/*
**	InstrumentsWin.c
**
**	Copyright (C) 1994,95,96 Bernardo Innocenti
**
**	Instruments editor handling functions.
*/

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

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <proto/xmodule.h>

#include "XModulePriv.h"
#include "Gui.h"



/* Gadgets IDs */

enum
{
	GD_InstrGroup0,
		GD_InstrGroup1,
			GD_InstrGroup2,
				GD_InstrList,
				GD_InstrName,
			GD_InstrGroup3,
				GD_InstrNew,
				GD_InstrOpen,
				GD_InstrDel,
				GD_InstrUp,
				GD_InstrDown,
		GD_InstrGroup4,
			GD_InstrVolume,
			GD_InstrFineTune,
			GD_InstrLen,
			GD_InstrKind,
			GD_InstrEdit,

	Instruments_CNT
};



/*****************************/
/* Local function prototypes */
/*****************************/

static void InstrumentsDropIcon		(struct AppMessage *msg);
static void InstrumentsPostOpen		(void);
static void InstrumentsPostClose	(void);
void UpdateInstrInfo	(void);
void UpdateInstrList	(void);

static void InstrNewClicked			(void);
static void InstrOpenClicked		(void);
static void InstrDelClicked			(void);
static void InstrUpClicked			(void);
// TODO static void InstrSwapClicked		(void);
static void InstrDownClicked		(void);
static void InstrNameClicked		(struct WinUserData *wud);
static void InstrListClicked		(void);
static void InstrVolumeClicked		(void);
static void InstrFineTuneClicked	(void);
static void InstrEditClicked		(void);
static void InstrKindClicked		(void);

static void InstrumentsMiLoad		(void);
static void InstrumentsMiSave		(void);
static void InstrumentsMiSaveAs		(void);
static void InstrumentsMiRemap		(void);
static void InstrumentsMiSaveIcons	(void);
static void InstrumentsMiSaveCompressed	(void);
static void InstrumentsMiSaveRaw	(void);


XDEF struct List	InstrList;
static ULONG		InstrSecs = 0, InstrMicros = 0;


static struct NewMenu InstrumentsNewMenu[] = {
	NM_TITLE, (STRPTR)MSG_INSTRUMENTS_MEN, NULL, 0, NULL, NULL,
	NM_ITEM, (STRPTR)MSG_LOAD_MEN, (STRPTR)"L", 0, 0L, (APTR)InstrumentsMiLoad,
	NM_ITEM, (STRPTR)MSG_SAVE_MEN, (STRPTR)"S", 0, 0L, (APTR)InstrumentsMiSave,
	NM_ITEM, (STRPTR)MSG_SAVE_AS_MEN, (STRPTR)"A", 0, 0L, (APTR)InstrumentsMiSaveAs,
	NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
	NM_ITEM, (STRPTR)MSG_REMAP_MEN, (STRPTR)"R", 0, 0L, (APTR)InstrumentsMiRemap,
	NM_TITLE, (STRPTR)MSG_SETTINGS_MEN, NULL, 0, NULL, NULL,
	NM_ITEM, (STRPTR)MSG_SAVE_ICONS_MEN, NULL, CHECKIT|MENUTOGGLE, 0L, (APTR)InstrumentsMiSaveIcons,
	NM_ITEM, (STRPTR)MSG_SAVE_COMPRESSED_MEN, NULL, CHECKIT|MENUTOGGLE, 4L, (APTR)InstrumentsMiSaveCompressed,
	NM_ITEM, (STRPTR)MSG_SAVE_RAW_MEN, NULL, CHECKIT|MENUTOGGLE, 2L, (APTR)InstrumentsMiSaveRaw,
	NM_END, NULL, NULL, 0, 0L, NULL };



static STRPTR InstrKindLabels[] = {
	(STRPTR)MSG_SAMPLE_GAD,
	(STRPTR)MSG_SYNTH_GAD,
	(STRPTR)MSG_HYBRID_GAD,
	(STRPTR)0
};



