/*-------------------------------------------------------*/
/* ProjectOmega                 									*/
/* Written by T.Miles												*/
/* ID: 289175															*/
/* Module:	App Class												*/
/* Responsible for message passing & realtime clock 		*/
/* initiation															*/
/*-------------------------------------------------------*/
#include <clib/exec_protos.h>
#include <stdio.h>
#include <intuition/intuition.h>
#include <clib/intuition_protos.h>
#include <clib/alib_protos.h>
#include <clib/realtime_protos.h>
#include <iostream.h>
#include <libraries/realtime.h>
#include <cybergraphx/cybergraphics.h>
#include <libraries/mui.h>
#include <string.h> 
 
#include "misc/systemdefs.h"
#include "app.h"
OmegaApp::OmegaApp(){
	if (oa_OpenLibraries()==FALSE){
		oa_PurgeLibs();
		exit (10);
	}
	oa_appTitle=NULL;
	oa_SetName("ProjectOmega");
	oa_Author=NULL;
	oa_Version=NULL;
	oa_Date=NULL;
	basePort=replyPort=NULL;
	dataMessage=NULL;
	oa_running=FALSE;
	oa_quit=FALSE;
	oa_realtime=FALSE;
	oa_Tempo=120;
	oa_Player=NULL;
	oa_playerSignal=-1;
	msgBuffer=new OmegaMessage[MAXMSGS];		// Set up a message buffer		
	dataMessage=&msgBuffer[0];						// Point to the first one
	curMsgIndex=0;
}

OmegaApp::~OmegaApp(){
//	cout << "Deleting app" << endl;
	FreeSignal(oa_playerSignal);
	if (msgBuffer)
		delete []msgBuffer;
	if (oa_Player)
		DeletePlayer(oa_Player);
	if (basePort)
		DeletePort(basePort);
	if (replyPort)
		DeletePort(replyPort);
	if (oa_appTitle)
		delete[] oa_appTitle;
	oa_PurgeLibs();
}

BOOL OmegaApp::Initialise(char *name){
	BOOL Success=TRUE;
	Task *thisTask;
	UINT n;
	// Setup message ports
	basePort=CreatePort(name,0);
	replyPort=CreatePort(NULL,0);
	if (!basePort || !replyPort){
		if (basePort)
			DeletePort(basePort);
		if (replyPort)
			DeletePort(replyPort);
		Error("Unable to Create MsgPorts","Too Many Plugins?");
		return FALSE;
	}
	else{
		// Set some standard entries - other stuff is initialised by the
		// derived class as needed
		// Let's just hope these don't get overriden!
		// Moved here to speed up the SendPort() function
		for (n=0;n<MAXMSGS;n++){
			msgBuffer[n].om_Message.mn_ReplyPort=replyPort;
			msgBuffer[n].om_Message.mn_Length=sizeof(OmegaMessage);
			msgBuffer[n].om_Message.mn_Node.ln_Name="OmegaMsg";
			msgBuffer[n].om_Port=basePort;
		}
	}
	// Set up the realtime library player and conductor
	// I wonder if it might be better to set this up if needed??
	// We should still allocate a signal as we need to WAIT for it,
	// but the rest could possibly wait I suppose!
	if (oa_realtime){
		thisTask=FindTask(NULL);
		oa_playerSignal=AllocSignal(-1L);
			if (oa_playerSignal){
			oa_Player=CreatePlayer(PLAYER_Name, oa_appTitle,
									PLAYER_Conductor, oa_appTitle,
									PLAYER_AlarmSigTask, thisTask,
									PLAYER_AlarmSigBit, oa_playerSignal,
									TAG_END);
			if (!oa_Player)
				Success=FALSE;
			else
			if (SetConductorState(oa_Player, CONDSTATE_STOPPED,0L)!=0){
				Success=FALSE;		
			}
		}
		else
			Success=FALSE;
		if (!Success){
			Error("Unable To Initialise RealTime Stuff",NULL);
			return FALSE;
		}
	}
	return TRUE;
}

