/********************************************
 **************    win.c   ******************
 ********************************************/

#define INTUI_V36_NAMES_ONLY

#include <exec/exec.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <workbench/startup.h>

#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>

#include <stdlib.h>
#include <string.h>

#include "windows.h"

#include "consts.h"
#include "structs.h"
#include "protos.h"

extern prj_p prj;

extern UWORD __chip WaitPointer[];

/*
Function : BOOL win_idcmphandler(struct IntuiMessage *curr_msg)
Purpose : Handles messages from the main window.
*/

BOOL win_idcmphandler(struct IntuiMessage *curr_msg)
{
	struct Gadget *gad;

	BOOL done = FALSE;

	switch (curr_msg->Class) {
		case IDCMP_CLOSEWINDOW:
			done = TRUE;

			break;
		case IDCMP_GADGETUP:
			gad = (struct Gadget *)curr_msg->IAddress;

			switch(gad->GadgetID) {
				case mainwin_listview:
					win_listview((WORD)curr_msg->Code);
					break;
				case mainwin_parent:
					win_parent();
					break;
				case mainwin_getbinary:
					win_getbinary();
					break;
				case mainwin_putbinary:
					win_putbinary();
					break;
				case mainwin_all:
					win_all();
					break;
				case mainwin_none:
					win_none();
					break;
				case mainwin_about:
					win_about();
					break;
				case mainwin_devices:
					win_devices();
					break;
				default:
					break;
			}

			break;
		case IDCMP_REFRESHWINDOW:
			GT_BeginRefresh(mainwin);
			GT_EndRefresh(mainwin,TRUE);
			break;
		default:
			break;
	}

	return (done);
}

/*
Function : void win_ghost_set()
Purpose : Ghosts all gadgets out in window.
*/

void win_ghost_set()
{
	GT_SetGadgetAttrs(mainwinGadgets[mainwin_all],mainwin,NULL,
GA_Disabled,TRUE,TAG_END);
	GT_SetGadgetAttrs(mainwinGadgets[mainwin_none],mainwin,NULL,
GA_Disabled,TRUE,TAG_END);
	GT_SetGadgetAttrs(mainwinGadgets[mainwin_parent],mainwin,NULL,
GA_Disabled,TRUE,TAG_END);
	GT_SetGadgetAttrs(mainwinGadgets[mainwin_devices],mainwin,NULL,
GA_Disabled,TRUE,TAG_END);

	GT_SetGadgetAttrs(mainwinGadgets[mainwin_getbinary],mainwin,NULL,
GA_Disabled,TRUE,TAG_END);
	GT_SetGadgetAttrs(mainwinGadgets[mainwin_putbinary],mainwin,NULL,
GA_Disabled,TRUE,TAG_END);

	GT_SetGadgetAttrs(mainwinGadgets[mainwin_about],mainwin,NULL,
GA_Disabled,TRUE,TAG_END);
}

/*
Function : void win_ghost_clear()
Purpose : Unghosts all gadgets out in window.
*/

void win_ghost_clear()
{
	GT_SetGadgetAttrs(mainwinGadgets[mainwin_all],mainwin,NULL,
GA_Disabled,FALSE,TAG_END);
	GT_SetGadgetAttrs(mainwinGadgets[mainwin_none],mainwin,NULL,
GA_Disabled,FALSE,TAG_END);
	GT_SetGadgetAttrs(mainwinGadgets[mainwin_parent],mainwin,NULL,
GA_Disabled,FALSE,TAG_END);
	GT_SetGadgetAttrs(mainwinGadgets[mainwin_devices],mainwin,NULL,
GA_Disabled,FALSE,TAG_END);

	GT_SetGadgetAttrs(mainwinGadgets[mainwin_getbinary],mainwin,NULL,
GA_Disabled,FALSE,TAG_END);
	GT_SetGadgetAttrs(mainwinGadgets[mainwin_putbinary],mainwin,NULL,
GA_Disabled,FALSE,TAG_END);

	GT_SetGadgetAttrs(mainwinGadgets[mainwin_about],mainwin,NULL,
GA_Disabled,FALSE,TAG_END);
}

/*
Function : void win_block_set()
Purpose : Blocks the main window from input and puts up a sleep pointer.
*/