static ULONG InstrumentsArgs[] =
{
	HGROUP_KIND, BBFT_RIDGE,
		VGROUP_KIND, 0,
			LISTVIEW_KIND,	(ULONG)InstrListClicked,		0,	(ULONG)&InstrList,	TAG_DONE,
			STRING_KIND,	(ULONG)InstrNameClicked,		0,	64,					TAG_DONE,
			ENDGROUP_KIND,
		VGROUP_KIND, 0,
			BUTTON_KIND,	(ULONG)InstrNewClicked,		MSG_UNDERSCORE_NEW_GAD,		TAG_DONE,
			BUTTON_KIND,	(ULONG)InstrOpenClicked,	MSG_OPEN_GAD,				TAG_DONE,
			BUTTON_KIND,	(ULONG)InstrDelClicked,		MSG_DEL_GAD,				TAG_DONE,
			BUTTON_KIND,	(ULONG)InstrUpClicked,		MSG_UNDERSCORE_UP_GAD,		TAG_DONE,
			BUTTON_KIND,	(ULONG)InstrDownClicked,	MSG_UNDERSCORE_DOWN_GAD,	TAG_DONE,
			ENDGROUP_KIND,
		ENDGROUP_KIND,
	VGROUP_KIND,	BBFT_RIDGE,
		SLIDER_KIND,	(ULONG)InstrVolumeClicked,	MSG_VOLUME_GAD,		0,	64,	(ULONG)"%lu",	3,	TAG_DONE,
		SLIDER_KIND,	(ULONG)InstrFineTuneClicked,MSG_FINETUNE_GAD,	-8,	+7,	(ULONG)"%ld",	3,	TAG_DONE,
		NUMBER_KIND,	MSG_LENGHT_GAD,				7,												TAG_DONE,
		CYCLE_KIND,		(ULONG)InstrKindClicked,	MSG_KIND_GAD,	(ULONG)InstrKindLabels,			TAG_DONE,
		BUTTON_KIND,	(ULONG)InstrEditClicked,	MSG_EDIT_DOTS_GAD,								TAG_DONE,
		ENDGROUP_KIND,
	ENDGROUP_KIND
};



XDEF LONG InstrumentsWinTags[] =
{
	XMWIN_NewMenu,		(LONG)InstrumentsNewMenu,
	XMWIN_LayoutArgs,	(LONG)InstrumentsArgs,
	XMWIN_GCount,		Instruments_CNT,
	XMWIN_Title,		MSG_INSTRUMENTS_TITLE,
	XMWIN_WindowFlags,	WFLG_CLOSEGADGET,
	XMWIN_IDCMPFlags,	BUTTONIDCMP|STRINGIDCMP|LISTVIEWIDCMP|INTEGERIDCMP|NUMBERIDCMP|IDCMP_MENUPICK|IDCMP_CLOSEWINDOW|IDCMP_REFRESHWINDOW,
	XMWIN_PostOpenFunc,	(LONG)InstrumentsPostOpen,
	XMWIN_PostCloseFunc,(LONG)InstrumentsPostClose,
	XMWIN_DropIconFunc,	(LONG)InstrumentsDropIcon,
	XMWIN_HelpNode,		(LONG)"Instruments",
	TAG_DONE
};



static void InstrumentsPostOpen (void)
{
	UpdateInstrSwitches();
	UpdateInstrList();
}

static void InstrumentsPostClose (void)
{
	while (!IsListEmpty(&InstrList))
		RemListViewNode (InstrList.lh_Head);
}



static void InstrumentsDropIcon (struct AppMessage *msg)
{
	struct SongInfo *si;

	LockWindows();

	if (si = xmLockActiveSong (SM_EXCLUSIVE))
	{
		struct WBArg	*wba = msg->am_ArgList;
		BPTR olddir;
		UWORD i, j;

		olddir = CurrentDir (wba->wa_Lock);

		for (i = 0, j = si->CurrentInst;
			(i < msg->am_NumArgs) && (j < MAXINSTRUMENTS);
			i++, j++)
		{
			CurrentDir (msg->am_ArgList->wa_Lock);

			if (j == 0) j++;

			if (LastErr = LoadInstrument (si, j, wba->wa_Name))
				break;

			wba++;
		}

		ReleaseSemaphore (&si->Lock);

		if (si->CurrentInst == 0)
			SetAttrs (si,
				SNGA_CurrentInst, 1,
				TAG_DONE);

		CurrentDir (olddir);
	}

	UnlockWindows();
}



/*************************/
/* Instruments Functions */
/*************************/

GLOBALCALL void UpdateInstrList (void)
{
	struct SongInfo *si;
	struct WinUserData *wud = WDescr[WID_INSTRUMENTS].Wud;
	ULONG i, curr = 0;

	if (wud && wud->Win)
	{
		GT_SetGadgetAttrs (wud->Gadgets[GD_InstrList], wud->Win, NULL,
			GTLV_Labels, ~0,
			TAG_DONE);

		/* Empty previous list */
		while (!IsListEmpty (&InstrList))
			RemListViewNode (InstrList.lh_Head);

		if (si = xmLockActiveSong (SM_SHARED))
		{
			for (i = 1 ; i <= si->LastInstrument; i++)
			{
				AddListViewNode (&InstrList, "%02lx %s", i,
					si->Instr[i] ?
						(si->Instr[i]->Name ? si->Instr[i]->Name : STR(MSG_UNNAMED))
						: STR(MSG_EMPTY));
			}

			curr = si->CurrentInst - 1;

			ReleaseSemaphore (&si->Lock);
		}

		GT_SetGadgetAttrs (wud->Gadgets[GD_InstrList], wud->Win, NULL,
			GTLV_Labels, &InstrList,
			GTLV_MakeVisible, curr,
			TAG_DONE);

		UpdateInstrInfo();
	}
}



