/*
 * Programs to allow for reading and writing of a log file which
 * will record all output from both XSPEC and TCL.
 */
#include "xstcl.h"
 
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>

Tcl_Channel XS_Stdout_Chan;
Tcl_Channel XS_Stderr_Chan;
Tcl_Channel XS_Logfile_Chan;


char* xs_log_out = "LogOut";
char* xs_log_err = "ErrOut";

#include <cfortran.h>
#ifdef __cplusplus
}
#endif




/*
 * xs_input_log -- Dummy input routine for data logging channel.
 */
int
xs_input_log(ClientData cdata,char * buf,int  bufsize,int * errcode )
{
        return TCL_OK;
}


/*
 * xs_close_log -- Procedure for closing the data logging channel.
 */
int
xs_close_log(ClientData cdata,Tcl_Interp * interp ) 
{
        return TCL_OK;
}


/*
 * xs_output_log -- 
 */
int xs_output_log(ClientData cdata, char* buf,int  bufsize,int* errcode )
{
  /*
   *  First write to the log file.
   */


  if( Tcl_Write(XS_Logfile_Chan, buf, bufsize) != bufsize )
  {
        *errcode = Tcl_GetErrno();
        return TCL_ERROR;
  }
  if( Tcl_Flush(XS_Logfile_Chan) != TCL_OK)
  {
        *errcode = Tcl_GetErrno();
        return TCL_ERROR;
  }
  /*
   *  Now write either to stadard out or error, depending on oufile.
   */
  if( (char *)cdata == xs_log_out )
  {
        if( Tcl_Write(XS_Stdout_Chan, buf, bufsize) != bufsize )
        {
                *errcode = Tcl_GetErrno();
                return TCL_ERROR;
        }
        if( Tcl_Flush(XS_Stdout_Chan) != TCL_OK)
        {
                *errcode = Tcl_GetErrno();
                return TCL_ERROR;
        }

  }
  else if( (char *)cdata == xs_log_err )
  {
        if( Tcl_Write(XS_Stderr_Chan, buf, bufsize) != bufsize )
        {
                *errcode = Tcl_GetErrno();
                return TCL_ERROR;
        } 
        if( Tcl_Flush(XS_Stderr_Chan) != TCL_OK)
        {
                *errcode = Tcl_GetErrno();
                return TCL_ERROR;
        }
  }

  return bufsize;
}

/*
 * xs_watch_log --
 */
int xs_watch_log(ClientData cdata,int mask)
{
  int error=TCL_OK;
  if( mask | TCL_WRITABLE )
  {
        if( (char *)cdata == xs_log_out ) Tcl_NotifyChannel(XS_Stdout_Chan,mask);
        if( (char *)cdata == xs_log_err ) Tcl_NotifyChannel(XS_Stderr_Chan,mask);
        Tcl_NotifyChannel(XS_Logfile_Chan,mask);
  }

  return error;
}


/*
 * xs_handle_log --
 */
int xs_handle_log(ClientData cdata,int direct,ClientData* handler)
{
  if( (char *)cdata == xs_log_out )
  {
        return Tcl_GetChannelHandle(XS_Stdout_Chan, TCL_WRITABLE, handler);
  }
  else if ((char *)cdata == xs_log_err) 
  {
        return Tcl_GetChannelHandle(XS_Stderr_Chan, TCL_WRITABLE, handler);
  } 
  else return TCL_OK;
}


/*
 * xs_log --
 * Routine which sets everything up for writing a log file
 */
