/*
 *    SCCS ID: %Z%%M% %I% %E% SST 
 *
 *    Copyright (c) 1992-1993 Mark Soloway.  All rights reserved.
 *    See SST_LEGAL_NOTICE file for terms of the license.
 */

#ifndef _TT_SESSION_H
#define _TT_SESSION_H

#include <memory.h>
#include <stdio.h>
#include <string.h>
#include <desktop/tt_c.h>
#include <rpc/types.h>
#include <rpc/xdr.h>

#include "TTBoolean.h"
#include "TTGenericArrayTemplate.h"
#include "TTGenericHash.h"
#include "TTSharedTypes.h"

class PollFD;
class TTContextValue;
class TTFile;
class TTMessage;
class TTPattern;
class TTSession;

DECLARE_TT_GENERIC_ARRAY(TTContextValue);
 
enum Tt_session_type { TT_DEFAULT_SESSION,
		       TT_INITIAL_SESSION,
		       TT_USER_SESSION,
		       TT_X_SESSION };

enum Tt_poll_action { TT_POLL_ABORT, 
		      TT_POLL_CONTINUE };

typedef Tt_status      (*TTSessionCallback) (TTSession *, TTMessage *);
typedef Tt_poll_action (*TTPollCallback) (TTSession *);

class TTSession : public TTGeneric {
public:
  TTSession (Tt_status&);
  TTSession (Tt_session_type, const char *, Tt_status&);
  TTSession (const TTSession&);
  TTSession &operator= (const TTSession&);
  ~TTSession ();

  Tt_status setDefaultFile (const char *);
  Tt_status setDefaultFile (const TTFile&);

  Tt_status setDefaultPType (const char *);

  // All file operations apply to all of the registered patterns
  // and declared ptypes
  Tt_status joinFile (const char *);
  Tt_status joinFile (const TTFile&);
  Tt_status quitFile (const char *);
  Tt_status quitFile (const TTFile&);
  Tt_status quitAllFiles ();

  // All context operations apply to all of the registered patterns
  // and declared ptypes
  Tt_status joinContext (const char *, int);
  Tt_status joinContext (const char *, const char *);
  Tt_status joinContext (const char *, unsigned const char *, int);
  Tt_status joinContext (const char *, xdrproc_t, void *);
  Tt_status quitContext (const char *, int);
  Tt_status quitContext (const char *, const char *);
  Tt_status quitContext (const char *, unsigned const char *, int);
  Tt_status quitContext (const char *, xdrproc_t, void *);
  Tt_status quitAllContextValues (const char *);

  Tt_status declarePType (const char *);
  Tt_status undeclarePType (const char *);
  Tt_status doesPTypeExist (const char *);
  Tt_status loadPTypesFile (const char *);

  // Specifies the timeout in milliseconds of how long polls on the
  // TT FD should last in the waitForMessage, waitForServiceRequest,
  // and sendSynchronousMessage calls.  If the poll call times out, then
  // the time out callback, specified by setTimeOutCallback, is called.
  Tt_status setTimeOut (int);
  Tt_status setTimeOutCallback (TTPollCallback);

  // If an error occurs during a poll on a TT FD, the specified
  // callback is called.
  Tt_status setPollErrorCallback (TTPollCallback);

  // Polls the TT FD and returns a message when activated.  The
  // message returned must be deleted by the caller.
  TTMessage *waitForMessage (Tt_status&);

  // Polls the TT FD.  If the message is a start message, the
  // message is accepted if tt_message_accept is implemented.
  // If tt_message_accept is not implemented, then the start
  // message is failed.  If the message is not failed, it is
  // returned.  The message returned must be deleted by the
  // caller.
  TTMessage *waitForServiceRequest (Tt_status&);

  // Send a request and return the reply.
  Tt_status sendSynchronousMessage (TTMessage&);

  // Send a message and return immediately.
  Tt_status  sendAsynchronousMessage (TTMessage&);

  // Send a message and return immediately.  Also return the ID of this
  // message send.
  Tt_status  sendAsynchronousMessage (TTMessage&, char* &message_send_id);

  // Receive a message.  If the message is a reply to a message
  // that was sent asynchronously, the same message object is
  // returned.  Otherwise, a new message object is returned.
  TTMessage *receiveAsynchronousMessage (Tt_status&);

  // Sends a service request.  If the message sent goes
  // through the TT_STARTED and TT_FAILED states, it assumed
  // that a special service request protocol is being followed
  // and the message is resent.  The reply to the request is
  // returned.
  Tt_status sendServiceRequest (TTMessage&);

  // Sends a message on behalf of the client when the client connection
  // is closed.
  Tt_status sendMessageOnExit (TTMessage&);

  Tt_status replyToMessage (const TTMessage&) const;
  Tt_status rejectMessage (const TTMessage&) const;
  Tt_status failMessage (const TTMessage &message,
			 Tt_status        message_status,
			 const char      *message_status_string=NULL) const;
  Tt_status acceptMessage (const TTMessage&) const;

  Tt_status registerPattern (const TTPattern &);
  Tt_status unregisterPattern (const TTPattern &);

  // When the session is in a "waitFor..." mode or receiveAsynchronousMessage
  // is called, the specified TTSessionCallback function is called when a
  // message is received.
  Tt_status setCallback (TTSessionCallback);

  int   getPropertyNameCount (Tt_status&) const;
  char *getPropertyName (int, Tt_status&) const;

  int       getPropertyCount (const char *name, Tt_status&) const;
  Tt_status getProperty (const char *name, int, char*&) const;
  Tt_status getProperty (const char *name, int, unsigned char*&, int&) const;

