/* custom.c contains the list feature selection/customization
 */

/* Includes required */
#include <Common.h>
#include <System/SysAll.h>
#include <UI/UIAll.h>
#include "listrc.h"
#include "list.h"

Boolean CustomFormEventHandler(EventPtr event)
{
  FormPtr form;
  FieldPtr field;
  Word len;
  VoidHand textHandle;
  Char *text;
  Boolean handled = false;
  ListPreferences preferences;
  ControlPtr ctl;
  ListPtr lst;
  int errorID;
  LocalID dbID;
  UInt cardNo;
  UInt dbAttr;
  CALLBACK_PROLOGUE;   /* Work around PilotGCC 0.5.0 bug */

  switch( event->eType ) 
    {
    case ctlSelectEvent:
      if( event->data.ctlSelect.controlID == idCustomDoneButton ) {

	if(( errorID = CustomFormClose()) != 0 ) {
	  FrmAlert( errorID );
	} else {
	  FrmGotoForm( idMainForm );
	}
	handled = true;
      }
      break;

    case frmOpenEvent:
      form = FrmGetActiveForm();

      /* list name */
      field = FrmGetObjectPtr(form, FrmGetObjectIndex( form, idCustomFieldListName ) );
      /* we don't have to free the current text handle since its NULL (the form is being opened) */
      len = StrLen( ListDBName );
      textHandle = MemHandleNew( len + 1 );
      if( textHandle == NULL ) { /* deal with out of memory case */
		  FrmAlert( bad ); 
		  break;
      }
      StrCopy( MemHandleLock( textHandle ), ListDBName );
      MemHandleUnlock( textHandle );
      FldSetText( field, textHandle, 0, len + 1 );
      /* The textHandle will be freed by the form when it is closed (ROOHACK is this true?)*/

      /* Build some helpers here too to save memory */

      /* field 1 */
      field = FrmGetObjectPtr(form, FrmGetObjectIndex( form, idCustomFieldField1 ) );
      len = StrLen( CustomField1 );
      textHandle = MemHandleNew( len + 1 );
      if( textHandle == NULL ) { /* deal with out of memory case */
		  FrmAlert( bad ); 
		  break;
      }
      StrCopy( MemHandleLock( textHandle ), CustomField1 );
      MemHandleUnlock( textHandle );
      FldSetText( field, textHandle, 0, len + 1 );      

      /* field 1 */
      field = FrmGetObjectPtr(form, FrmGetObjectIndex( form, idCustomFieldField2 ) );
      len = StrLen( CustomField2 );
      textHandle = MemHandleNew( len + 1 );
      if( textHandle == NULL ) { /* deal with out of memory case */
		  FrmAlert( bad ); 
		  break;
      }
      StrCopy( MemHandleLock( textHandle ), CustomField2 );
      MemHandleUnlock( textHandle );
      FldSetText( field, textHandle, 0, len + 1);

      /* display style */
      lst = FrmGetObjectPtr( form, FrmGetObjectIndex( form, idCustomPopupList ));
      LstSetSelection( lst, DisplayStyle );
      ctl = FrmGetObjectPtr( form, FrmGetObjectIndex( form, idCustomPopupTrigger ));
      CtlSetLabel( ctl, LstGetSelectionText( lst, DisplayStyle ));

      /* write-protect state of this database */
      ctl = FrmGetObjectPtr( form, FrmGetObjectIndex( form, idCustomCheckWritePro ));
      CtlSetValue(ctl, WriteProtect );
      
      /* backup-bit state */
      DmOpenDatabaseInfo( CurrentDB, &dbID, NULL, NULL, &cardNo, NULL );
      DmDatabaseInfo( cardNo, dbID, NULL, &dbAttr, NULL, NULL, NULL, NULL,
		      NULL, NULL, NULL, NULL, NULL );
      ctl = FrmGetObjectPtr( form, FrmGetObjectIndex( form, idCustomCheckBackup ));      
      CtlSetValue(ctl, (dbAttr & dmHdrAttrBackup));

      /* set the state of the automate check box to reflect the applications preferences */
      PrefGetAppPreferencesV10( ListType, ListVersion, &preferences, sizeof(ListPreferences));
      ctl = FrmGetObjectPtr( form, FrmGetObjectIndex( form, idCustomCheckAutomate ));      
      CtlSetValue(ctl, preferences.automateBackup );

      /* set the state of the select check box to reflect the applications preferences */
      ctl = FrmGetObjectPtr( form, FrmGetObjectIndex( form, idCustomCheckSelect ));      
      CtlSetValue(ctl, preferences.selectDatabaseOnStartup );

      FrmDrawForm( form );
      handled = true;
      break;

    case appStopEvent:
      /* We are switching to a new application, clean up */
      CustomFormClose();
      /* do not set handled, let system clean up */
      break;
    }
  CALLBACK_EPILOGUE; /* Work around PilotGCC 0.5.0 bug */
  return( handled );
}

