/*--------------------------------------------------------------------------

	Just a Status management object. Not very exciting.
	

	Mark Koennecke,    November 1996
        added callback facilities and interst command. 
        Mark Koennecke, August 1997

	Copyright:

	Labor fuer Neutronenstreuung
	Paul Scherrer Institut
	CH-5423 Villigen-PSI


        The authors hereby grant permission to use, copy, modify, distribute,
        and license this software and its documentation for any purpose, provided
        that existing copyright notices are retained in all copies and that this
        notice is included verbatim in any distributions. No written agreement,
        license, or royalty fee is required for any of the authorized uses.
        Modifications to this software may be copyrighted by their authors
        and need not follow the licensing terms described here, provided that
        the new terms are clearly indicated on the first page of each file where
        they apply.

        IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
        FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
        ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
        DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
        POSSIBILITY OF SUCH DAMAGE.

        THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
        INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
        IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
        NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
        MODIFICATIONS.
-----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include "fortify.h"
#include <string.h>
#include "sics.h"
#include "status.h"
#include "interrupt.h"
#include "devexec.h"
#undef VALUECHANGE
#define VALUECHANGE 2

	static Status eCode = eEager;
	
        static char *pText[] = {
                "Eager to execute commands",
                "User requested Wait",
                "Counting",
                "No Beam",
                "Paused",
                "Driving",
                "Running",
                "Running a scan",
                "Writing data",
                "Processing a batch file", 
                "Halted",
                "Dead",
                "Waiting for User Input",
                NULL }; 

     static char *iText[] = {
                              "eager",
                              "userwait",
                              "count",
                              "nobeam",
                              "paused",
                              "driving",
                              "running",
                              "scanning",
			      "writing",
                              "batch",
                              "halt",
                              "dead",
                              "input",
                              NULL };
                              
    static pICallBack pCall = NULL;
    static int fixed = 0;
/*-------------------------------------------------------------------------*/
   void KillStatus(void *pData)
   {
     if(pCall != NULL)
     {
        DeleteCallBackInterface(pCall);
     }
   }                              
/*--------------------------------------------------------------------------*/
   void SetStatus(Status eNew)
   {
     if(!fixed)
     {
       if(eCode == eNew)
       {
	 return;
       }
       eCode = eNew;
       InvokeCallBack(pCall,VALUECHANGE,NULL);
     }
   }
/*----------------------------------------------------------------------*/
   void SetStatusFixed(Status eNew)
   {
       if(eCode == eNew)
       {
	 return;
       }
       eCode = eNew;
       InvokeCallBack(pCall,VALUECHANGE,NULL);
       fixed = 1;
   }
/*----------------------------------------------------------------------*/
   void ClearFixedStatus(Status eNew)
   {
       if(eCode == eNew)
       {
	 return;
       }
       eCode = eNew;
       InvokeCallBack(pCall,VALUECHANGE,NULL);
       fixed = 0;
   }
/*-------------------------------------------------------------------------*/   
   Status GetStatus(void)
   {
     return eCode;
   }
/*-------------------------------------------------------------------------*/   
   void   GetStatusText(char *buf, int iBufLen)
   {
     strncpy(buf,pText[(int)eCode],iBufLen-1);
   }
/*-------------------------------------------------------------------------*/
   int SetStatusFromText(char *text)
   {
      int i = 0;

   /* check for short form */
      strtolower(text);
      while(iText[i] != NULL)
      {
        if(strcmp(text,iText[i]) == 0)
        {
          break;
        }
        i++;
      }
      if(i >= 10)
      {
         /* check for long form */
         i = 0;
         while(pText[i] != NULL)
         {
           if(strcmp(text,pText[i]) == 0)
           {
             break;
           }
           i++;
         }
         if(i >= 10)
         {
           return 0;
         }
      }
      SetStatus((Status)i);
      return 1;
   }   
/*------------------- The CallBack function for interest ------------------*/
  static int StatusCallback(int iEvent, void *pEvent, void *pUser)
  {
     SConnection *pCon;
     char pBueffel[80];
     
     assert(pUser);
  
     pCon = (SConnection *)pUser;
          
     sprintf(pBueffel,"status = %s", pText[(int)eCode]);
     SCWrite(pCon,pBueffel,eWarning);
     return 1;
  }  
   
