/*-----------------------------------------------------------------------
                           X Y T A B L E

 a helper class which implements a XY-table of values.

 Mark Koennecke, June 1999
 ---------------------------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <tcl.h>
#include "fortify.h"
#include "sics.h"
#include "lld.h"
#include "xytable.i"
#include "xytable.h"

/*-------------------------------------------------------------------------*/
  static void KillXY(void *pData)
  {
      pXYTable self = NULL;

      self = (pXYTable)pData;
      if(!self)
          return;

      if(self->pDes)
      {
         DeleteDescriptor(self->pDes);
      } 
      LLDdelete(self->iList);

      free(self);
  }
/*------------------------------------------------------------------------*/
  int XYFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
                int argc, char *argv[])
  {
       pXYTable pNew = NULL;
       int iRet;
       char pBueffel[512];

       /* I want a name as argument */
       if(argc < 2)
       {
           SCWrite(pCon,"ERROR: need a name for the XYTable",eError);
           return 0;
       }

       /* mallocate memory */
       pNew = (pXYTable)malloc(sizeof(XYTable));
       if(!pNew)
       {
          SCWrite(pCon,"ERROR: out of memory in function XYFactory",
                  eError);
          return 0;    
       }      
       memset(pNew,0,sizeof(XYTable));
       pNew->pDes = CreateDescriptor("XYTable");
  
       pNew->iList = LLDcreate(sizeof(TableEntry));

       if( (pNew->iList < 0) || (pNew->pDes == NULL) )
       {
          SCWrite(pCon,"ERROR: out of memory in function XYFactory",
                  eError);
          return 0;    
       }
     
       iRet = AddCommand(pSics,
                         argv[1],
                         XYAction, 
                         KillXY,
                         pNew);
       if(!iRet)
       {
           sprintf(pBueffel,"ERROR: duplicate command %s not created",
                   argv[1]);
           SCWrite(pCon,pBueffel,eError);
           return 0;
       }
       return 1;
  }
/*-----------------------------------------------------------------------*/
  int XYClear(pXYTable self)
  {
     assert(self);

      LLDdelete(self->iList);
      self->iList = LLDcreate(sizeof(TableEntry));
      self->iCount = 0;
      if(self->iList > 0)
      {
        return 1;
      }
      else
      {
         return 0;
      }
  }
/*----------------------------------------------------------------------*/
  int XYAdd(pXYTable self, float x, float y)
  {
     TableEntry te;

     assert(self);

     te.x = x;
     te.y = y;
     LLDnodeAppendFrom(self->iList,&te);
     self->iCount++;
     return 1;
  } 
 extern void SNXFormatTime(char *pBueffel, int ilen);
/*----------------------------------------------------------------------*/
  int XYWrite(pXYTable self, FILE *fd)
  {
     char pBueffel[132];
     TableEntry pData;
     int iRet;
   
     assert(self);
     assert(fd);

     SNXFormatTime(pBueffel,131);
     fprintf(fd,"XYTable written at: %s\n",pBueffel);
     iRet = LLDnodePtr2First(self->iList);
     while(iRet != 0)
     {
        LLDnodeDataTo(self->iList,&pData);
        fprintf(fd," %12.4f  %12.4f\n",pData.x, pData.y);
        iRet = LLDnodePtr2Next(self->iList);
     }
     return 1;
  }
/*----------------------------------------------------------------------*/
  int XYList(pXYTable self, SConnection *pCon)
  {
     char pBueffel[132];
     char *pBuffer = NULL;
     TableEntry pData;
     int iRet;
   
     assert(self);
     assert(pCon);

     if(self->iCount < 1)
     {
         SCWrite(pCon,"WARNING: nothing to list",eWarning);
         return 1;
     }

     /* malloc space */
     pBuffer = (char *)malloc((self->iCount*30)*sizeof(char));
     if(!pBuffer)
     {
       SCWrite(pCon,"ERROR: out of memory in XYlist",eError);
       return 0;
     }
     memset(pBuffer,0,(self->iCount*30)*sizeof(char));

     iRet = LLDnodePtr2First(self->iList);
     while(iRet != 0)
     {
        LLDnodeDataTo(self->iList,&pData);
        sprintf(pBueffel," %12.4f  %12.4f\n",pData.x, pData.y);
        strcat(pBuffer,pBueffel);
        iRet = LLDnodePtr2Next(self->iList);
     }
     SCWrite(pCon,pBuffer,eValue);
     free(pBuffer);
     return 1;
  }
