/*------------------------------------------------------------------------
              C h o p p e r C o n t r o l l e r

 Implementation file for the SICS chopper controller and general controller
 device. For details about this object and its relation with the SICS system 
 see choco.w or choco.tex.

 Mark Koennecke, January 1998
-------------------------------------------------------------------------*/
#include <stdlib.h>
#include <tcl.h>
#include <assert.h>
#include "fortify.h"
#include "sics.h"
#define CHOCOINTERNAL
#include "choco.h"


 
/*------------------------------------------------------------------------*/
  int CHGetParameter(pChoco self, char *parname, char *pParValue,
                     int iBuflen)
  {
      int iRet, iCode;

      assert(self);

      iRet = self->pDriv->GetPar(self->pDriv, parname, pParValue,
                                 iBuflen);
      if(!iRet)
      {
         iRet = 0;
         self->pDriv->GetError(self->pDriv,&iCode,pParValue, iBuflen); 
      }
      return iRet;
  }
/*------------------------------------------------------------------------*/
  pCodri CHGetDriver(pChoco self)
  {
     assert(self);
 
     return self->pDriv;
  }
/*------------------------------------------------------------------------*/
  int CHList(pChoco self, SConnection *pCon, char *name)
  {
     char *pPar, *pCopy = NULL;
     char pValue[80];
     char pMessage[256];
     int iRet, iLen;
     Tcl_DString  tlist;   

     assert(self);

    /* copy pParList as it will be destroyed by strtok */
    iLen = strlen(self->pDriv->pParList);
    pCopy = (char *)malloc((iLen+10)*sizeof(char));
    if(!pCopy)
    {
      SCWrite(pCon,"ERROR: out of memory in CHList",eError);
      return 0;
    }
    memset(pCopy,0,iLen+10);
    strcpy(pCopy,self->pDriv->pParList);
    Tcl_DStringInit(&tlist);

     pPar = strtok(pCopy,",");
     while(pPar != NULL)
     {
        iRet = CHGetParameter(self,pPar,pValue,79);
        if(iRet)
	{
          sprintf(pMessage,"%s.%s = %s \n",name,pPar,pValue);
        }
        else
	{
          sprintf(pMessage,"ERROR: %s : while reading parameter %s \n",
                  pValue,pPar);
	}  
        Tcl_DStringAppend(&tlist, pMessage,-1);
        pPar = strtok(NULL,",");
     }
     SCWrite(pCon,Tcl_DStringValue(&tlist),eValue);
     Tcl_DStringFree(&tlist);
     free(pCopy);
     return 1;
  }
/*-----------------------------------------------------------------------*/
  int ChocoAction(SConnection *pCon, SicsInterp *pSics, void *pData,
                  int argc, char *argv[])
  {
     pChoco self = NULL;
     char pValue[80], pMessage[256];
     int iRet;

     self = (pChoco)pData;
     assert(self);

     if(argc < 2)
     {
       sprintf(pMessage, "ERROR: Ragument required for %s",argv[0]);
       SCWrite(pCon,pMessage,eError);
       return 0;
     }

     /* argument can either be list or parameter name */
     strtolower(argv[1]);
     if(strcmp(argv[1],"list") == 0)
     {
	return CHList(self,pCon,argv[0]);
     }
     else
     {
        if(argc > 2)
	{
 	  /* set case */
          iRet = self->pDriv->SetPar2(self->pDriv,argv[1],argv[2]);
          if(!iRet)
	  {
            self->pDriv->GetError(self->pDriv,&iRet,pValue,79);
            sprintf(pMessage,"ERROR: %s",pValue);
            SCWrite(pCon,pMessage,eError);
            return 0;
          }         
          else
	  {
             SCSendOK(pCon);
             return 1;
          }
        }
        else
	{
	  /* get case */
	   iRet = CHGetParameter(self,argv[1],pValue,79);
           if(iRet)
	   {
              sprintf(pMessage,"%s.%s = %s",argv[0],argv[1],pValue);
           }
           else
	   {
                sprintf(pMessage,"ERROR: %s : while reading parameter %s",
                  pValue,argv[1]);
	   }  
           SCWrite(pCon,pMessage,eValue);
           return iRet;
        }
     }
     return 0;
  }
