//
//	File/database manipulation routines
//
//	Paul Nash
//	paul@frcs.alt.za

//
//	$Header: /usr/home/pilot/gypsy-1.6/RCS/file.c,v 1.14 1999/08/30 06:35:32 paul Exp $
//
//	$Log: file.c,v $
//	Revision 1.14  1999/08/30 06:35:32  paul
//	Added Jaque Andre's patches
//
//	Revision 1.13  1999/05/12 08:48:05  paul
//	Ready for release as Gypsy 1.4.  Major changes include:
//	*  Rudimentary track/route buffer to transfer data between GPS
//	   and PC (a'la gps2p2pc)
//	*  Protocol fix for DLE escaping bug
//	*  Code changes from <andre@drfmc.ceng.cea.fr> to be able to
//	   compile a PalmOS2 version
//	*  Garmin protocol tries a bit harder to recover from comms
//	   errors (but is still *very* dumb)
//
//


#pragma pack(2)

#include "gps.h"
#include <Common.h>
#include <System/SysAll.h>
#include <UI/UIAll.h>
#include <UI/Progress.h>
//	This is only needed for the GNU C/C++ 0.5 cross-compiler
#include "callback.h"

#include "globals.h"


//
//	Local function prototypes
//

void fileDrawName (VoidPtr tbl, Word row, Word column, RectanglePtr bounds);
int HandleFileMenu (Word menu_item);
int HandleFileButton (Word button);
void DisplayFileTable (void);
void MergeDatabase (LocalID id, UInt card);
Boolean mergeProgressCallback (PrgCallbackData *data);


//	Internal global variables and the like

static char *rcs_id = "$Id: file.c,v 1.14 1999/08/30 06:35:32 paul Exp $";
static LocalID current_file = -1;
static UInt current_card = 0;
extern DWord romVersion;

Boolean HandleFileListEvent (EventPtr e)
{
   int handled = false;
   FormPtr form;
   TablePtr table;
   Word row;

   CALLBACK_PROLOGUE;
   form = FrmGetActiveForm ();
   switch (e->eType) {
      case frmOpenEvent:
	 setField (dbName, currentDBName ());
	 FrmDrawForm (form);
	 DisplayFileTable ();
	 current_file = -1;
	 handled = true;
	 break;
      case tblSelectEvent:
	 table = FrmGetObjectPtr( form, FrmGetObjectIndex( form, fileTable ));
	 row = e->data.tblSelect.row;
	 current_file = TblGetRowData (table, row);
	 current_card = TblGetItemInt (table, row, 2);
	 handled = true;
	 break;
      case ctlSelectEvent:
         handled =  HandleFileButton (e->data.ctlEnter.controlID);
	 break;
      default:
	break;
   }
   CALLBACK_EPILOGUE;
   return handled;
}


//
//	Display a table of file names with our Application ID
//

void DisplayFileTable ()
{
   int i;
   FormPtr form;
   TablePtr table;
   FieldPtr field;
   DmSearchStateType state;
   Boolean new = true;
   UInt card;
   ULong nrecs = 42;
   LocalID id = 0,
	   current_id = -1;

   form = FrmGetActiveForm();
   table = FrmGetObjectPtr( form, FrmGetObjectIndex( form, fileTable ));
   field = FrmGetObjectPtr (form, FrmGetObjectIndex (form, dbName));
   if (waypoint_db) {
      DmOpenDatabaseInfo (waypoint_db, &current_id, NULL, NULL, NULL, NULL);
   }
   FldEraseField (field);
   setField (dbName, currentDBName ());
   FldDrawField (field);
   TblEraseTable (table);
   TblSetColumnUsable (table, 0, true);
   TblSetColumnUsable (table, 1, true);
   TblSetColumnUsable (table, 2, true);
   TblSetCustomDrawProcedure (table, 0, fileDrawName);
   for (i = 0; i < TABLE_ROWS; ++i) {
      if (DmGetNextDatabaseByTypeCreator (new, &state, DB_TYPE, DB_APPID,
					  false, &card, &id)) {
	 TblSetRowUsable (table, i, false);
      }
      else {
	 new = false;
	 if (waypoint_db && file_merge && current_id == id) {
	    --i;
	    continue;
	 }
	 TblSetRowData (table, i, id);
	 TblSetItemStyle (table, i, 0, customTableItem);
	 DmDatabaseSize (card, id, &nrecs, NULL, NULL);
	 TblSetItemStyle (table, i, 1, numericTableItem);
	 TblSetItemInt (table, i, 1, nrecs);
	 TblSetItemStyle (table, i, 2, numericTableItem);
	 TblSetItemInt (table, i, 2, card);
	 TblSetRowUsable (table, i, true);
	 TblSetRowSelectable (table, i, true);
	 TblMarkRowInvalid (table, i);
      }
   }
   TblDrawTable (table);
}


