#include "dtmf.h"

extern void Init(void);
extern char dirProg[];

struct FILE *conwin;

struct TextAttr LCD =
{
	(STRPTR) "DTMF:fonts/LCD.font",
	13,
	FS_NORMAL,
	FPF_DISKFONT
};

struct TextAttr Cyber =
{
	(STRPTR) "DTMF:fonts/Cyber.font",
	16,
	FS_NORMAL,
	FPF_DISKFONT
};

struct NewMenu mymenu[] =
{
	{NM_TITLE, "DTMF", 0, 0, 0, 0,},
	{NM_ITEM, "Répertoire", 0, 0, 0, 0,},
	{NM_ITEM, "A propos...", 0, 0, 0, 0,},
	{NM_END, NULL, 0, 0, 0, 0,}
};

struct Menu *menuStrip;

struct MsgPort *allocPort;
struct MsgPort *NarratorPort;
struct MsgPort *rexxPort;

struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;
struct Library *DiskfontBase;
struct Library *GadToolsBase;

//struct RxsLib  *RexxSysBase;

struct Window *MyWindow;
struct Gadget *glist,
       *gad,
       *gadText;
struct NewGadget ng;
struct TextFont *LCDFont;
struct TextFont *CyberFont;
struct narrator_rb *NarratorReq;

UBYTE   SpokenString[] = "RIY4MEHMBER. OW3NLIY AHMIYGAH MEY4KS IHT PAA4SIHBUL.";	// Merci Say

WORD    channels = 0,
        channel0,
        channel1;

BPTR    fileRepertoire;

ULONG   NarratorDev = -1,
        device = -1,
        rexxPortBit;

UWORD   offx,
        offy;

BOOL    setMenu;

char    nameRexxPort[] = "DTMF_Rexx";

UWORD   iconDtmfCoords[4] =
{50, 0, 202, 14};

struct timerequest *create_timer(ULONG);
void    delete_timer(struct timerequest *);

/****************************************************************/
/*
 * ouvre les devices, les librairies, etc....
 */
/*
 */
/*
 * Paramètres: NULL
 */
/*
 * Retour: NULL
 */
/****************************************************************/

