
#include <PalmOS.h>

#include "RegisterLibrary.h"


/***********************************************************************
 *
 *	Function prototypes
 *
 ***********************************************************************/

static Err InitializeLibrary(UInt16 refNum, SysLibTblEntryPtr entryP);

/***********************************************************************
 *
 *  Library dispatch table             
 *
 *  This table gets installed into the dispatchTblP field of the library
 *  entry in the library table. It gives the 16-bit offset of every
 *  routine relative to the start of the dispatch table.
 *
 ***********************************************************************/

#define kNumDispatchEntries    14       // UPDATE THIS WHEN CALLS ARE ADDED TO @TABLE
#define kOffset                ((kNumDispatchEntries + 1) * 2)

static asm void** PrvGetDispatchTable( void )
{
    LEA     @Table, A0  // load table ptr
    RTS                 // exit with it

@Table:

    //  Offset to the name of this library.

    DC.W    @Name

    //  Offsets to the entry points
                              // Generic library entry points:
    DC.W    (kOffset+( 0*4))  //   Open
    DC.W    (kOffset+( 1*4))  //   Close
    DC.W    (kOffset+( 2*4))  //   Sleep
    DC.W    (kOffset+( 3*4))  //   Wake
                              // Mandatory Exchange Library entry points:
    DC.W    (kOffset+( 4*4))  //   HandleEvent
    DC.W    (kOffset+( 5*4))  //   Connect
    DC.W    (kOffset+( 6*4))  //   Accept
    DC.W    (kOffset+( 7*4))  //   Disconnect
    DC.W    (kOffset+( 8*4))  //   Put
    DC.W    (kOffset+( 9*4))  //   Get
    DC.W    (kOffset+(10*4))  //   Send
    DC.W    (kOffset+(11*4))  //   Receive
    DC.W    (kOffset+(12*4))  //   Control
    DC.W    (kOffset+(13*4))  //   Request

    //  The entry points.
    
    JMP     ExgDemoBExgLibOpen
    JMP     ExgDemoBExgLibClose
    JMP     ExgDemoBExgLibSleep
    JMP     ExgDemoBExgLibWake
    JMP     ExgDemoBExgLibHandleEvent
    JMP     ExgDemoBExgLibConnect
    JMP     ExgDemoBExgLibAccept
    JMP     ExgDemoBExgLibDisconnect
    JMP     ExgDemoBExgLibPut
    JMP     ExgDemoBExgLibGet
    JMP     ExgDemoBExgLibSend
    JMP     ExgDemoBExgLibReceive
    JMP     ExgDemoBExgLibControl
    JMP     ExgDemoBExgLibRequest

    //  The library name.
@Name:
    DC.B    RegisterLibName
}


/***********************************************************************
 *
 *  Library initialization procedure.
 *
 *  This function gets passed to SysLibInstall(), who calls it back
 *  after having allocated a slot in the system's library table.
 *  It performs the following initializations:
 *
 *    - allocation and initialization of globals
 *    - installation of the dispatch table
 *    - registration of the feature version
 *
 ***********************************************************************/
static Err InitializeLibrary(UInt16 refNum,             // this lib's refNum
                             SysLibTblEntryPtr entryP   // this lib's entry in system library table
                            )
{
   libGlobalType *gP;
   UInt32 version;
   Err err;

   //  Allocate globals, set low-mem ptr to them.
   gP = MemPtrNew(sizeof(libGlobalType));
   if (!gP) {
      ErrNonFatalDisplay("no memory for globals");
      return memErrNotEnoughSpace;
   }
   // Must be 3.0 or greater
   err = FtrGet(sysFtrCreator, sysFtrNumROMVersion, &version);

   //  Initialize globals.
   MemPtrSetOwner(gP, 0);       // Make System owner 
   MemSet(gP, sizeof(libGlobalType), 0);
   gP->refNum = refNum;         // make self reference
   gP->sysVersion = version;    // save os version for reference
   // Plug globals and dispatch table into our entry in the library table.
   entryP->globalsP = gP;
   entryP->dispatchTblP = PrvGetDispatchTable();

   return 0;
}



/***********************************************************************
 *
 *  Additional help functions
 *
 ***********************************************************************/

/***********************************************************************
 *
 *  Install this library, and register it with the Exchange Manager.
 *
 ***********************************************************************/
void RegisterLibrary(void)
{
   MemHandle codeH;
   UInt16 cardNo;
   LocalID dbID;
   UInt16 refNum;
   Err err;


   // Do nothing if this library is already installed.
   if (SysLibFind(RegisterLibName, &refNum) == 0) {
      return;
   }

   // Install this library.
   err = SysLibInstall(InitializeLibrary, &refNum);
   if (err) {
      ErrNonFatalDisplay("can't install library " RegisterLibName);
      return;
   }

   // Lock library/application code segment so it can be used outside this app.
#if EMULATION_LEVEL == EMULATION_NONE
   codeH = DmGet1Resource(sysResTAppCode, 1);
   MemHandleLock(codeH);
#else
#pragma unused( codeH )
#endif

   // Protect the library/application database so it can't be deleted.
   // TODO: use delete notification rather than protecting/unprotecting.
   err = SysCurAppDatabase(&cardNo, &dbID);
   err = DmDatabaseProtect(cardNo, dbID, true);

   // Register for notification about start of Hotsync and when about to be deleted.
   // Used to trigger unregister process. 
   err =
       SysNotifyRegister(cardNo, dbID, sysNotifySyncStartEvent, 0,
                         sysNotifyNormalPriority, 0);
   if (!err)
      err =
          SysNotifyRegister(cardNo, dbID, sysNotifyDeleteProtectedEvent,
                            NULL, sysNotifyNormalPriority, NULL);


   if (err) {
      ErrNonFatalDisplay("can't install");
      return;
   }
}


/***********************************************************************
 *
 *  Unregister this library with the Exchange Manager, and uninstall it.
 *  Returns the refnum of this library.
 *
 ***********************************************************************/
void UnRegisterLibrary(void)
{
   MemHandle codeH;
   UInt16 cardNo;
   LocalID dbID;
   UInt16 refNum;
   SysLibTblEntryPtr entryP;    // this lib's entry in system library table

   // Do nothing if this library is not installed.
   if (SysLibFind(RegisterLibName, &refNum))
      return;

   // Unregister for notification
   SysCurAppDatabase(&cardNo, &dbID);
   (void) SysNotifyUnregister(cardNo, dbID, sysNotifySyncStartEvent,
                              sysNotifyNormalPriority);
   (void) SysNotifyUnregister(cardNo, dbID, sysNotifyDeleteProtectedEvent,
                              sysNotifyNormalPriority);


   // Unprotect the library/application database.
   // TODO: use delete notification rather than protecting/unprotecting.
   DmDatabaseProtect(cardNo, dbID, false);

   // Unlock library/application code segment.
#if EMULATION_LEVEL == EMULATION_NONE
   codeH = DmGet1Resource(sysResTAppCode, 1);
   MemHandleUnlock(codeH);
#else
#pragma unused( codeH )
#endif

   // Free the library's Globals if the library hasn't already
   entryP = SysLibTblEntry(refNum);
   if (entryP && entryP->globalsP)
      MemPtrFree(entryP->globalsP);

   // Uninstall this library.
   SysLibRemove(refNum);
}