  Tt_status setProperty (const char *name, const char *);
  Tt_status setProperty (const char *name, const unsigned char *, int);

  Tt_status addProperty (const char *name, const char *);
  Tt_status addProperty (const char *name, const unsigned char *, int);

  int   getFD (Tt_status&) const;
  char *getProcID (Tt_status&) const;
  char *getSessionID (Tt_status&) const;
  char *getDefaultFile (Tt_status&) const;
  char *getDefaultPType (Tt_status&) const;

protected:
  // If called with TT_TRUE (by a derived class), the defaultPollErrorCallback
  // function is called when an error occurs during a poll on a TT FD.
  // The defaultPollErrorCallback function can be overridden by the derived
  // class.  If TT_POLL_ABORT is returned, the poll is aborted.  If
  // TT_POLL_CONTINUE is returned, the poll is continued.
  Tt_status useDefaultPollErrorCallback (TTBoolean);

  // If called with TT_TRUE (by a derived class), the defaultSessionCallback
  // function is called when the session is a "waitFor.." mode and
  // a message is received or if receiveAsynchronousMessage is called.
  // The defaultSessionCallback function can be overridden by the derived class.
  Tt_status useDefaultSessionCallback (TTBoolean);

  // If called with TT_TRUE (by a derived class), the defaultTimeOutCallback
  // function if a poll on the TT FD times out.  The defaultTimeOutCallback
  // function can be overridden by the derived class.  If TT_POLL_ABORT is 
  // returned, the poll is aborted.  If TT_POLL_CONTINUE is returned, the
  // poll is continued.
  Tt_status useDefaultTimeOutCallback (TTBoolean);

private:
  TTGenericHash	     contextTable;
  int		     dummyData;
  TTGenericHash      fileTable;
  PollFD            *pollFD;
  TTPollCallback     pollErrorCallback;
  TTSessionCallback  sessionCallback;
  TTPollCallback     timeOutCallback;
  int                timeOut;
  char		    *ttDefaultFile;
  char		    *ttDefaultPType;
  int                ttFD;
  char              *ttProcID;
  char              *ttSessionID;
  TTBoolean          useDefaultPollErrorCallbackFlag;
  TTBoolean          useDefaultSessionCallbackFlag;
  TTBoolean          useDefaultTimeOutCallbackFlag;

  void      setTTSessionDefaults ();
  void      copy (const TTSession&);
  void      destroy ();
  int       findContext (const TTContextValueArray&,
			 const TTContextValue&) const;
  Tt_status rejoin ();
  Tt_status setTTDefaults () const;

  virtual Tt_poll_action defaultPollErrorCallback ();
  virtual Tt_status      defaultSessionCallback (TTMessage *);
  virtual Tt_poll_action defaultTimeOutCallback ();
};

class TTContextValue : public TTGeneric {
public:
  TTContextValue ()
    {
      setTTContextValueDefaults ();
    }

  TTContextValue (const TTContextValue &value)
    {
      copy (value);
    }

  TTContextValue &TTContextValue::operator= (const TTContextValue &value) 
    { 
      if (this != &value) {
	destroy ();
        copy (value); 
      }

      return *this;
    } 
  
  ~TTContextValue ()
    {
      destroy ();
    }

  int operator== (const TTContextValue &value)
    {
      int equal = 0;

      if (type == value.type) {
	if (intValue == value.intValue) {
	  if (type == TT_BYTES_VALUE) {
	    if (bytesValueLength == value.bytesValueLength) {
	      equal = !memcmp (bytesValue, value.bytesValue, bytesValueLength);
	    }
	  }
	}
      }

      return equal;
    }

  void setIntValue (int value)
    {
      destroy ();
      setTTContextValueDefaults ();

      type = TT_INT_VALUE;
      intValue = value;
    }

  int getIntValue () const
    {
      return intValue;
    }

  void setBytesValue (const char *value)
    {
      setInternalBytesValue ((const unsigned char *)value,
			     value ? strlen (value) : 0);
    }
 
  void setBytesValue (const unsigned char *value, int length)
    {
      setInternalBytesValue (value, length);
    }

  unsigned char *getBytesValue () const
    {
      return bytesValue;
    }

  int getLength () const
    {
      return bytesValueLength;
    }

  Tt_value_type getType ()
    {
      return type;
    }
 
private:
  Tt_value_type  type;
  int            intValue;
  unsigned char *bytesValue;
  int            bytesValueLength;

  void setTTContextValueDefaults ()
    {
      type = TT_NULL_VALUE;
      intValue = 0;
      bytesValue = (unsigned char *)NULL;
      bytesValueLength = 0;
    }

  void copy (const TTContextValue &value)
    {
      type = value.type;
      intValue = value.intValue;
      bytesValueLength = value.bytesValueLength; 

      if (type == TT_BYTES_VALUE) {
        bytesValue = (unsigned char *)
                     memcpy (new char [bytesValueLength + 1],
                             value.bytesValue,
                             bytesValueLength);
        bytesValue [bytesValueLength] = (unsigned char)'\0';
      }
      else {
        bytesValue = value.bytesValue;
      }
    }

  void destroy ()
    {
      if (bytesValue) delete bytesValue;
    }

  void setInternalBytesValue (const unsigned char *value, int length)
    {
      destroy ();
      setTTContextValueDefaults ();

      if (value) {
	type = TT_BYTES_VALUE;
	bytesValue = (unsigned char *)
		     memcpy (new char [length + 1], value, length);
	bytesValue [length] = '\0';
	bytesValueLength = length;
      }
      else {
        type = TT_NULL_VALUE;
        bytesValue = (unsigned char *)NULL;
	bytesValueLength = 0;
      }
    }
};
 
#endif
