/* view.c contains the viewing related code
 */

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


Boolean ViewFormEventHandler(EventPtr event)
{
  Boolean handled = false;
  FormPtr form;
  ControlPtr ctl;
  Word length;
  Word x, y;
  RectangleType rect = { 0, 16, 160, 128 }; /* Fudged? */
  Boolean penDown;
  UInt attr;
  Word category;
  CALLBACK_PROLOGUE;   /* Work around PilotGCC 0.5.0 bug */

  switch( event->eType )
    {
    case ctlSelectEvent:
      if( event->data.ctlSelect.controlID == idViewDoneButton ) {
	FrmGotoForm( idMainForm );
	handled = true;
      }
      if( event->data.ctlSelect.controlID == idViewEditButton ) {
	if( WriteProtect ) {
	  FrmAlert( idWriteProtect );
	  FrmGotoForm( idMainForm );
	} else {
	  FrmGotoForm( idEditForm );
	}
	handled = true;
      }
      break;

      case ctlRepeatEvent:
      case keyDownEvent: 

	if( ChrIsHardKey( event->data.keyDown.chr ) ) {
  	  FrmGotoForm( idMainForm );
	  handled = true;
	  break;
	} 
	form = FrmGetActiveForm();
	if( (event->data.keyDown.chr == pageUpChr) || 
	    (event->data.ctlRepeat.controlID == idViewUpButton) ) {
	    /* Scroll Up: backup one page */
	  ctl = FrmGetObjectPtr( form, FrmGetObjectIndex( form, idViewUpButton ));
	  if( ctl->attr.visible && CtlEnabled( ctl ) ) {
	    ViewPage--;
	  } else {
	    /* We are at the top of the record, is there a previous record?
	       If so, beep and change to viewing that record */
	    if(!DmSeekRecordInCategory( CurrentDB, &CurrentRecord, 1, dmSeekBackward, CurrentCategory )) {
	      /* yes there is, play sound, move to new record */
	      SndPlaySystemSound( sndInfo );
	      WinEraseWindow();
	      goto viewRecord;
	    } 
	  }
	}
	if( (event->data.keyDown.chr == pageDownChr) || 
	    (event->data.ctlRepeat.controlID == idViewDownButton) ) {
	  /* Scroll Down: move forward one page */
	  ctl = FrmGetObjectPtr( form, FrmGetObjectIndex( form, idViewDownButton ));
	  if( ctl->attr.visible && CtlEnabled( ctl ) ) {
	    ViewPage++;
	  } else {
	    /* We are at the bottom of the record, is there another record?
	       If so, beep and change to viewing that record */
	    if(!DmSeekRecordInCategory( CurrentDB, &CurrentRecord, 1, dmSeekForward, CurrentCategory )) {
	      /* yes there is, play sound, move to new record */
	      SndPlaySystemSound( sndInfo );
	      WinEraseWindow();
	      goto viewRecord;
	    }
	  }
	}
	if( ctl->attr.visible && CtlEnabled( ctl ) ) { 
	  WinEraseRectangle( &rect, 0 );
	  ViewDrawRecord();
	}
	break;


    case frmOpenEvent:
    case frmGotoEvent:

    viewRecord:

      ViewPage = 0; /* Initialize the view page */
      form = FrmGetActiveForm();

      {
		  UInt current, total;

		  current = DmPositionInCategory( CurrentDB, CurrentRecord, CurrentCategory ) + 1;
		  total = DmNumRecordsInCategory( CurrentDB, CurrentCategory );
		  
		  SysCopyStringResource( ViewTitle, idStringView );
		  StrIToA( &ViewTitle[StrLen( ViewTitle )], current );
		  SysCopyStringResource( &ViewTitle[StrLen( ViewTitle)], idStringOf );
		  StrIToA( &ViewTitle[StrLen( ViewTitle )], total );
	  }
      
      FrmSetTitle( form, ViewTitle );
      FrmDrawForm( form );

      DmRecordInfo( CurrentDB, CurrentRecord, &attr, NULL, NULL );
      category = attr & dmRecAttrCategoryMask;
      CategoryGetName( CurrentDB, category, CategoryName );

      FntSetFont( stdFont );
      length = StrLen( CategoryName );
      x = 158 - FntCharsWidth( CategoryName, length );
      WinDrawChars( CategoryName, length, x, 1 );

      ViewDrawRecord();

      handled = true;
      break;

    case penDownEvent:
      /* Make it feel like the address book and allow editing when they tap on the screen */
      if (RctPtInRectangle (event->screenX, event->screenY, &rect)) {
	do 
	  {
	    PenGetPoint (&x, &y, &penDown);
	  } while (penDown);
	  
	  if (RctPtInRectangle( x, y, &rect )) {
	    if( !WriteProtect ) {
	      FrmGotoForm( idEditForm ); 
	    }
	  }
	  handled = true;
	}
      break;
    }

  CALLBACK_EPILOGUE; /* Work around PilotGCC 0.5.0 bug */
  return( handled );
}