void
OpenAll()
{
	long    n = STRGADGORD,
	        i = 2;

	if (GUI)
	{
		if ((GfxBase = (struct GfxBase *) OpenLibrary((UBYTE *) "graphics.library", 33)) == NULL)
			cleanUp("\nImpossible d'ouvrir graphics.library", 6);

		if ((IntuitionBase = (struct IntuitionBase *) OpenLibrary((UBYTE *) "intuition.library", 33)) == NULL)
			cleanUp("\nImpossible d'ouvrir Intuition.library", 6);

		if ((GadToolsBase = (struct Library *) OpenLibrary((UBYTE *) "gadtools.library", 36)) == NULL)
			cleanUp("\nImpossible d'ouvrir LIBS:gadtools.library", 6);

		if ((DiskfontBase = (struct Library *) OpenLibrary((UBYTE *) "diskfont.library", 33)) == NULL)
			cleanUp("\nImpossible d'ouvrir LIBS:diskfont.library", 6);

		if ((pubScreen = (struct Screen *) LockPubScreen((UBYTE *) NULL)) == NULL)
			cleanUp("\nImpossible de vérouiller l'écran public", 6);

		if ((PubDrawInfo = (struct DrawInfo *) GetScreenDrawInfo(pubScreen)) == NULL)
			cleanUp("\nImpossble d'obtenir les ScreenDrawInfo", 6);

		if ((vi = GetVisualInfo(pubScreen, TAG_END)) == NULL)
			cleanUp("\nImpossble d'obtenir les Visualinfo", 6);

		offx = pubScreen->WBorLeft;
		offy = pubScreen->WBorTop + pubScreen->RastPort.TxHeight + 1;

		if ((MyWindow = (struct Window *) OpenWindowTags(NULL,
								 WA_Top, winClavTop,
								 WA_Left, winClavLeft,
								 WA_Width, 202,
								 WA_Height, 147 + offy,
								 WA_CloseGadget, TRUE,
								 WA_DragBar, TRUE,
								 WA_DepthGadget, TRUE,
								 WA_ReportMouse, TRUE,
								 WA_Activate, TRUE,
								 WA_Title, (STRPTR) "Dual Tone MultiFreq",
								 WA_SmartRefresh, TRUE,
								 WA_Activate, TRUE,
								 WA_Zoom, iconDtmfCoords,
								 WA_PubScreen, pubScreen,
								 TAG_END
		     )) == NULL)
			cleanUp("\nOuverture fenètre impossible", 6);

		iconDtmfCoords[3] = pubScreen->BarHeight;

		if (NULL == (menuStrip = CreateMenus(mymenu, TAG_END)))
			cleanUp("Impossible de créer le menu", 6);

		if (!(LayoutMenus(menuStrip, vi, TAG_END)))
			cleanUp("Impossible d'appliquer les visualInfos au menu", 6);

		if (!(setMenu = SetMenuStrip(MyWindow, menuStrip)))
			cleanUp("Impossible de connecter le menu à la fenêtre", 6);

		if ((LCDFont = (struct TextFont *) OpenDiskFont(&LCD)) == NULL)
		{
			strcpy(LCD.ta_Name, "LCD.font");
			if ((LCDFont = (struct TextFont *) OpenDiskFont(&LCD)) == NULL)
				cleanUp("Impossible d'ouvrir FONTS:LCD/13", 6);
		}

	    /* Sans ce strcpy, la fonte n'est pas utilisée par les Gadgets  ??!! */
		strcpy(LCD.ta_Name, "LCD.font");

		if ((CyberFont = (struct TextFont *) OpenDiskFont(&Cyber)) == NULL)
		{
			strcpy(Cyber.ta_Name, "Cyber.font");
			if ((CyberFont = (struct TextFont *) OpenDiskFont(&Cyber)) == NULL)
				cleanUp("Impossible d'ouvrir FONTS:Cyber/16", 6);
		}

		strcpy(Cyber.ta_Name, "Cyber.font");

		if (DiskfontBase != NULL)
			CloseLibrary((struct Library *) DiskfontBase);

/************ Mise en place du clavier *************************/
/*
 * A B C D
 * 7 8 9 *
 * 4 5 6 #
 * 1 2 3 B
 * 0   P s
 */
		gad = CreateContext(&glist);

		ng.ng_TextAttr = &LCD;
		ng.ng_VisualInfo = vi;
		ng.ng_Width = MyWindow->Width - 10;
		ng.ng_Height = LCDFont->tf_YSize + 10;
		ng.ng_Flags = 0;

		ng.ng_LeftEdge = 5;
		ng.ng_TopEdge = pubScreen->WBorTop + pubScreen->RastPort.TxHeight + 2;
		ng.ng_GadgetID = 0;

		gadText = gad = CreateGadget(TEXT_KIND, gad, &ng,
					     GTTX_Border, TRUE,
					     TAG_END);

		ng.ng_TextAttr = &Cyber;
		ng.ng_VisualInfo = vi;
		ng.ng_Width = 30;
		ng.ng_Height = CyberFont->tf_YSize + 2;
		ng.ng_Flags = 20;

		ng.ng_TopEdge += gad->Height + 5;
		ng.ng_LeftEdge = 19;
		ng.ng_GadgetText = "A";
		ng.ng_GadgetID = 12;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_LeftEdge += 44;
		ng.ng_GadgetText = "B";
		ng.ng_GadgetID = 13;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_LeftEdge += 44;
		ng.ng_GadgetText = "C";
		ng.ng_GadgetID = 14;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_LeftEdge += 44;
		ng.ng_GadgetText = "D";
		ng.ng_GadgetID = 15;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_TopEdge += CyberFont->tf_YSize + 6;
		ng.ng_LeftEdge = 19;
		ng.ng_GadgetText = "7";
		ng.ng_GadgetID = 7;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_LeftEdge += 44;
		ng.ng_GadgetText = "8";
		ng.ng_GadgetID = 8;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_LeftEdge += 44;
		ng.ng_GadgetText = "9";
		ng.ng_GadgetID = 9;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_LeftEdge += 44;
		ng.ng_GadgetText = "*";
		ng.ng_GadgetID = 10;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_TopEdge += CyberFont->tf_YSize + 6;
		ng.ng_LeftEdge = 19;
		ng.ng_GadgetText = "4";
		ng.ng_GadgetID = 4;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_LeftEdge += 44;
		ng.ng_GadgetText = "5";
		ng.ng_GadgetID = 5;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_LeftEdge += 44;
		ng.ng_GadgetText = "6";
		ng.ng_GadgetID = 6;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_LeftEdge += 44;
		ng.ng_GadgetText = "#";
		ng.ng_GadgetID = 11;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_TopEdge += CyberFont->tf_YSize + 6;
		ng.ng_LeftEdge = 19;
		ng.ng_GadgetText = "1";
		ng.ng_GadgetID = 1;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_LeftEdge += 44;
		ng.ng_GadgetText = "2";
		ng.ng_GadgetID = 2;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_LeftEdge += 44;
		ng.ng_GadgetText = "3";
		ng.ng_GadgetID = 3;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_Height = 2 * (CyberFont->tf_YSize + 2) + 6;
		ng.ng_LeftEdge += 44;
		ng.ng_GadgetText = "R";				     // Height * 2

		ng.ng_GadgetID = 17;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_Width = 74;
		ng.ng_Height = CyberFont->tf_YSize + 2;
		ng.ng_TopEdge += CyberFont->tf_YSize + 6;
		ng.ng_LeftEdge = 19;
		ng.ng_GadgetText = "0";
		ng.ng_GadgetID = 0;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		ng.ng_Width = 30;
		ng.ng_LeftEdge += 88;
		ng.ng_GadgetText = "P";
		ng.ng_GadgetID = 16;

		gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

		AddGList(MyWindow, glist, ~0, 20, NULL);

		RefreshGList(glist, MyWindow, NULL, 20);
	}

	if (GUI || composeNom)
	{
		if (!(fileRepertoire = Open((UBYTE *) "DTMF:repertoire.dat", MODE_READWRITE)))
			cleanUp("ouverture fichier de données impossible", 6);

		if (Read(fileRepertoire, " ", 1L) == 0)
		{
			Write(fileRepertoire, (char *) &n, 4);
			Flush(fileRepertoire);
		}

		Init();
	}

	switch ((device = OpenDevice((UBYTE *) AUDIONAME, 0, (struct IORequest *) allocIOB, 0)))
	    {
	    case IOERR_OPENFAIL:
		    cleanUp("Cannot open audio device", 6);

	    case ADIOERR_ALLOCFAILED:
		    cleanUp("Cannot allocate audio channels", 6);
	    }

	channels = (WORD) allocIOB->ioa_Request.io_Unit;
	channel0 = (channels & RIGHT0F) ? 0 : 1;
	channel1 = (channels & RIGHT1F) ? 3 : 2;

/*
 * if ((NarratorPort = (struct MsgPort *) CreatePort((UBYTE *) "DTMF_Narrator", 0L)) == NULL)
 * cleanUp("Cannot create reply port", 6);
 * 
 * if ((NarratorReq = (struct narrator_rb *) AllocMem(sizeof(struct narrator_rb), MEMF_PUBLIC | MEMF_CLEAR)) == 0)
 * cleanUp("Out of memory", 6);
 * 
 * NarratorDev = OpenDevice("narrator.device", 0, (struct IORequest *)NarratorReq, 0);
 * 
 * if (!NarratorDev)
 * {
 * NarratorReq->rate = 170;
 * NarratorReq->pitch = 70;
 * NarratorReq->mode = 0;
 * NarratorReq->sex = 0;
 * NarratorReq->ch_masks = (UBYTE *) allocationMap;
 * NarratorReq->nm_masks = (UWORD) sizeof(allocationMap);
 * NarratorReq->volume = 64;
 * NarratorReq->sampfreq = 27000;
 * NarratorReq->mouths = 0;
 * NarratorReq->message.io_Data = (APTR) SpokenString;
 * NarratorReq->message.io_Length = (ULONG) strlen((char *) SpokenString);
 * NarratorReq->message.io_Command = (UWORD) CMD_WRITE;
 * SendIO((struct IORequest *) NarratorReq);
 * }
 */
	while (FindPort(nameRexxPort))
	{
		if (strlen(nameRexxPort) == 9)
			strcat(nameRexxPort, "1");
		else
			nameRexxPort[10] = '0' + i++;
	}
	if (!(rexxPort = (struct MsgPort *) CreatePort(nameRexxPort, 0)))
		cleanUp("impossible de créer le port ARexx", 6);

	rexxPortBit = (1L << rexxPort->mp_SigBit);

	tr = create_timer(UNIT_MICROHZ);

}