void win_block_set()
{
	if (prj->blocked)
		return;

	InitRequester(&prj->req);

	if (Request(&prj->req,mainwin)) {
		SetPointer(mainwin,WaitPointer,16,16,-6,0);
		prj->blocked = TRUE;
	}
}

/*
Function : void win_block_clear()
Purpose : Unblocks main window.
*/

void win_block_clear()
{
	if (!prj->blocked)
		return;

	ClearPointer(mainwin);
	EndRequest(&prj->req,mainwin);

	prj->blocked = FALSE;
}

/*
Function : void win_listview(WORD num)
Purpose : The user has clicked on an entry in the listview.
*/

void win_listview(WORD num)
{
	struct listviewdata *lvdata;

	/* If there's nothing in the listview */

	if (prj->zpathdepth == -1)
		return;

	/* Get a quick pointer to the listviewdata */

	lvdata = prj->listviewarray[num];

	/* Are we looking at the devices ? */

	if (prj->zpathdepth == 0) {
		win_ghost_set();

		/* Copy the chosen device */

		strcpy(prj->zpath,lvdata->fname);
		strcat(prj->zpath,"/");

		prj->zpathdepth++;

		/* Clear the listview */

		win_listview_clear();

		/* Read the directories for the device */

		if (!serial_directories()) {
			error("Unable to read directories.",
ERROR_WARNING,__LINE__,__FILE__);
			win_ghost_clear();

			return;
		}

		/* Read the files for the device */

		if (!serial_filenames()) {
			error("Unable to read filenames.",
ERROR_WARNING,__LINE__,__FILE__);
			win_ghost_clear();

			return;
		}

		/* Redraw the listview */

		win_listview_redraw();

		win_ghost_clear();
	}
	else {					/* files */
		/* If clicked on dir */

		if (lvdata->zfiletype == ZFILETYPE_DIR) {
			win_ghost_set();

			/* Update path */

			strcat(prj->zpath,lvdata->fname);
			strcat(prj->zpath,"/");

			prj->zpathdepth++;

			/* Clear the listview */

			win_listview_clear();

			/* Read the directories for the device */

			if (!serial_directories()) {
				error("Unable to read directories.",
ERROR_WARNING,__LINE__,__FILE__);
				win_ghost_clear();

				return;
			}

			/* Read the files for the device */

			if (!serial_filenames()) {
				error("Unable to read filenames.",
ERROR_WARNING,__LINE__,__FILE__);
				win_ghost_clear();

				return;
			}

			/* Redraw the listview */

			win_listview_redraw();

			win_ghost_clear();
		}
		else {			/* clicked on file */
			/* Temporarily remove the list */

			GT_SetGadgetAttrs(mainwinGadgets[mainwin_listview],
mainwin,NULL,GTLV_Labels,~0,TAG_END);

			/* Toggle selected status */

			if (lvdata->text[0] == '*')
				sprintf(lvdata->text,"  %-16s",
lvdata->fname);
			else
				sprintf(lvdata->text,"* %-16s",
lvdata->fname);

			/* Attatch list */

			GT_SetGadgetAttrs(mainwinGadgets[mainwin_listview],
mainwin,NULL,GTLV_Labels,&prj->listviewlist,TAG_END);
		}
	}
}

/*
Function : void win_devices()
Purpose : Gets the list of devices from the Z88.
*/

void win_devices()
{
	win_block_set();

	win_listview_clear();

	prj->zpath[0] = '\0';

	win_block_clear();
	win_ghost_set();

	if (!serial_devices()) {
		win_ghost_clear();

		return;
	}

	prj->zpathdepth = 0;

	win_listview_redraw();

	win_ghost_clear();
}

/*
Function : void win_parent()
Purpose : Go back to the parent directory, to the devices if neccessary.
*/