void OmegaApp::oa_PurgeLibs(){
	extern struct Library *RealTimeBase;
	if (IntuitionBase) CloseLibrary(IntuitionBase);
 	if (AslBase) CloseLibrary(AslBase);
	if (DosBase) CloseLibrary(DosBase);
	if (RealTimeBase) CloseLibrary(RealTimeBase);
	if (MUIMasterBase) CloseLibrary(MUIMasterBase);
	if (GfxBase) CloseLibrary(GfxBase);
	if (CyberGfxBase) CloseLibrary(CyberGfxBase);
}

BOOL OmegaApp::oa_OpenLibraries(){
	extern struct Library *RealTimeBase;
	char version[255];
	ULONG verNo;
	
	BOOL result=TRUE;
 	if (!(IntuitionBase=OpenLibrary("intuition.library",0L))){
 		result=FALSE;
 	}
 	if (!(AslBase=OpenLibrary("asl.library",0L))){
 		Error("Unable to open Asl.Library",NULL);
 		result=FALSE;
	}
 	if (!(DosBase=OpenLibrary("dos.library",0L))){
 		Error("Unable to open dos.Library",NULL);	
 		result=FALSE;
	}
	if (!(RealTimeBase=OpenLibrary("realtime.library",0L))){
		Error("Unable to open Realtime.Library",NULL);
		result=FALSE;
	}
	verNo=MUIMASTER_VLATEST;
	if (!(MUIMasterBase=OpenLibrary(MUIMASTER_NAME,verNo))){
		scanf(&version[0],"Version %d required",verNo);
		Error("Unable to open MUIMaster.Library",&version[0]);
		result=FALSE;
	}
	if (!(GfxBase=OpenLibrary("graphics.library",0L))){
		Error("Unable to open Graphics.Library",NULL);
		result=FALSE;
	}
	if (!(CyberGfxBase=OpenLibrary(CYBERGFXNAME,CYBERGFX_INCLUDE_VERSION))){
		verNo=CYBERGFX_INCLUDE_VERSION;
		scanf(&version[0],"Version %d required",verNo);
		Error("Unable to open Cybergraphics.Library",&version[0]);
		result=FALSE;
	}
	return result;
}

void OmegaApp::Error(char *msg, char *reason){
	UINT len=strlen(&oa_appTitle[0]);
	char *errorTitle=new char[len+8];
	memcpy(errorTitle,&oa_appTitle[0],len);
	memcpy(errorTitle+len," Error",6);
	errorTitle[len+6]=0;
	
	struct EasyStruct ErrorES = {
   	sizeof (struct EasyStruct),
      0,
      errorTitle,
      "%s\n%s",
      "OK!",
   };
	
	while(EasyRequest(NULL,&ErrorES,NULL,msg,reason)!=0){};
	delete [] errorTitle;
}

void OmegaApp::Report(char *msg, char *reason){
	UINT len=strlen(&oa_appTitle[0]);
	char *errorTitle=new char[len+8];
	memcpy(errorTitle,&oa_appTitle[0],len);
	memcpy(errorTitle+len," Message",8);
	errorTitle[len+8]=0;
	
	struct EasyStruct ErrorES = {
   	sizeof (struct EasyStruct),
      0,
      errorTitle,
      "%s\n%s",
      "OK!",
   };
	
	while(EasyRequest(NULL,&ErrorES,NULL,msg,reason)!=0){};
	delete [] errorTitle;
}

void OmegaApp::About(){
	UINT len=strlen(&oa_appTitle[0]);
	char *aboutTitle=new char[len+8];
	memcpy(aboutTitle,"About ",6);
	memcpy(aboutTitle+6,&oa_appTitle[0],len);
	aboutTitle[len+6]=0;
	
	struct EasyStruct ErrorES = {
   	sizeof (struct EasyStruct),
      0,
      aboutTitle,
      "Author: %s\nVersion: %s\nDate: %s",
      "OK!",
   };
	
	while(EasyRequest(NULL,&ErrorES,NULL,oa_Author,oa_Version,oa_Date)!=0){};
	delete[] aboutTitle;
}