/* Draw the record showing the current page of information */

void ViewDrawRecord()
{
  VoidHand recordHandle;
  ListDBHeader *record;
  CharPtr string;
  Word y;
  FormPtr form;
  Word upIndex, downIndex;
  Boolean scrollUp, scrollDown;
  Word skip;

  recordHandle = DmQueryRecord( CurrentDB, CurrentRecord );
  record = MemHandleLock( recordHandle );

  /* There is an assumption that the two first fields will always fit on
     the first page ROOHACK */
  y = 16;
  if( record->field1 != 0) {
    string = (CharPtr)record + record->field1;
    FntSetFont( largeFont );
    /* Simply discard any remaining field1 information if it doesn't fit */
    ViewDrawChars( string, &y, 100, (ViewPage == 0) ); 
  }
  
  FntSetFont( stdFont );
  if( record->field2 != 0) {
    string = (CharPtr)record + record->field2;
    /* Simply discard any remaining field2 information if it doesn't fit */
    ViewDrawChars( string, &y, 120, (ViewPage == 0) );
    y += 6; /* ROOHACK: fudge factor */
  }
  /* By using the 100 and 120 values, we have ensured there is at least room for
     one line of the note.  */

  scrollDown = false;  

  if( record->note != 0) {
    string = (CharPtr)record + record->note;
    
    if( ViewPage != 0 ) {
      /* Skip one or more pages */

      string = (CharPtr)record + record->note;
      for(skip=0; skip < ViewPage; skip++) {
	string = ViewDrawChars( string, &y, 128, false );
	/*       if( string == NULL ) break; ROOHACK -- might need a safety break out? */
	y = 16;
      }
    }
    
    if( ViewDrawChars( string, &y, 128, true ) != NULL ) {
      /* There was more to draw */
      scrollDown = true;
    }
  }
  
  MemHandleUnlock( recordHandle );

  /* update the up/down buttons so they reflect what is possible */
  scrollUp = !(ViewPage == 0);
  form = FrmGetActiveForm();
  upIndex = FrmGetObjectIndex( form, idViewUpButton );
  downIndex = FrmGetObjectIndex( form, idViewDownButton );
  FrmUpdateScrollers( form, upIndex, downIndex, scrollUp, scrollDown );   
  
}

/* Start drawing the string at the y offset, if the edge of the screen
   is reached, wrap to the next line.  Modify the y position value passed
   in to reflect where the next y position is.  Return a pointer to the
   remaining text if we ran out of room on the page, otherwise return
   NULL.  By setting the boolean draw flag to false this routine can
   be used to skip pages. */

CharPtr ViewDrawChars(CharPtr string, Word *y, Word maxY, Boolean draw)
{
  CharPtr text;
  Int length;
  Int width;
  Int truncate;
  Int end;
  Boolean truncated;

  text = string;
  do {
	  length = end = StrLen( text );
	  width = 160;
	  /* Get the OS to tell us how many characters will fit */
	  FntCharsInWidth( text, &width, &length, &truncated );
	  /* truncated is used only if CR caused the end but it may not be in position
	  text[length] if it was preceeded by spaces*/
	  
	  /* If we're not using all the text, and its not followed by whitespace,
	  then try to word wrap it */
	  if(( length != end) &&( text[length] != '\n') && ( text[length] != ' ')) { 
		  truncate = length;
		  while( (length > 0)  && (text[length] != ' ') ) {
			  length --;
		  }
		  /* No spaces at all? -- Just hard wrap it */ 
		  if( length == 0 ) {
			  length = truncate;
		  }
	  } 
	  /* display the text if we were asked to*/
	  if( draw ) {
		  WinDrawChars( text, length, 0, *y );
	  }
	  /* If the entire string was used text[length] is NULL or not whitespace and
	  routine will drop through, otherwise it skips one CR or all trailing
	  spaces to next word or past next CR */  
	  if (text[length]=='\n') {
		  length++;
	  } else {
		  while( ((text[length] == ' ') || (text[length]== '\t')) && (length != end)) {
			  if (text[++length] == '\n') {
				  length++;
				  break;
			  }
		  }
	  }
	  /* Set the new position in the string and on the screen and see if we're
	  finished with either*/
	  text += length;
	  *y += FntCharHeight();
  } while ( (length < end) && (*y < maxY) );
  
  /* Let the caller know where we are in the string if there is more*/
  if( length != end ) {
    return( text );
  }
  return( NULL );
}