void win_parent()
{
	char *chrptr;

	/* If we're already showing the devices */

	if (!prj->zpathdepth)
		return;

	/* Should we go to the devices ? */

	if (prj->zpathdepth == 1) {

		win_ghost_set();

		prj->zpath[0] = '\0';

		prj->zpathdepth = 0;

		/* Clear the listview */

		win_listview_clear();

		/* Read the devices */

		if (!serial_devices()) {
			error("Unable to read devices.",ERROR_WARNING,
__LINE__,__FILE__);
			win_ghost_clear();

			return;
		}

		/* Redraw the listview */

		win_listview_redraw();

		win_ghost_clear();
	}
	else {		/* step up the directory path one level */
		win_ghost_set();

		/* Find penultimate directory seperator */

		for (chrptr = &prj->zpath[strlen(prj->zpath) - 2];
chrptr >= prj->zpath; chrptr--) {
			if (*chrptr == '/') {
				*(chrptr + 1) = '\0';

				break;
			}
		}

		prj->zpathdepth--;

		/* Read the new path */

		/* Clear the listview */

		win_listview_clear();

		/* Read the directories for the device */

		if (!serial_directories()) {
			error("Unable to read directories.",ERROR_WARNING,
__LINE__,__FILE__);
			win_ghost_clear();

			return;
		}

		/* Read the files for the device */

		if (!serial_filenames()) {
			error("Unable to read filenames.",ERROR_WARNING,
__LINE__,__FILE__);
			win_ghost_clear();

			return;
		}

		/* Redraw the listview */

		win_listview_redraw();

		win_ghost_clear();
	}
}

/*
Function : void win_getbinary()
Purpose : Opens up a path requester and copies the Z88 files chosen in the
	listview into the chosen Amiga directory.
*/

void win_getbinary()
{
	struct FileRequester *filereq;

	WORD l;

	BOOL found = FALSE;

	struct listviewdata *lvdata;

	win_block_set();

	/* Check that there are some Z88 files chosen */

	for (l = 0; l < MAX_LISTVIEW_ENTRIES; l++) {
		lvdata = prj->listviewarray[l];

		if (!lvdata)
			break;

		if (lvdata->text[0] == '*') {
			found = TRUE;

			break;
		}
	}

	if (!found) {
		error("No Z88 files selected.",ERROR_WARNING,__LINE__,__FILE__);

		win_block_clear();

		return;
	}

	filereq = (struct FileRequester *)AllocAslRequestTags(
		ASL_FileRequest,
		ASL_Hail,"Choose dest directory...",
		ASL_Dir,prj->path_binary_get,
		ASL_Window,mainwin,
		ASL_FuncFlags,FILF_SAVE,
		ASL_ExtFlags1,FIL1F_NOFILES);

	if (!filereq) {
		error("Out of memory.",ERROR_WARNING,__LINE__,__FILE__);

		win_block_clear();

		return;
	}

	/* Open the requester */

	if (!AslRequest(filereq,NULL)) {
		/* Cancelled */

		FreeAslRequest(filereq);

		win_block_clear();

		return;
	}

	/* Clear the window block incase user wishes to abort */

	win_ghost_set();
	win_block_clear();

	/* Copy path, may have changed */

	strcpy(prj->path_binary_get,filereq->rf_Dir);

	FreeAslRequest(filereq);

	/* Get selected files */

	for (l = 0; l < MAX_LISTVIEW_ENTRIES; l++) {
		lvdata = prj->listviewarray[l];

		if (!lvdata)
			break;

		if (lvdata->text[0] == '*') {
			if (!serial_binary_get(lvdata->fname)) {
				error("Unable to get file.",ERROR_WARNING,
__LINE__,__FILE__);
				win_status_clear();

				break;
			}
		}
	}

	win_ghost_clear();
}

/*
Function : void win_putbinary()
Purpose : Opens a multifile requester to choose many Amiga files to send
	to Z88.
*/