/* Used to save away the information stored in the customize form
   We should probablay build some more helpers here too to save 
   memory. 
   Return an error code.
 */
int CustomFormClose()
{
  FormPtr form;
  FieldPtr field;
  ListPtr list;
  Word len;
  VoidHand textHandle;
  Char *text;
  LocalID dbID;
  UInt cardNo; 
  UInt dbAttr;
  LocalID appInfoID;
  ListAppInfoType *appInfo;
  Boolean resort = false;
  ListPreferences preferences;
  ControlPtr ctl;
  int result = 0;
  Byte displayStyle;
  Byte writeProtect;
  char newDBName[dmDBNameLength];
  Boolean nameEqual;

  /* Get the list name */
  form = FrmGetActiveForm();
  field = FrmGetObjectPtr(form, FrmGetObjectIndex( form, idCustomFieldListName ) );
  textHandle = (VoidHand)FldGetTextHandle( field );
  text = MemHandleLock( textHandle );
  StrCopy( newDBName, text );
  MemHandleUnlock( textHandle );
  /* Strip off any trailing spaces */
  len = StrLen( newDBName );
  while ((len != 0) && (newDBName[len-1] == ' ')) {
    newDBName[len-1] = '\0';
    len--;
  }
  if( len == 0 ) {
    result = idNameEmptyError;
  } else {
    /* Verify that the new name is not already in use by another database. */
	nameEqual = (StrCompare( ListDBName, newDBName ) == 0);
	if( !nameEqual && (DmFindDatabase( 0 /* Card no? */, newDBName ) != 0)) {
      /* Another database of this name exists -- warn the user that the name will not change */
      result = idNameConflict;
    } else {
      StrCopy( ListDBName, newDBName );
    }
  }

  /* field 1 */
  field = FrmGetObjectPtr(form, FrmGetObjectIndex( form, idCustomFieldField1 ) );
  textHandle = (VoidHand)FldGetTextHandle( field );
  text = MemHandleLock( textHandle );
  len = StrLen( text );
  MemMove( CustomField1, text, len + 1 );
  MemHandleUnlock( textHandle );

  /* field 2 */
  field = FrmGetObjectPtr(form, FrmGetObjectIndex( form, idCustomFieldField2 ) );
  textHandle = (VoidHand)FldGetTextHandle( field );
  text = MemHandleLock( textHandle );
  len = StrLen( text );
  MemMove( CustomField2, text, len + 1 );
  MemHandleUnlock( textHandle );

  /* write-protect */
  ctl = FrmGetObjectPtr( form, FrmGetObjectIndex( form, idCustomCheckWritePro ));
  WriteProtect = CtlGetValue(ctl);

  /* display style */
  list = FrmGetObjectPtr(form, FrmGetObjectIndex( form, idCustomPopupList ) );
  len = LstGetSelection( list );
  if( len == -1 ) {
    DisplayStyle = 0;  /* default if something strange happened */
  } else {
    DisplayStyle = len;
  }
  
  /* now write the ListDBName to the database */
  DmOpenDatabaseInfo( CurrentDB, &dbID, NULL, NULL, &cardNo, NULL );

  /* While we're messing with the database info, update the backup bit to reflect
     the state of the checkbox */
  ctl = FrmGetObjectPtr( form, FrmGetObjectIndex( form, idCustomCheckBackup ));
  DmDatabaseInfo( cardNo, dbID, NULL, &dbAttr, NULL, NULL, NULL, NULL, 
		  NULL, &appInfoID, NULL, NULL, NULL );
  dbAttr &= !dmHdrAttrBackup;
  if( CtlGetValue(ctl) != 0 ) {
    dbAttr |= dmHdrAttrBackup;     /* the bit should be set */
  }
  
  /* PalmOS BUG? -- setting the dbName to the same value causes the call
     to fail?  This was making the attribute set fail as well, so we do
     the call twice (pre 3.5 OS comment)*/
  /* More bugs in the same area?! PalmOS 3.5 introduced a crash here so
	  we check in advance if the name is the same and do a different call? */
  if( nameEqual ) {
	  DmSetDatabaseInfo(cardNo, dbID, NULL, &dbAttr, NULL, NULL, NULL, NULL, 
						NULL, NULL, NULL, NULL, NULL);
	  } else {
	  DmSetDatabaseInfo(cardNo, dbID, ListDBName, &dbAttr, NULL, NULL, NULL, NULL, 
						NULL, NULL, NULL, NULL, NULL);
  }

  /* and update the fields in the ListAppInfoType structure */
  appInfo = MemLocalIDToLockedPtr( appInfoID, cardNo );
  if( appInfo->displayStyle != DisplayStyle ) {
    /* we want to re-sort the database */
    resort = true;
  }

  /* Bugfix: write just what changed -- Thanks to Christopher Antos: HandyShopper sources */  
  displayStyle = DisplayStyle;
  DmWrite( appInfo, ((ULong)&(appInfo->displayStyle) - (ULong)appInfo), &displayStyle, 1 );
  writeProtect = WriteProtect;
  DmWrite( appInfo, ((ULong)&(appInfo->writeProtect) - (ULong)appInfo), &writeProtect, 1 );
  DmWrite( appInfo, ((ULong)&(appInfo->customField1) - (ULong)appInfo), &CustomField1, CUSTOM_FIELD_SIZE );
  DmWrite( appInfo, ((ULong)&(appInfo->customField2) - (ULong)appInfo), &CustomField2, CUSTOM_FIELD_SIZE );

  MemPtrUnlock( appInfo );

  /* Resort if required */
  if( resort ) {
    RectangleType box = { 20, 60, 120, 40 };
    WinDrawRectangle( &box, 4 );
    FntSetFont( boldFont );
    WinEraseChars( "Please Wait..", 13, 48, 74 );

    DmQuickSort( CurrentDB, (DmComparF *)&ListCompareRecords, DisplayStyle );
  }

  /* Determine the state of the checkbox and set the application preferences to
     reflect it for the automate and select checkboxes. */
  PrefGetAppPreferencesV10( ListType, ListVersion, &preferences, sizeof(ListPreferences));
  
  ctl = FrmGetObjectPtr( form, FrmGetObjectIndex( form, idCustomCheckAutomate ));
  preferences.automateBackup = CtlGetValue(ctl);

  ctl = FrmGetObjectPtr( form, FrmGetObjectIndex( form, idCustomCheckSelect ));
  preferences.selectDatabaseOnStartup = CtlGetValue(ctl);

  PrefSetAppPreferencesV10( ListType, ListVersion, &preferences, sizeof( ListPreferences ));

  return( result );
}