/*----------------------------------------------------------------------*/
  int XYSendUU(pXYTable self, SConnection *pCon)
  {
     int *iData = NULL;
     int iRet, i, i2;
     TableEntry pData;

     assert(self);
     iData = (int *)malloc((self->iCount*2+1)*sizeof(int));
     if(!iData)
     {
       SCWrite(pCon,"ERROR: out of memory in XYSendUU",eError);
       return 0;
     }
     iData[0] = htonl(self->iCount);
     i = 1;
     i2 = self->iCount + 1;
     iRet = LLDnodePtr2First(self->iList);
     while(iRet != 0)
     {
       LLDnodeDataTo(self->iList,&pData);
       iData[i] = htonl((int)(pData.x*65536));
       iData[i2] = htonl((int)(pData.y*65536));
       i++;
       i2++;
       iRet = LLDnodePtr2Next(self->iList);
     }
     SCWriteUUencoded(pCon,"XYTable",iData,
                        (self->iCount*2 + 1)*sizeof(int));
     free(iData);
     return 1;
  }
/*-----------------------------------------------------------------------*/
  int XYAction(SConnection *pCon, SicsInterp *pSics, void *pData,
                int argc, char *argv[])
  {
     pXYTable self = NULL;
     char pBueffel[512];
     float fX, fY;
     double dVal;
     FILE *fd = NULL;
     int iRet;

     self = (pXYTable)pData;
     assert(self);
     assert(pCon);
     assert(pSics);

     if(argc < 2)
     {
        sprintf(pBueffel,"ERROR: need command word for %s",argv[0]);
        SCWrite(pCon,pBueffel,eError);
        return 0;
     }

     strtolower(argv[1]);
     if(strcmp(argv[1],"clear") == 0)
     {
        if(!SCMatchRights(pCon,usUser))
	{
          return 0;
        }
        XYClear(self);
        SCSendOK(pCon);
        return 1;        
     }
     else if(strcmp(argv[1],"add") == 0)
     {
        if(!SCMatchRights(pCon,usUser))
	{
          return 0;
        }
        if(argc < 4)
	{
          sprintf(pBueffel,"ERROR: insufficient no of args to %s add",argv[0]);
          SCWrite(pCon,pBueffel,eError);
          return 0;
        }
        iRet = Tcl_GetDouble(pSics->pTcl, argv[2],&dVal);
        if(iRet != TCL_OK)
	{
         sprintf(pBueffel,"ERROR: failed to conert %s to number",argv[2]);
         SCWrite(pCon,pBueffel,eError);
         return 0;
        }
        fX = (float)dVal;
        iRet = Tcl_GetDouble(pSics->pTcl, argv[3],&dVal);
        if(iRet != TCL_OK)
	{
         sprintf(pBueffel,"ERROR: failed to conert %s to number",argv[3]);
         SCWrite(pCon,pBueffel,eError);
         return 0;
        }
        fY = (float)dVal;
        XYAdd(self,fX,fY);
        SCSendOK(pCon);
        return 1;
     }
     else if(strcmp(argv[1],"write") == 0)
     {
        if(!SCMatchRights(pCon,usUser))
	{
          return 0;
        }
        if(argc < 3)
	{
          sprintf(pBueffel,"ERROR: insufficient no of args to %s write",
                  argv[0]);
          SCWrite(pCon,pBueffel,eError);
          return 0;
        }
        fd = fopen(argv[2],"w");
        if(fd == NULL)
	{
           sprintf(pBueffel,"ERROR: failed to open %s for writing",
                   argv[2]);
           SCWrite(pCon,pBueffel,eError);
           return 0;
        }        
        XYWrite(self,fd);
        fclose(fd);
        SCSendOK(pCon);
        return 1;
     }
     else if(strcmp(argv[1],"uuget") == 0)
     {
       XYSendUU(self,pCon);
       return 1;
     }
     else if(strcmp(argv[1],"list") == 0)
     {
       XYList(self,pCon);
       return 1;
     }
     sprintf(pBueffel,"ERROR: subcommand %s to %s unknonw",
             argv[1], argv[0]);
     SCWrite(pCon,pBueffel,eError);
     return 0;
  }