void win_putbinary()
{
	struct FileRequester *filereq;
	struct WBArg *filereqargs;

	WORD l;

	win_block_set();

	/* Check that there is a Z88 path chosen */

	if (!prj->zpathdepth) {
		error("No Z88 path selected.|"
"Choose place on the Z88 to store\n"
"the files from the Amiga.",ERROR_WARNING,__LINE__,__FILE__);

		win_block_clear();

		return;
	}

	filereq = (struct FileRequester *)AllocAslRequestTags(
		ASL_FileRequest,
		ASL_Hail,"Choose source directory...",
		ASL_Dir,prj->path_binary_put,
		ASL_Window,mainwin,
		ASL_FuncFlags,FILF_MULTISELECT | FILF_PATGAD);

	if (!filereq) {
		error("Out of memory.",ERROR_WARNING,__LINE__,__FILE__);

		win_block_clear();

		return;
	}

	/* Open the requester */

	if (!AslRequest(filereq,NULL)) {
		/* Cancelled */

		FreeAslRequest(filereq);

		win_block_clear();

		return;
	}

	/* Clear the window block incase user wishes to abort */

	win_ghost_set();
	win_block_clear();

	/* Copy path, may have changed */

	strcpy(prj->path_binary_put,filereq->rf_Dir);

	/* Did the user select 1 file */

	if (!filereq->rf_NumArgs) {
		if (!serial_binary_put(filereq->rf_Dir,filereq->rf_File)) {
			error("Unable to put file.",ERROR_WARNING,
__LINE__,__FILE__);
		}

		win_status_clear();
	}
	else {
		filereqargs = filereq->rf_ArgList;

		for (l = 0; l < filereq->rf_NumArgs; l++) {
			if (!serial_binary_put(filereq->rf_Dir,
filereqargs[l].wa_Name)) {
				error("Unable to put file.",ERROR_WARNING,
__LINE__,__FILE__);
				win_status_clear();

				break;
			}
		}
	}

	FreeAslRequest(filereq);

	/* Update the directory in the listview */

	win_listview_clear();

	/* Read the directories for the device */

	if (!serial_directories()) {
		error("Unable to read directories.",ERROR_WARNING,
__LINE__,__FILE__);
		win_ghost_clear();

		return;
	}

	/* Read the files for the device */

	if (!serial_filenames()) {
		error("Unable to read filenames.",ERROR_WARNING,
__LINE__,__FILE__);
		win_ghost_clear();

		return;
	}

	/* Redraw the listview */

	win_listview_redraw();

	win_ghost_clear();
}

/*
Function : void win_all()
Purpose : Selects all the files in the current listview.
*/

void win_all()
{
	WORD l;

	struct listviewdata *lvdata;

	win_block_set();

	/* Temporarily remove the list */

	GT_SetGadgetAttrs(mainwinGadgets[mainwin_listview],mainwin,
NULL,GTLV_Labels,~0,TAG_END);

	/* Loop through all files */

	for (l = 0; l < MAX_LISTVIEW_ENTRIES; l++) {
		lvdata = prj->listviewarray[l];

		if (!lvdata)
			break;

		/* If it's not a file */

		if (lvdata->zfiletype != ZFILETYPE_FILE)
			continue;

		/* If not selected, select it */

		if (lvdata->text[0] != '*')
			sprintf(lvdata->text,"* %-16s",lvdata->fname);
	}

	/* Attatch list */

	GT_SetGadgetAttrs(mainwinGadgets[mainwin_listview],mainwin,NULL,
GTLV_Labels,&prj->listviewlist,TAG_END);

	win_block_clear();
}

/*
Function : void win_none()
Purpose : Selects none of the files in the current listview.
*/

void win_none()
{
	WORD l;

	struct listviewdata *lvdata;

	win_block_set();

	/* Temporarily remove the list */

	GT_SetGadgetAttrs(mainwinGadgets[mainwin_listview],mainwin,
NULL,GTLV_Labels,~0,TAG_END);

	/* Loop through all files */

	for (l = 0; l < MAX_LISTVIEW_ENTRIES; l++) {
		lvdata = prj->listviewarray[l];

		if (!lvdata)
			break;

		/* If it's not a file */

		if (lvdata->zfiletype != ZFILETYPE_FILE)
			continue;

		/* If not selected, select it */

		if (lvdata->text[0] == '*')
			sprintf(lvdata->text,"  %-16s",lvdata->fname);
	}

	/* Attatch list */

	GT_SetGadgetAttrs(mainwinGadgets[mainwin_listview],mainwin,NULL,
GTLV_Labels,&prj->listviewlist,TAG_END);

	win_block_clear();
}

/*
Function : void win_about()
Purpose : Pops up an about requester.
*/