GLOBALCALL void UpdateInstrInfo (void)
{
	struct SongInfo *si;
	struct WinUserData *wud;

	if (!(wud = WDescr[WID_INSTRUMENTS].Wud)) return;
	if (!(wud->Win)) return;

	if (si = xmLockActiveSong (SM_SHARED))
	{
		struct Instrument *instr;

		if (si->CurrentInst && (instr = si->Instr[si->CurrentInst]))
			SetGadgets (wud,
				GD_InstrName,		instr->Name,
				GD_InstrVolume,		instr->Volume,
				GD_InstrFineTune,	instr->FineTune,
				GD_InstrLen,		instr->Length,
				GD_InstrList,		si->CurrentInst - 1,
				-1);
		else
			SetGadgets (wud,
				GD_InstrName,		NULL,
				GD_InstrVolume,		0,
				GD_InstrFineTune,	0,
				GD_InstrLen,		0,
				GD_InstrList,		si->CurrentInst - 1,
				-1);


		ReleaseSemaphore (&si->Lock);
	}

	DB(kprintf("remember to uncomment updatesample!\n"));
	//UpdateSample();
	UpdateEditorInst();
}



GLOBALCALL void UpdateInstrSwitches (void)
{
	struct MenuItem *item;
	struct WinUserData *wud = WDescr[WID_INSTRUMENTS].Wud;

	if (wud && wud->MenuStrip)
	{
		if (wud->Win) ClearMenuStrip (wud->Win);

		item = ItemAddress (wud->MenuStrip, SHIFTMENU(1) | SHIFTITEM(0) );

		/* Save Icons? */
		if (GuiSwitches.InstrSaveIcons)
			item->Flags |= CHECKED;
		else
			item->Flags &= ~CHECKED;

		if (wud->Win) ResetMenuStrip (wud->Win, wud->MenuStrip);
	}
}



static void InstrumentsLoad (STRPTR name, ULONG num, ULONG count)
{
	struct SongInfo *si;

	LockWindows();

	if (si = xmLockActiveSong (SM_EXCLUSIVE))
	{
		UWORD instnum;

		if (si->CurrentInst == 0)
			instnum = 1;
		else
			instnum = si->CurrentInst + num;

		if (instnum < MAXINSTRUMENTS)
			LoadInstrument (si, instnum, name);

		if (si->CurrentInst == 0)
			SetAttrs (si,
				SNGA_CurrentInst, 1,
				TAG_DONE);

		ReleaseSemaphore (&si->Lock);
	}

	UnlockWindows();
}



/***********************/
/* Instruments Gadgets */
/***********************/

static void InstrNewClicked (void)
{
	struct SongInfo *si;

	if (si = xmLockActiveSong (SM_EXCLUSIVE))
	{
		xmAddInstrumentA (si, -1, NULL);

		SetAttrs (si,
			SNGA_CurrentInst,	si->LastInstrument,
			TAG_DONE);

		ReleaseSemaphore (&si->Lock);
	}

	UpdateSongInfo();
}



static void InstrOpenClicked (void)
{
	StartFileRequest (FREQ_LOADINST, InstrumentsLoad);
}



static void InstrDelClicked (void)
{
	struct SongInfo *si;

	if (si = xmLockActiveSong (SM_EXCLUSIVE))
	{
		xmRemInstrument (si, si->CurrentInst);

		SetAttrs (si,
			SNGA_CurrentInst,	si->CurrentInst + 1,
			TAG_DONE);

		ReleaseSemaphore (&si->Lock);
	}

	UpdateSongInfo();
}



static void InstrUpClicked (void)
{
	struct Instrument *tmp;
	struct SongInfo *si;

	if (si = xmLockActiveSong (SM_EXCLUSIVE))
	{
		/* Swap actual instrument with the previous one */
		if (si->CurrentInst <= 1) return;

		tmp = si->Instr[si->CurrentInst];
		si->Instr[si->CurrentInst] = si->Instr[si->CurrentInst-1];
		si->Instr[si->CurrentInst-1] = tmp;

		SetAttrs (si,
			SNGA_CurrentInst,	si->CurrentInst-1,
			TAG_DONE);

		ReleaseSemaphore (&si->Lock);

		UpdateInstrList();
	}
}