/*----------------------------------------------------------------------*/
  static void KillChoco(void *pData)
  {
     pChoco self = NULL;

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

     if(self->pDriv)
     {
       self->pDriv->Close(self->pDriv);
       self->pDriv->Delete(self->pDriv);
       if(self->pDriv->pParList)
             free(self->pDriv->pParList);
       free(self->pDriv);
     }
     if(self->pDes)
        DeleteDescriptor(self->pDes);

     free(self);
  }
/*-----------------------------------------------------------------------
      DRIVERS
*/

extern pCodri MakeSimChopper(void);
extern pCodri MakeDoChoDriver(char *pHost, int iPort, int iChannel);
extern pCodri MakeCookerDriver(char *pHost, int iPort, int iChannel);
/*-----------------------------------------------------------------------*/
  int ChocoFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
                  int argc, char *argv[])
  {
      pChoco pNew = NULL;
      pCodri pDriv = NULL;
      pObjectDescriptor pDes = NULL;
      char pBueffel[132];
      int iRet, iPort, iChannel;

      if(argc < 3)
      {
         SCWrite(pCon,
            "ERROR: Insufficient number of arguments to MakeController",
                 eError);
         return 0;
      }
	

      /* first try to get everything done */
      pNew = (pChoco)malloc(sizeof(Choco));
      pDes = CreateDescriptor("Chopper");
      /* do driver */
      strtolower(argv[2]);
      if(strcmp(argv[2],"sim") == 0)
      {
        pDriv = MakeSimChopper();
      }
      else if(strcmp(argv[2],"docho") == 0)
      {
         if(argc < 6)
	 {
           SCWrite(pCon,
  "ERROR: Insufficient number of arguments to install Dornier Chopper driver",
           eError);
           return 0;    
         }
         iRet = Tcl_GetInt(pSics->pTcl,argv[4],&iPort);
         if(iRet != TCL_OK)
	 {
           sprintf(pBueffel,"ERROR: expected integer as port number, got %s",
                   argv[4]);
           SCWrite(pCon,pBueffel,eError);
           return 0;
         }
         iRet = Tcl_GetInt(pSics->pTcl,argv[5],&iChannel);
         if(iRet != TCL_OK)
	 {
           sprintf(pBueffel,"ERROR: expected integer as channel number, got %s",
                   argv[4]);
           SCWrite(pCon,pBueffel,eError);
           return 0;
         }
         pDriv = MakeDoChoDriver(argv[3],iPort,iChannel);
      }
      else if(strcmp(argv[2],"sanscook") == 0)
      {
         if(argc < 6)
	 {
           SCWrite(pCon,
  "ERROR: Insufficient number of arguments to install SANS Cooker driver",
           eError);
           return 0;    
         }
         iRet = Tcl_GetInt(pSics->pTcl,argv[4],&iPort);
         if(iRet != TCL_OK)
	 {
           sprintf(pBueffel,"ERROR: expected integer as port number, got %s",
                   argv[4]);
           SCWrite(pCon,pBueffel,eError);
           return 0;
         }
         iRet = Tcl_GetInt(pSics->pTcl,argv[5],&iChannel);
         if(iRet != TCL_OK)
	 {
           sprintf(pBueffel,"ERROR: expected integer as channel number, got %s",
                   argv[4]);
           SCWrite(pCon,pBueffel,eError);
           return 0;
         }
         pDriv = MakeCookerDriver(argv[3],iPort,iChannel);
      }
      else
      {
        sprintf(pBueffel,"ERROR: Driver %s NOT supported for MakeController",
                argv[2]);
        SCWrite(pCon,pBueffel,eError);
        return 0;
      }
      if( (pNew == NULL) || (pDes == NULL) || (pDriv == NULL) )
      {
        SCWrite(pCon,"ERROR: No memory left to create controller",eError);
        return 0;
      }
      pNew->pDes = pDes;
      pNew->pDriv = pDriv;

      /* initialize driver */
      iRet = pDriv->Init(pDriv);
      if(!iRet)
      {
        SCWrite(pCon,"ERROR: Failed to initialize driver",eError);
        KillChoco(pNew);
        return 0;
      }

      /* install as command */
      iRet = AddCommand(pSics, argv[1],ChocoAction,KillChoco,pNew);
      if(!iRet)
      {
	sprintf(pBueffel,"ERROR: duplicate command %s NOT created",
		argv[1]);
	SCWrite(pCon,pBueffel,eError);
        return 0;
      }
      return 1;
  }