/*-----------------------------------------------------------------------*/   
   int UserStatus(SConnection *pCon, SicsInterp *pSics, void *pData,
                  int argc, char *argv[])
   {
      char pBueffel[512];
      long lID;

      assert(pSics);
      assert(pCon);
      
      /* create callback if not present */
      if(pCall == NULL)
      {
         pCall = CreateCallBackInterface();
      }
      
      /* check for interest */
      if(argc > 1)
      {
         strtolower(argv[1]);
         if(strcmp(argv[1],"interest") == 0)
         {
             lID = RegisterCallback(pCall, VALUECHANGE, StatusCallback,
                                    pCon, NULL);
             SCRegister(pCon,pSics, pCall,lID);
             SCSendOK(pCon);
             return 1;                       
         }
      }
      
      /* else just print value */
      sprintf(pBueffel,"status = %s", pText[(int)eCode]);
      SCWrite(pCon,pBueffel,eValue);
      return 1;
   } 
/*-------------------------------------------------------------------------*/
   int ResetStatus(SConnection *pCon, SicsInterp *pSics, void *pData,
                  int argc, char *argv[])
   {
      assert(pCon);
      assert(pSics);

      if(!SCMatchRights(pCon,usUser))
      {
         SCWrite(pCon,"Insufficient authorisation to reset server",eError);
         return 0;
      }      
      SetStatus(eEager);
      SetInterrupt(eContinue);
      ClearExecutor(GetExecutor());
      return 1;
   }               
/* ===================== Control Connection Management ====================*/                  
   static SConnection *pOwner = NULL;
   
   void SetControl(SConnection *pCon)
   {
      pOwner = pCon;
   }
/*--------------------------------------------------------------------------*/   
   int IsControl(SConnection *pCon)
   {
      if(pCon == pOwner)
      {
        return 1;
      }
      else
      {
        return 0;
      }
   }               
/*--------------------------------------------------------------------------*/
   SConnection *GetControl(void)
   {
     return pOwner;
   }
/*--------------------------------------------------------------------------*/
   int RedirectControl(SConnection *pCon, SicsInterp *pSics, void *pData,
                  int argc, char *argv[])
   {
      assert(pCon);
      assert(pSics);
      
      /* check user Rights */
      if(!SCMatchRights(pCon,usUser))
      {
         SCWrite(pCon,
           "You have NO, I repeat NO, Privilege to grab a control connection",
            eError);
          return 0;
      } 
      
      /* check if the connection is dead at all */
      if(pCon->pSock)
      {
        SCWrite(pCon, 
          "GOTCHA!!! Control still lives! You CANNOT grab it! FUCK OFF",
          eError);
        return 0;
      }
      
      /* now the wizardry */
      pOwner->pSock = pCon->pSock;
      return 1;
   }       
/*---------------------------------------------------------------------*/        
static int motorSave = 0;
/*-----------------------------------------------------------------------*/   
   int BackupStatus(SConnection *pCon, SicsInterp *pSics, void *pData,
                  int argc, char *argv[])
   {
      int iRet;
      char pBueffel[512];
      char *pFile = NULL;

      assert(pSics);
      assert(pCon);
      
      if(argc < 2)
      {
        pFile = IFindOption(pSICSOptions,"statusfile");
        if(pFile)
        {
            iRet = WriteSicsStatus(pSics,pFile,motorSave);
        }
        else
	{
           SCWrite(pCon,"ERROR: No filename given for backup, Aborted.",
                   eError);
           return 0;
        } 
      }
      else
      {
	if(strcmp(argv[1],"motorSave") == 0)
	{
	  if(motorSave== 1)
	    motorSave= 0;
          else
	    motorSave= 1;
	  sprintf(pBueffel,"New Value of motorSave= %d\n",motorSave);
          SCWrite(pCon,pBueffel,eValue);
	  return 1;
        }
        else
	{
          iRet = WriteSicsStatus(pSics,argv[1],motorSave);
        }
      }

      if(!iRet)
      {
        sprintf(pBueffel,"ERROR: could not open file %s\n", argv[1]);
        SCWrite(pCon,pBueffel,eError);
        return 0;
      }
      SCSendOK(pCon);
      return 1;
   } 
/*-----------------------------------------------------------------------*/   
   int RestoreStatus(SConnection *pCon, SicsInterp *pSics, void *pData,
                  int argc, char *argv[])
   {
     char pBueffel[512];
     int iRights;
     int iRet;
     char *pFile = NULL;
     
     assert(pSics);
     assert(pCon);

      if(argc < 2)
      {
        pFile = IFindOption(pSICSOptions,"statusfile");
        if(pFile)
        {
           sprintf(pBueffel,"FileEval %s",pFile);
        }
        else
	{
           SCWrite(pCon,"ERROR: No filename given for backup, Aborted.",
                   eError);
           return 0;
        } 
      }
      else
      {
          sprintf(pBueffel,"FileEval %s",argv[1]);
      }
      
      iRights = SCGetRights(pCon);
      pCon->iUserRights = usInternal;
      iRet = InterpExecute(pSics,pCon,pBueffel);
      pCon->iUserRights = iRights;
      return iRet;
   }

