
#include <PalmOS.h>
#include <PCENativeCall.h>
#include <PNOLoader.h>
#include <VfsMgr.h>
#include <PalmOSGlue.h>
#include "StarterRsc.h"
#include "host68k.h"
#include "display68k.h"
#include "pnobridge.h"
#include "starter.h"
#include <Incs/Core/System/DLServer.h>
#include "stdfile.h"
#include "zodiac.h"

Boolean exit_launcher = false;
UInt16 currSysSoundVolume;

static Err RomVersionCompatible ( UInt32 requiredVersion,
				  UInt16 launchFlags )
{
  UInt32 romVersion;

  // See if we're on in minimum required version of the ROM or later.
  FtrGet(sysFtrCreator, sysFtrNumROMVersion, &romVersion);

  if ( romVersion < requiredVersion ) {
    if ((launchFlags & (sysAppLaunchFlagNewGlobals | sysAppLaunchFlagUIApp)) ==
	(sysAppLaunchFlagNewGlobals | sysAppLaunchFlagUIApp))
    {
      FrmAlert (RomIncompatibleAlert);
		
      // Palm OS 1.0 will continuously relaunch this app unless we switch to 
      // another safe one.
      if (romVersion <= kPalmOS10Version) {
	AppLaunchWithCommand(sysFileCDefaultApp, sysAppLaunchCmdNormalLaunch, NULL);
      }
    }
		
    return sysErrRomIncompatible;
  }

  return errNone;
}

void * GetObjectPtr ( UInt16 objectID ) {
  FormPtr frmP;
  frmP = FrmGetActiveForm();
  return FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, objectID));
}

static void MainFormInit ( FormPtr frmP ) {
  return;
}

static Boolean MainFormDoCommand ( UInt16 command ) {
  Boolean handled = false;
  FormPtr frmP;
	
  return handled;
}

static Boolean MainFormHandleEvent ( EventPtr eventP ) {
  Boolean handled = false;
  FormPtr frmP;
  FILE *f;

  switch ( eventP -> eType ) {

  case ctlSelectEvent:

    switch ( eventP -> data.ctlSelect.controlID ) {
    case GoButton:
      run_emu();
      exit_launcher = true;
      break;
    } // switch

    break;

  case frmOpenEvent:
  	{
		UInt32 freeMem,maxMem;
		Char strtmp[64];  
    	frmP = FrmGetActiveForm();
    	MainFormInit( frmP );
		MemHeapFreeBytes(0,&freeMem,&maxMem);	
		StrPrintF(strtmp,"Free Heap: %ldK",freeMem/1024);
		FrmCopyLabel  (frmP,LauncherFrmRAM,strtmp);    
    	FrmDrawForm ( frmP);
    	handled = true;
    break;
	}		
  case frmUpdateEvent:
    // To do any custom drawing here, first call FrmDrawForm(), then do your
    // drawing, and then set handled to true.
    break;

  case frmCloseEvent:
    break;

  default:
    break;
		
  }
	
  return handled;
}

Boolean AppHandleEvent ( EventPtr eventP ) {
  UInt16 formId;
  FormPtr frmP;

  if (eventP->eType == frmLoadEvent) {
    // Load the form resource.
    formId = eventP->data.frmLoad.formID;
    frmP = FrmInitForm(formId);
    FrmSetActiveForm(frmP);

    // Set the event handler for the form.  The handler of the currently
    // active form is called by FrmHandleEvent each time is receives an
    // event.
    switch (formId) {

    case MainForm:
      FrmSetEventHandler(frmP, MainFormHandleEvent);
      break;

    default:
      // ErrFatalDisplay("Invalid Form Load Event");
      break;

    }
    return true;
  }
	
  return false;
}

static void AppEventLoop ( void ) {
  UInt16 error;
  EventType event;

  do {
    EvtGetEvent(&event, evtWaitForever);

    if (! SysHandleEvent(&event))
	if (! AppHandleEvent(&event))
	  FrmDispatchEvent(&event);

	if( exit_launcher == true )
	{
		break;
	}
  } while (event.eType != appStopEvent);

  return;
}

static Err AppStart ( void ) {
  UInt16 voliter;
  FileRef dirRef = 0;
  Err error;

  /* create our directory if we can't open it..
   */
  voliter = palm_vfs_iter();

  error = VFSFileOpen ( voliter, VFSPATH, vfsModeRead, &dirRef );

  if ( error != errNone ) {
    error = VFSDirCreate ( voliter, VFSROOT );
    error = VFSDirCreate ( voliter, VFSPATH );

    error = VFSFileOpen ( voliter, VFSPATH, vfsModeRead, &dirRef );

    if ( error != errNone ) {
      ErrNonFatalDisplay (
		       "TTD requires expansion media for its "
		       "data files; put media in first slot.");
      return ( -1 );
    }

  }

  VFSFileClose ( dirRef );

#ifdef HW16BPP
  /* go to 16bpp
   */
  if ( ! hw_set16bpp() ) {
    DEBUGS ( "Couldn't set to 16 bit colour!" );
    return ( 1 );
  }
#endif

  /* zodiac?
   */
  if ( is_zodiac() ) {
    g_zodiac = 1;
  } // zodiac

  // Disable System Level Sounds
  currSysSoundVolume = PrefGetPreference(prefSysSoundVolume);
  PrefSetPreference(prefSysSoundVolume, 0);

  return errNone;
}