void OmegaApp::oa_SetStatus(UINT status,BOOL state){
	switch(status){
	case APP_STATUS_RUNNING:
		oa_running=state;
		break;
	case APP_STATUS_QUIT:
		oa_quit=state;
		break;
	case APP_STATUS_REALTIME:
		SetTaskPri(FindTask(NULL),21);		// If we're using realtime then up the priority
		oa_realtime=state;
		break;
	}
}

//
// If we are using the timer then we need to set the alarm - i.e. when it
// will send a message to our task
// Set this to 0 to stop the timer
//
BOOL OmegaApp::oa_SetTimerAlarm(ULONG alarm){
	if (oa_alarmtime!=alarm){
//		cout << "Alarm time set to: "<< alarm << endl;
		oa_alarmtime=alarm;
	}
	
	if (oa_realtime){
		SetConductorState( oa_Player, CONDSTATE_RUNNING,0L);
		SetPlayerAttrs(oa_Player, PLAYER_AlarmTime, alarm,
						   PLAYER_Ready, TRUE,
							TAG_END);
	}
	else
		cout << "realtime not set" << endl;
	return TRUE;
}

//
// If we've got through to the app level with our message then there's not 
// a lot left to do with it!
void OmegaApp::DealWithMessage(OmegaMessage *msg){
	UINT Class=msg->om_Class;
	ReplyMsg((Message *)msg);
	
	switch(Class){
	case OM_START:
		oa_running=TRUE;
		OnStart();
		break;
	case OM_QUIT:
		oa_quit=TRUE;	// Fall through to stop running as well
		oa_running=FALSE;
		OnQuit();
		break;
	case OM_STOP:
		oa_running=FALSE;
		OnStop();
		break;
	case OM_ABOUT:
		About();
		break;
	}
}

// Send a message to port specified - dataMessage must be initialised
// properly before hand!
void OmegaApp::SendToPort(MsgPort * port, BOOL wait){
	dataMessage->om_Tempo=oa_Tempo;
	BOOL debug=FALSE;
	UINT lastIndex=curMsgIndex;

//	if (dataMessage->om_Type!=OMEGAINPUT)
//		debug=TRUE;
	// Send the blighter if there's a valid port to send it to
	if (port){
		if (debug){
			cout << "Sent msg " << (UINT)dataMessage->om_Class;
			cout << " to " << (UINT)port << endl; 
		}
	 	PutMsg(port,(Message *)dataMessage);
		if (wait){
 			WaitPort(replyPort);
 			if (debug)
 				cout << "Received reply" << endl;
 			GetMsg(replyPort); 	// Kill the reply
 		}
 		// We're being impatient with our msgs so we must need a buffer
 		// If we're waiting for a reply then it's okay to reuse the same one
 		else{
	 		curMsgIndex++;
 			if (curMsgIndex>=MAXMSGS)
 				curMsgIndex=0;
 			dataMessage=&msgBuffer[curMsgIndex];
 		// We use a 'running status' on msg->Class  & type so we need to see
 		// what the last one was
 			dataMessage->om_Class=msgBuffer[lastIndex].om_Class;
 			dataMessage->om_Type=msgBuffer[lastIndex].om_Type;
 		}	
 	}
 	else
 		cout << "Port not found " << endl;
}


void OmegaApp::oa_SetName(char *name){
	if (oa_appTitle!=NULL)		// Delete the space used if we've set the name b4
		delete[] oa_appTitle; 
		
	oa_appTitle=new char[strlen(name)+1];
	strcpy(oa_appTitle,name);
}

void OmegaApp::StopConductor(){
	if (oa_realtime && SetConductorState(oa_Player, CONDSTATE_STOPPED,0L)!=0)
		Error("Couldn`t stop conductor",NULL);
}

void OmegaApp::StartConductor(){
	if (oa_realtime && SetConductorState( oa_Player, CONDSTATE_RUNNING,0L)!= 0)
		Error("Couldn't start timer",NULL);
}