//
//	Custom draw procedure for the file name.  Takes the 
//	local ID & gets the name.
//

void fileDrawName (VoidPtr tbl, Word row, Word column, RectanglePtr bounds)
{
   char txt[32];
   LocalID id;
   FontID old_font;
   UInt card;

   CALLBACK_PROLOGUE;
   id = TblGetRowData (tbl, row);
   card = TblGetItemInt (tbl, row, 2);
   if (DmDatabaseInfo (card, id, txt, NULL, NULL, NULL, NULL, NULL,
				      NULL, NULL, NULL, NULL, NULL)) {
      CALLBACK_EPILOGUE;
      return;
   }
   old_font = FntSetFont (0);
   WinDrawChars (txt, StrLen(txt), bounds->topLeft.x, bounds->topLeft.y);
   FntSetFont (old_font);
   CALLBACK_EPILOGUE;
   return;
}


//
//	Process the various buttons.
//

int HandleFileButton (Word button)
{
   int handled = false;
   FormPtr form;
   LocalID id = -1;
   char name[32];

   form = FrmGetActiveForm ();
   switch (button) {
      case gpsOkBtn:
	 if (current_file != -1) {
	    if (! file_merge) {
	       if (waypoint_db) {
		  DmCloseDatabase (waypoint_db);
		  waypoint_db = NULL;
	       }
	       waypoint_db = DmOpenDatabase (current_card, current_file,
					     dmModeReadWrite);
	       num_records = DmNumRecords (waypoint_db);
	       table_top = 0;
	       FrmGotoForm (gpsWptListFrm);
	    }
	    else {
	       MergeDatabase (current_file, current_card);
	       num_records = DmNumRecords (waypoint_db);
	       table_top = 0;
	    }
	 }
	 else {
	    FrmAlert (noActiveDB);
	 }
	 handled = true;
	 break;
      case gpsNokBtn:
	 if (waypoint_db) {
	    FrmGotoForm (gpsWptListFrm);
	 }
	 else {
	    FrmAlert (noActiveDB);
	 }
	 handled = true;
	 break;
      case gpsKillBtn:
	 if (current_file != -1) {
	    DmDatabaseInfo (current_card, current_file, name, NULL, NULL,
			    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
	    if (FrmCustomAlert (fileDeleteAlert, name, " ", " ") == 0) {
	       if (waypoint_db) {
		  DmOpenDatabaseInfo (waypoint_db, &id, NULL, NULL, NULL, NULL);
		  if (current_file == id) {
		     DmCloseDatabase (waypoint_db);
		     waypoint_db = NULL;
		  }
	       }
	       DmDeleteDatabase (current_card, current_file);
	    }
	 }
	 current_file = -1;
	 DisplayFileTable ();
	 handled = true;
	 break;
      case gpsNewBtn:
	 newfile_camefrom = FrmGetFormId (form);
	 FrmPopupForm (gpsFileNewFrm);
	 handled = true;
	 break;
      default:
	 FrmAlert (gpsAlert1);
	 handled = true;
	 break;
   }
   return handled;
}


//
//	Handle creating a new file, including getting filename
//

Boolean HandleFileNewEvent (EventPtr e)
{
   int handled = false;
   Word err;
   char name[64];
   FormPtr form;

   CALLBACK_PROLOGUE;
   form = FrmGetActiveForm ();
   switch (e->eType) {
      case frmOpenEvent:
	 FrmDrawForm (form);
	 FrmSetFocus (form, FrmGetObjectIndex (form, newFile));
	 handled = true;
	 break;
      case ctlSelectEvent:
         switch (e->data.ctlEnter.controlID) {
	    case gpsOkBtn:
	       getField (newFile, name);
	       if (name[0] != '\0') {
		  err = DmCreateDatabase (0, name, DB_APPID, DB_TYPE, false);
		  if (!err &&
		      newfile_camefrom == gpsWptListFrm && waypoint_db) {
		     DmCloseDatabase (waypoint_db);
		     waypoint_db = NULL;
		  }
		  if (!waypoint_db) {
		     current_file = DmFindDatabase (0, name);
		     waypoint_db = DmOpenDatabase (0, current_file,
						   dmModeReadWrite);
		  }
		  FrmCloseAllForms ();
		  if (newfile_camefrom) {
		     FrmGotoForm (newfile_camefrom);
		  }
		  else {
		     FrmGotoForm (gpsWptListFrm);
		  }
	       }
	       handled = true;
	       break;
	    case gpsNokBtn:
	       FrmReturnToForm (0);
	       handled = true;
	       break;
	 }
	 break;
      default:
	break;
   }
   CALLBACK_EPILOGUE;
   return handled;
}


//
//	Merge another database into the current waypoint db
//

void MergeDatabase (LocalID id, UInt card)
{
   UInt i = 0,
        new;
   VoidHand rec, new_rec;
   DmOpenRef db;
   struct waypoint *wpt, *new_wpt;
   LocalID my_id = -1;
   UInt my_card;
   char msg[64];
   ProgressPtr progress = NULL;

   if (!waypoint_db) {
      FrmAlert (gpsAlert1);
      DisplayFileTable ();
      return;
   }
   DmOpenDatabaseInfo (waypoint_db, &my_id, NULL, NULL, &my_card, NULL);
   if (my_id == id && my_card == card) {
      FrmAlert (gpsAlert1);
      DisplayFileTable ();
      return;
   }
   if (! (db = DmOpenDatabase (card, id, dmModeReadOnly))) {
      DisplayFileTable ();
      return;
   }
   new = DmNumRecords (db);
   StrCopy (msg, " / ");
   StrIToA (msg + 3, new);
   if ( romVersion >= 0x03000000) {
      progress = PrgStartDialog ("Merge waypoints", mergeProgressCallback);
   }
   while (true) {
      if (! (rec = DmQueryRecord (db, i++))) {
	 break;
      }
      if ( romVersion >= 0x03000000) {
         PrgUpdateDialog (progress, 0, ++i, msg, true);
      }
      new = DmNumRecords (waypoint_db) + 1;
      new_rec = DmNewRecord (waypoint_db, &new, sizeof (struct waypoint));
      wpt = (struct waypoint *) MemHandleLock (rec);
      new_wpt = (struct waypoint *) MemHandleLock (new_rec);
      DmWrite (new_wpt, 0, wpt, sizeof (struct waypoint));
      MemHandleUnlock (rec);
      MemHandleUnlock (new_rec);
      DmReleaseRecord (waypoint_db, new, true);
   }
   if ( romVersion >= 0x03000000) {
      PrgStopDialog (progress, true);
   }
   DmCloseDatabase (db);
   DisplayFileTable ();
   return;
}


//
//	Callback routine for the progress dialogue box
//

Boolean mergeProgressCallback (PrgCallbackData *data)
{
   CALLBACK_PROLOGUE;
   if (data->textLen > 20) {
      StrCopy (data->textP, "Record ");
   }
   else {
      data->textP[0] = '\0';
   }
   StrIToA (data->textP + StrLen (data->textP), data->stage);
   StrCat (data->textP, data->message);
   data->textChanged = true;
   CALLBACK_EPILOGUE;
   return true;
}