/****************************************************************/
/*
 * ferme les devices, les librairies, libère la mémoire
 */
/*
 */
/*
 * Paramètres: message d'erreur
 */
/*
 * Retour: NULL
 */
/****************************************************************/
void
cleanUp(TEXT * message, int erreur)
{

	if (strlen(message) > 0)
	{
		if (FromWB)
			fputs((const char *) message, conwin);
		else
			puts((const char *) message);
	}

	Execute("assign DTMF: remove", 0, 0);			     // alors ça c'est curieux, il semblerait que ce soit
    // la seule possibilité de supprimé un assign ???

	if (tr)
		delete_timer(tr);

	if (rexxPort)
		DeletePort(rexxPort);

	if (NarratorDev == 0)
		CloseDevice((struct IORequest *) NarratorReq);

	if (device == 0)
		CloseDevice((struct IORequest *) allocIOB);

	if (NarratorReq != NULL)
		FreeMem(NarratorReq, sizeof(struct narrator_rb));

	if (allocIOB != NULL)
		FreeMem(allocIOB, sizeof(struct IOAudio));

	if (NarratorPort != NULL)
		DeletePort(NarratorPort);

	if (fileRepertoire != NULL)
		Close(fileRepertoire);

	if (CyberFont != NULL)
		CloseFont(CyberFont);

	if (LCDFont != NULL)
		CloseFont(LCDFont);

	if (setMenu)
		ClearMenuStrip(MyWindow);

	if (menuStrip)
		FreeMenus(menuStrip);

	if (MyWindow != NULL)
		CloseWindow(MyWindow);

	if (glist)
		FreeGadgets(glist);

	if (vi)
		FreeVisualInfo(vi);

	if (PubDrawInfo)
		FreeScreenDrawInfo(pubScreen, PubDrawInfo);

	if (pubScreen)
		UnlockPubScreen(NULL, pubScreen);

	if (IconBase != NULL)
		CloseLibrary((struct Library *) IconBase);

	if (GadToolsBase)
		CloseLibrary((struct Library *) GadToolsBase);

	if (IntuitionBase != NULL)
		CloseLibrary((struct Library *) IntuitionBase);

	if (GfxBase != NULL)
		CloseLibrary((struct Library *) GfxBase);

	if (conwin)
		fclose(conwin);

	exit(erreur);
}

struct timerequest *
create_timer(ULONG unit)
{
/* return a pointer to a timer request.  If any problem, return NULL */
	LONG    error;
	struct MsgPort *timerport;
	struct timerequest *TimerIO;

	timerport = (struct MsgPort *) CreatePort(0, 0);
	if (timerport == NULL)
		return (NULL);

	TimerIO = (struct timerequest *)
		CreateExtIO(timerport, sizeof(struct timerequest));

	if (TimerIO == NULL)
	{
		DeletePort(timerport);				     /* Delete message port */
		return (NULL);
	}

	error = OpenDevice(TIMERNAME, unit, (struct IORequest *) TimerIO, 0L);

	if (error != 0)
	{
		delete_timer(TimerIO);
		return (NULL);
	}
	return (TimerIO);
}

void 
delete_timer(struct timerequest *tr)
{
	struct MsgPort *tp;

	if (tr != 0)
	{
		tp = tr->tr_node.io_Message.mn_ReplyPort;

		if (tp != 0)
			DeletePort(tp);

		CloseDevice((struct IORequest *) tr);
		DeleteExtIO((struct IORequest *) tr);
	}
}