void win_about()
{
	error(VERSION_NAME"\n"
"Version : "VERSION_NUMBER"\n"
"Date    : "VERSION_DATE,ERROR_WARNING,__LINE__,__FILE__);
}

/*
Function : void win_status_set(char *text)
Purpose : Puts the given text into the status window.
*/

void win_status_set(char *text)
{
	static char status_text[STRLEN_STATUS];

	/* Copy the text to the buffer */

	strcpy(status_text,text);

	/* Put the text in the gadget */

	GT_SetGadgetAttrs(mainwinGadgets[mainwin_status],mainwin,NULL,
GTTX_Text,status_text,TAG_END);
}

/*
Function : void win_status_clear()
Purpose : Puts up a default string in the status bar.
*/

void win_status_clear()
{
	GT_SetGadgetAttrs(mainwinGadgets[mainwin_status],mainwin,NULL,
GTTX_Text,"",TAG_END);
}

/*
Function : void win_listview_clear()
Purpose : Frees all the memory in the prj->listviewarray and resets the
	prj->listviewlist. Clears the listview display.
*/

void win_listview_clear()
{
	WORD l;

	/* Clear display */

	GT_SetGadgetAttrs(mainwinGadgets[mainwin_listview],mainwin,NULL,
GTLV_Labels,NULL,TAG_END);

	/* Reset list */

	NewList(&prj->listviewlist);

	/* Free mem */

	for (l = 0; l < MAX_LISTVIEW_ENTRIES; l++) {
		if (prj->listviewarray[l])
			free(prj->listviewarray[l]);

		prj->listviewarray[l] = NULL;
	}
}

/*
Function : BOOL win_listview_add(struct listviewdata *data,
	zfiletype_e zfiletype)
Purpose : Copies the data given in 'data' and places it in the next free
	entry of the prj->listviewarray. Add the entry to the
	prj->listviewlist. The filetype (file, dev or dir) is given in
	'zfiletype'. Returns TRUE on success, FALSE if out of memory or
	no room left in array.
*/

BOOL win_listview_add(struct listviewdata *data,zfiletype_e zfiletype)
{
	WORD l;

	struct listviewdata *new_data;

	char typestring[10];

	/* Check that we're not adding an invalid entry */

	if ((zfiletype == ZFILETYPE_DEV) && (strchr(data->fname,'-')))
		return (TRUE);

	if ((zfiletype == ZFILETYPE_DIR) && (!strcmp(data->fname,".")))
		return (TRUE);

	if ((zfiletype == ZFILETYPE_DIR) && (!strcmp(data->fname,"..")))
		return (TRUE);

	/* Allocate new listviewdata */

	new_data = malloc(sizeof(struct listviewdata));

	if (!new_data)
		return (FALSE);

	/* Copy the data */

	CopyMem(data,new_data,sizeof(struct listviewdata));

	/* Set up list part */

	AddTail(&prj->listviewlist,(struct Node *)new_data);

	new_data->node.ln_Name = new_data->text;

	/* Setup the other data */

	new_data->zfiletype = zfiletype;

	switch (zfiletype) {
		case ZFILETYPE_DEV:
			strcpy(typestring,"[dev]");
			break;
		case ZFILETYPE_DIR:
			strcpy(typestring,"[dir]");
			break;
		case ZFILETYPE_FILE:
			strcpy(typestring,"");
			break;
		default:
			error("Unknown ZFILETYPE.",ERROR_INTERNAL,
__LINE__,__FILE__);
			break;
	}

	sprintf(new_data->text,"  %-16s %s",new_data->fname,typestring);

	/* Add to array */

	for (l = 0; l < MAX_LISTVIEW_ENTRIES; l++) {
		if (!prj->listviewarray[l]) {
			prj->listviewarray[l] = new_data;

			break;
		}
	}

	/* If no space in array */

	if (l == MAX_LISTVIEW_ENTRIES)
		return (FALSE);

	/* Return OK */

	return (TRUE);
}

/*
Function : void win_listview_redraw()
Purpose : Redraws the list in the listview.
*/

void win_listview_redraw()
{
	GT_SetGadgetAttrs(mainwinGadgets[mainwin_listview],mainwin,NULL,
GTLV_Labels,&prj->listviewlist,TAG_END);
}