int xs_log(ClientData cdata,Tcl_Interp* interp,int objc,Tcl_Obj* CONST objv[] )
{
  Tcl_Channel Logging_Chan;
  char logfile[1024];
  time_t clock;
  int objlen = 0;
  int iarg, stamp = 0;
  static Tcl_ChannelType *LogPtr;

  strcpy(logfile,"xspec");

  for(iarg=1; iarg<objc; iarg++)
  {
    /*
     * If none is requested then either close the current log file,
     * or if there is not one, tell the user they are being silly.
     */  
        if( !strcmp(Tcl_GetStringFromObj(objv[iarg],&objlen),"none") )
        {
                if( Tcl_GetChannel(interp, xs_log_out, NULL) == NULL )
                {
                        Tcl_SetResult(interp, "No log file currently active.", TCL_VOLATILE);
                }
                else
                {
                        Logging_Chan = Tcl_GetChannel(interp, xs_log_out, NULL);
                        Tcl_UnregisterChannel(interp, Logging_Chan);
                        Logging_Chan = Tcl_GetChannel(interp, xs_log_err, NULL);
                        Tcl_UnregisterChannel(interp, Logging_Chan);
                        /*        Tcl_UnregisterChannel(interp, XS_Logfile_Chan); */
                        Tcl_SetResult(interp, "Logging disabled.", TCL_VOLATILE);
                        free(LogPtr);
                        Tcl_SetStdChannel(XS_Stdout_Chan, TCL_STDOUT);
                        Tcl_SetStdChannel(XS_Stderr_Chan, TCL_STDERR);
                }
                return TCL_OK;
        }
	/*
	* Set the stamp boolean if the string "stamp" is detected
	*/
        else if(!strcmp(Tcl_GetStringFromObj(objv[iarg],&objlen),"stamp") ||
                !strcmp(Tcl_GetStringFromObj(objv[iarg],&objlen),"STAMP") )
	{
	        stamp = 1;
	}
        /*
        * Get the log file name if specified.
        */
        else
        {
                strcpy(logfile,Tcl_GetStringFromObj(objv[iarg],&objlen));
        }
  }
  /*
   *  Make sure logging isn't already enabled.
   */
  if( Tcl_GetChannel(interp, xs_log_out, NULL) != NULL )
  {
        Tcl_SetResult(interp, "Log file is already active.", TCL_VOLATILE);
        return TCL_ERROR;
  }
  
  Tcl_ResetResult(interp);

  /*
   * If stamp is set then add a time stamp to the log file name.
   */
  if(stamp)
  {
    char *tstamp;
    int i;
    tstamp = (char *)malloc(26*sizeof(char));
    clock = time(0);
    tstamp = ctime(&clock);
    strcat(logfile, "_");
    strcat(logfile, tstamp);
    if (index(logfile,'.')==NULL) strcat(logfile,".log");
    for(i=0;i<strlen(logfile);i++)
    {
      if(logfile[i]==' ' || logfile[i]=='\n') logfile[i] = '_';
    }
  }
  /*
   * Open the log file and register it.
   */
  XS_Logfile_Chan = Tcl_OpenFileChannel(interp, logfile, "w", 0664);
  if( XS_Logfile_Chan == NULL ) return TCL_ERROR;

  Tcl_RegisterChannel(interp, XS_Logfile_Chan);

  /*
  * Create the channel getting input from gnu readline.
  * Updated B.Dorman. 11/98 for compatibility with tcl8.0 
  *
  * Channel drivers revised in tcl8.3.2 8/2000.
  *
  */
  LogPtr = (Tcl_ChannelType *)malloc(sizeof(Tcl_ChannelType));

  LogPtr->typeName = "file";
  LogPtr->version  = (Tcl_ChannelTypeVersion) TCL_CHANNEL_VERSION_2;
  LogPtr->closeProc = (Tcl_DriverCloseProc *)xs_close_log;
  LogPtr->inputProc = (Tcl_DriverInputProc *)xs_input_log;
  LogPtr->outputProc = (Tcl_DriverOutputProc *)xs_output_log;
  LogPtr->seekProc = (Tcl_DriverSeekProc *)NULL;
  LogPtr->setOptionProc = (Tcl_DriverSetOptionProc *)NULL;
  LogPtr->getOptionProc = (Tcl_DriverGetOptionProc *)NULL;
  /*
  * Create the channel getting input from gnu readline.
  * Updated B.Dorman. 11/98 for compatibility with tcl8.0 
  *
  * Channel drivers revised in tcl8.3.2 8/2000.
  *
  */
  LogPtr->watchProc = (Tcl_DriverWatchProc *)xs_watch_log;
  LogPtr->getHandleProc = (Tcl_DriverGetHandleProc *)xs_handle_log;
  LogPtr->close2Proc = (Tcl_DriverClose2Proc *)NULL;                
  LogPtr->blockModeProc = (Tcl_DriverBlockModeProc *)NULL;
  LogPtr->flushProc     = (Tcl_DriverFlushProc *)NULL;
  LogPtr->handlerProc     = (Tcl_DriverHandlerProc *)NULL;


  Logging_Chan = Tcl_CreateChannel( LogPtr, xs_log_out,  (ClientData)xs_log_out, TCL_WRITABLE);
  if( Logging_Chan == NULL ) return TCL_ERROR;

  Tcl_RegisterChannel(interp, Logging_Chan);

  if (Tcl_SetChannelOption(interp, Logging_Chan, "-buffering", "line") != TCL_OK ) return TCL_ERROR;

  /*
   * Now switch it around to be the standard channel for output,
   * after saving the value of the old channel so we can restore it.
   */
  XS_Stdout_Chan = Tcl_GetStdChannel(TCL_STDOUT);

  Tcl_SetStdChannel(Logging_Chan, TCL_STDOUT);

  /*
   * Now do the same for the standard error
   */

  Logging_Chan = Tcl_CreateChannel( LogPtr, xs_log_err,(ClientData)xs_log_err, TCL_WRITABLE);
  if( Logging_Chan == NULL ) return TCL_ERROR;

  Tcl_RegisterChannel(interp, Logging_Chan);

  if( Tcl_SetChannelOption(interp, Logging_Chan, "-buffering", "line") != TCL_OK ) return TCL_ERROR;

  XS_Stderr_Chan = Tcl_GetStdChannel(TCL_STDERR);

  Tcl_SetStdChannel(Logging_Chan, TCL_STDERR);

  /*
   * Finished
   */

  Tcl_AppendResult(interp, "Logging to file: ", logfile, (char *)NULL);

  return TCL_OK;
}