static void InstrDownClicked (void)
{
	struct SongInfo *si;
	struct Instrument *tmp;

	if (si = xmLockActiveSong (SM_EXCLUSIVE))
	{
		/* Swap actual instrument with the next one */
		if (si->CurrentInst >= MAXINSTRUMENTS-1) DisplayBeep (Scr);
		else
		{
			/**/ /* Use some OO-legal way to do this!! :) */
			tmp = si->Instr[si->CurrentInst];
			si->Instr[si->CurrentInst] = si->Instr[si->CurrentInst+1];
			si->Instr[si->CurrentInst+1] = tmp;
			if (si->CurrentInst + 1 >= si->LastInstrument)
				si->LastInstrument = si->CurrentInst + 1;

			SetAttrs (si,
				SNGA_CurrentInst,	si->CurrentInst + 1,
				TAG_DONE);
		}

		ReleaseSemaphore (&si->Lock);

		UpdateInstrList();
	}
}



/*
static void InstrSwapClicked (void)
{
	TODO
}
*/


static void InstrNameClicked (struct WinUserData *wud)
{
	struct SongInfo *si;

	if (si = xmLockActiveSong (SM_EXCLUSIVE))
	{
		xmSetInstrument (si, si->CurrentInst,
			INSTRA_Name, GetString (wud->Gadgets[GD_InstrName]),
			TAG_DONE);

		ReleaseSemaphore (&si->Lock);

		UpdateInstrList();
	}
}



static void InstrListClicked (void)
{
	struct SongInfo *si;

	if (si = xmLockActiveSong (SM_SHARED))
	{
		if (si->CurrentInst != IntuiMsg.Code + 1)
		{
			si->CurrentInst = IntuiMsg.Code + 1;
			UpdateInstrInfo();
		}
		else
		{
			/* Check Double Click */
			if (DoubleClick (InstrSecs, InstrMicros, IntuiMsg.Seconds, IntuiMsg.Micros))
				NewWindow (WID_SAMPLE);
		}

		ReleaseSemaphore (&si->Lock);
	}

	InstrSecs = IntuiMsg.Seconds;
	InstrMicros = IntuiMsg.Micros;
}



static void InstrVolumeClicked (void)
{
	struct SongInfo *si;

	if (si = xmLockActiveSong (SM_EXCLUSIVE))
	{
		xmSetInstrument (si, si->CurrentInst,
			INSTRA_Volume, IntuiMsg.Code,
			TAG_DONE);

		ReleaseSemaphore (&si->Lock);
	}
}



static void InstrFineTuneClicked (void)
{
	struct SongInfo *si;

	if (si = xmLockActiveSong (SM_EXCLUSIVE))
	{
		xmSetInstrument (si, si->CurrentInst,
			INSTRA_FineTune, IntuiMsg.Code,
			TAG_DONE);
		ReleaseSemaphore (&si->Lock);
	}
}



static void InstrKindClicked (void)
{
	/**/
}



static void InstrEditClicked (void)
{
	NewWindow (WID_SAMPLE);
}



/**************/
/* Menu Items */
/**************/

static void InstrumentsMiLoad (void)
{
	StartFileRequest (FREQ_LOADINST, InstrumentsLoad);
}



static void InstrumentsMiSave (void)
{
	struct SongInfo *si;

	LockWindows();

	if (si = xmLockActiveSong (SM_SHARED))
	{
		if (si->Instr[si->CurrentInst])
			LastErr = SaveInstrument (si->Instr[si->CurrentInst],
				si->Instr[si->CurrentInst]->Name);

		ReleaseSemaphore (&si->Lock);
	}

	UnlockWindows();
}



static void InstrumentsMiSaveAs (void)
{
	struct SongInfo *si;

	LockWindows();

	if (si = xmLockActiveSong (SM_EXCLUSIVE))
	{
		struct Instrument *instr;
		UBYTE name[PATHNAME_MAX];

		if (instr = si->Instr[si->CurrentInst])
		{
			strncpy (name, instr->Name, PATHNAME_MAX-1);
			name[PATHNAME_MAX-1] = '\0';

			if (FileRequest (FREQ_SAVEINST, name))
			{
				xmSetInstrument (si, si->CurrentInst,
					INSTRA_Name,	FilePart (name),
					TAG_DONE);

				LastErr = SaveInstrument (instr, name);
			}
		}

		ReleaseSemaphore (&si->Lock);
	}

	UnlockWindows();
}



static void InstrumentsMiRemap (void)
{
	struct SongInfo *si;

	if (si = xmLockActiveSong (SM_EXCLUSIVE))
	{
		RemapInstruments (si);
		UpdateSongInfo();
		ReleaseSemaphore (&si->Lock);
	}
}



static void InstrumentsMiSaveIcons (void)
{
	GuiSwitches.InstrSaveIcons ^= 1;
}



static void InstrumentsMiSaveCompressed (void)
{
	/**/ /* TODO */
}



static void InstrumentsMiSaveRaw (void)
{
	/**/ /* TODO */
}