/* 
 * record1 < record2   return -1  
 * record1 == record2  return 0
 * record1 > record2   return 1
 */
Int ListCompareRecords( ListDBHeader *record1, ListDBHeader *record2, Int style )
{
  Int result;

  if( style == 0 ) {
    /* Style 0 means field 1 is most significant */
    if( record1->field1 != 0 ) {
      if( record2->field1 != 0 ) {
	result = StrCompare( (CharPtr)record1 + record1->field1, (CharPtr)record2 + record2->field1 ); 
	/* Use field2 if result == 0 */
	if( result == 0 ) {
	  result = StrCompare( (CharPtr)record1 + record1->field2, (CharPtr)record2 + record2->field2 ); 
	}
	return( result );
      } else {
	return( 1 );
      }
    } else {
      /* the only way they can be equal is if record2->field1 is also zero */
      if( record2->field1 == 0 ) {
	return( 0 );
      } else {
	return( -1 );
      }
    }
  }
  
  /* Style 1 means field 2 is most significant */
  if( record1->field2 != 0 ) {
    if( record2->field2 != 0 ) {
      result = StrCompare( (CharPtr)record1 + record1->field2, (CharPtr)record2 + record2->field2 ); 
      /* Use field1 if result == 0 */
      if( result == 0 ) {
	result = StrCompare( (CharPtr)record1 + record1->field1, (CharPtr)record2 + record2->field1 ); 
      }
      return( result );
    } else {
      return( 1 );
    }
  } else {
    /* the only way they can be equal is if record2->field2 is also zero */
    if( record2->field2 == 0 ) {
      return( 0 );
    } else {
      return( -1 );
    }
  }
}







