/*****************************************************************************/
/*                           Jean-Eloi Dussartre                             */
/*                          M.I.T. Project Athena.                           */
/*                              January 1990.                                */
/*                   The Spreadsheet Widget implementation.                  */
/*                     The AtTable Object implementation.                    */
/*****************************************************************************/

/*
 * This file is both a test and a demonstration program for the Spreadsheet
 * widget and the AtTable object.
 */

#include <stdio.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <X11/StringDefs.h>
#include <Xm/Text.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/ScrollBar.h>
#include <Xm/PushB.h>
#include <Xt/Shell.h>

#include "Spreadsheet.h"
#include "Table.h"

#include <stdio.h>
#include <string.h>



/* General purpose macro */

#define STRINGIFY__(X)   #X
#define STRINGIFY(X)     STRINGIFY__(X)

/* Some hard coded limitation...*/
#define BUF_MAX   128


/* Sign up for error messages */

char *prgname = NULL;
char *filename = NULL;

/* The widgets */

 struct ApplicationData {
				AtTableObject t;  /* The Table object        */
   				Widget	toplevel, /* shell widget            */
					ssw,	  /* ssw : SpreadSheetWidget */
					buw,	  /* A button widget         */
					edw,	  /* edw : Text Editor       */
					fow,	  /* Form Widget             */
					clw,	  /* Cursor Label widget     */
					flw,	  /* Filename Label widget   */
					shw,	  /* scroll bar horizontal   */
					svw;	  /* scroll bar vertical     */
			       };

void usage (char *msg, char *arg)

{
    fprintf (stderr, "\n%s : %s %s.\n", prgname, msg, arg);
    fprintf (stderr, "Usage is : %s [-row] [-column] -C# -R# [-f<filename>]\n",
	              prgname);
    _exit(1);
  }

/* Parse file */
#ifdef notdef
void parsefile (FILE *f, AtTable t, Boolean byrow)
{
  int irow = 0;
  int icol = 0;
  int nrow = AtTableGetRowNum(t);
  int ncol = AtTableGetColumnNum(t);
  char buffer [BUF_MAX];

  while (fgets(buffer, BUF_MAX, f)
	 && (irow < nrow)
	 && (icol < ncol))
    {    /* Fix the bug in fgets : the last char can be \n */
      if (buffer [strlen(buffer) - 1] == '\n')
	buffer [strlen(buffer) - 1] = '\0';
      /* Now I insert in the table */
      if (! AtTableSetCell(t, irow, icol, buffer))
	{
	  fprintf (stderr, "%s : Error inserting cell %d %d\n", prgname,
		   irow, icol);
	  _exit(1);
	}

      if (byrow)
	{
	  if (++irow == nrow)
	    irow = 0; icol++;
	}
      else
	if (++icol == ncol)
	  icol = 0; irow++;
    }
}


void trapnotification(void         *id,
		      AtTable      t,
		      AtTableEvent e,
		      int trow, int lcol,
		      int brow, int rcol)

{
	/* Trap size notification : to update the scroll bar widget */
  
        
}

AtTable LoadTable (int argc, char **argv)

{  int argidx;
   int nrow = 0;
   int ncol = 0;
   Boolean byrow = TRUE;
   FILE *f = stdin;
   AtTable t;

   prgname = argv [0];

   for (argidx = 1; (argidx < argc); argidx++)
     {
       switch (*(argv [argidx]))
	 {
	 case '-' :
	   switch (argv [argidx][1])
	     {
             case 'r' :
	       if (strcmp(argv [argidx] + 1, "row"))
		 usage ("Invalid option", argv [argidx] + 1);
	       else
		 byrow = TRUE;
               continue;

             case 'c' :
	       if (strcmp(argv [argidx] + 1, "column"))
		 usage ("Invalid option", argv [argidx] + 1);
	       else
		 byrow = FALSE;
	       continue;

	     case 'R' :
               if (!(sscanf(argv [argidx] + 2, "%d", &nrow)))
		 usage ("Invalid number of row", argv [argidx + 2]);
	       continue;

	     case 'C' :
	       if (!(sscanf(argv [argidx] + 2, "%d", &ncol)))
		 usage ("Invalid number of column", argv [argidx + 2]);
	       continue;

	     case 'f' :
	       if (!(f = fopen(filename = argv [argidx] + 2, "r")))
		   usage("Unable to open file", argv [argidx] + 2);
	       continue;

	     default :
	       usage("Unkwon option", argv [argidx] );
	       continue;
	     };

	   default :
	       usage("Unkwon option", argv [argidx] );
           };
     };

   if (!(t = AtTableCreate(nrow, ncol)))
	usage ("Unable to create table", "");
/* DEMONSTRATION FOR EVENT DRIVEN.
 *   AtTableSubscribe(t, AtTableEventRangeSet, (void *)NULL, trapnotification);
 */
   parsefile(f, t, byrow);

   fclose(f);
   return(t);
 }