static void AppStop ( void ) {
  // restore graffiti and stat windows
  hw_set_fullscreen(0);
  hw_show_grafitti(1);
  
  // Close all the open forms.
  FrmCloseAllForms ();
  
  // Disable System Level Sounds
  PrefSetPreference(prefSysSoundVolume, currSysSoundVolume);
}

static
UInt32 StarterPalmMain ( UInt16 cmd, MemPtr /*cmdPBP*/, UInt16 launchFlags ) {
  Err error;

  error = RomVersionCompatible (kOurMinVersion, launchFlags);
  if ( error ) return ( error );

  switch (cmd) {

  case sysAppLaunchCmdNormalLaunch:
    error = AppStart();
    if (error) 
      return error;
				
    FrmGotoForm(MainForm);
    AppEventLoop();
    AppStop();
    break;

  default:
    break;

  }
	
  return errNone;
}

UInt32 PilotMain ( UInt16 cmd, MemPtr cmdPBP, UInt16 launchFlags ) {
  return ( StarterPalmMain ( cmd, cmdPBP, launchFlags ) );
}

void run_emu ( void ) {
  UInt32 processor;
  UInt32 flags = 0;
  UInt16 pitch, width, height;
  ControlType *c;
  FormPtr frmP = FrmGetActiveForm();

  // is zodiac?
  if( g_zodiac > 0 )
  {
  	flags |= BF_ZODIAC;
  }
  // hide controls
  FrmHideObject ( frmP, FrmGetObjectIndex ( frmP, GoButton ) );

  // init screen dimensions and display flags then set to full screen
  hw_guess_screen_dimensions ( &width, &height, &pitch );
  hw_show_grafitti(0);
  hw_set_fullscreen(1);
  
  // call the PACE Native Object
  FtrGet(sysFtrCreator, sysFtrNumProcessorID, &processor);

  if ( sysFtrNumProcessorIsARM ( processor ) /*&&
       LstGetSelection ( list ) >= 0*/ )
  {
    PnoDescriptor pno;
    pnobridge_t *bridge = (pnobridge_t*) MemPtrNew ( sizeof(pnobridge_t) );
    MemHandle mh;
    MemPtr pnoPtr;
    UInt32 result;
    UInt32 pnosize = 0;
    UInt16 iter = 1;
    UInt8 *pnobuf = NULL;
    UInt8 *pnotarget;

    bridge -> vfs_max = palm_vfs_count();
    bridge -> vfs_vol = palm_vfs_iter();
    bridge -> vram = (UInt32) hw_query_vram();
    bridge -> eventf = (UInt32) host_event_handler;
    bridge -> display_width = width;
    bridge -> display_height = height;
    bridge -> display_pitch = pitch;
    bridge -> game_rom = (UInt32) 0;
    bridge -> audio_buf = (UInt32) 0;
    bridge -> flags = flags;

    // how large is pnolet?
    while ( ( mh = DmGetResource ( 'COJO', iter ) ) ) {
      pnosize += MemHandleSize ( mh );
      iter++;
      DmReleaseResource ( mh );
    }

    // get pnolet memory
    pnobuf = (UInt8*) MemGluePtrNew ( pnosize );

    if ( pnobuf == NULL ) {
      DEBUGS ( "Couldn't allocate enough storage memory for engine!" );
      return;
    }

    //StrPrintF ( buf, "Allocated %lu size pnolet.", pnosize );
    //DEBUGS ( buf );

    // reset
    iter = 1;
    pnotarget = pnobuf;

    // read pnolet into buffer
    while ( ( mh = DmGetResource ( 'COJO', iter ) ) ) {
      char msg [ 100 ];

      // lock source
      UInt8 *p = (UInt8*) MemHandleLock ( mh );

      // copy data
      MemMove ( pnotarget, p, MemHandleSize ( mh ) );
      //DmWrite ( pnobuf, pnotarget - pnobuf, p, MemHandleSize ( mh ) );

      // log
      //StrPrintF ( msg, "Assembling emulator core [ %u ]", iter );
      //WinDrawChars ( msg, StrLen ( msg ), 0, 150 );

      // unlock
      MemHandleUnlock ( mh );

      // next!
      pnotarget += MemHandleSize ( mh );
      iter++;
      DmReleaseResource ( mh );
    }

    //mh = DmGetResource('COJO', 1);
    //pnoPtr = MemHandleLock(mh);
    pnoPtr = pnobuf;

    // fire up pnolet
    PnoLoad(&pno, pnoPtr);
    result = PnoCall ( &pno, bridge );
    PnoUnload(&pno);

    //DEBUGU32 ( result );

    //MemHandleUnlock(mh);
    //DmReleaseResource(mh);
    MemPtrFree ( bridge );
    MemPtrFree ( pnobuf );
  }
  
  return;
}