/*
 * Callback implementation
 */

void trapCursorMovement (Widget w, caddr_t client_data, caddr_t call_data)

{
  AtSpreadsheetLocation *cursorL = (AtSpreadsheetLocation *)call_data;

  XmTextSetString((Widget)client_data, 
		  AtTableGetCell(cursorL->table,
				 cursorL->row,
				 cursorL->column));
}


/*
 * Trap modification on the buffer in the editor.
 */

void trapEditValidation (Widget w, caddr_t client_data, caddr_t call_data)

{
  

 /* Check if buffer has been really changed */
 /*========= How do I do that ? ======*/
 /* Update the table */

 AtTableSetCell(AtSpreadsheetGetTable((AtSpreadsheetWidget)client_data),
		AtSpreadsheetGetCursorRow((AtSpreadsheetWidget)client_data),
		AtSpreadsheetGetCursorColumn((AtSpreadsheetWidget)client_data),
		XmTextGetString(w));
}

void trapButtonPress (Widget w, caddr_t client_data, caddr_t call_data)

{
  Widget toplevel;
  Arg wargs [5];

  toplevel = XtAppCreateShell(prgname,
			      "Xcell",
			      topLevelShellWidgetClass,
			      XtDisplay((Widget)client_data),
			      NULL,
			      0);
  
   XtSetArg(wargs [0],
	    XtNtable,
	    (XtArgVal)AtSpreadsheetGetTable((AtSpreadsheetWidget)client_data));
 
   XtCreateManagedWidget("table",
			 atSpreadsheetWidgetClass,
			 toplevel,
			 wargs,
			 1);
   XtRealizeWidget(toplevel);
  
}

void trapScroll (AtSpreadsheetWidget s, Widget w, AtSpreadsheetScroll *Scrl)

{
  XmScrollBarSetValues(w,
		       (int)Scrl->lowIndex,
		       (int)(Scrl->highIndex - Scrl->lowIndex),
		       1,
		       (int)(Scrl->highIndex - Scrl->lowIndex + 1),
		       False);
}


void trapScrollV (Widget w, caddr_t client_data, caddr_t call_data)

{
  AtSpreadsheetScroll* ScrollPtr = (AtSpreadsheetScroll *)ScrollPtr;

  if (ScrollPtr->vertical)
    trapScroll((AtSpreadsheetWidget)w, (Widget)client_data, ScrollPtr);

}

void trapScrollH (Widget w, caddr_t client_data, caddr_t call_data)

{
  AtSpreadsheetScroll* ScrollPtr = (AtSpreadsheetScroll *)ScrollPtr;

  if (!(ScrollPtr->vertical))
    trapScroll((AtSpreadsheetWidget)w, (Widget)client_data, ScrollPtr);
}

/*==== To be added
  ==== Callback trapping for XmNpageIncrement, XmNtoBottomCallback,
  ==== XmNtoTopCallback,...
  ====*/

#endif
void main (int argc, char **argv)
{
  Arg wargs [10];
  struct ApplicationData app;
  AtTableObject t;
  int width, height;
  int i,j;
  char buf[30];

  /*
   * Create the top level widget.
   */
  app.toplevel = XtInitialize(argv [0], "Xcell", NULL, 0, &argc, argv);
  
  /*
   * Create the table object.
   */
  t = (AtTableObject) XtCreateWidget("table", atTableObjectClass,
				     app.toplevel, NULL, 0);
  AtTableGetSize(t, &width, &height);
  for(i=0; i<width; i++)
    {
      for (j=0; j<height; j++)
	{
	  sprintf(buf, "%d", i*j);
	  AtTableSetCellValue(t, i, j, buf);
	}
    }

  /*
   * Create the Spreadsheet widget.
   */
  XtSetArg(wargs [0], XtNtable, (XtArgVal)t);
  app.ssw = XtCreateManagedWidget("spreadsheet",
				  atSpreadsheetWidgetClass,
				  app.toplevel,
				  wargs,
				  1);
  /*
   * Let's Go
   */
  XtRealizeWidget(app.toplevel);

  XtMainLoop();
}




