//-----------------------------------------------------------------------------
// Copyright (c) 1994,1995 Southeastern Universities Research Association,
//                         Continuous Electron Beam Accelerator Facility
//
// This software was developed under a United States Government license
// described in the NOTICE file included as part of this distribution.
//
//-----------------------------------------------------------------------------
//
// Description:
//      Implementation of rsvcDataStoreMem Class
//
// Author:  Jie Chen
//
// Revision History:
//   rsvcDataStoreMem.cc,v
// Revision 1.2  1998/03/19  18:30:59  chen
// add monitorEntry capability to server table
//
// Revision 1.1  1998/01/22  17:08:07  akers
// Addition of new NameServer
//
//
//
#include <rsvcVirtualDbase.h>
#include <rsvcServerConfig.h>
#include <rsvcCacheData.h>
#include <rsvcIO.h>
#include <rsvcLogicQEng.h>
#include "rsvcDataStoreMem.h"

#ifdef _WIN32
#define strcasecmp _stricmp
#endif


rsvcDataStoreMem::rsvcDataStoreMem (char* name)
:rsvcDataStore (name)
{
#ifdef _TRACE_OBJECTS
  printf ("         Create rsvcDataStoreMem Class Object\n");
#endif
  database_ = new rsvcVirtualDbase ();
}

rsvcDataStoreMem::~rsvcDataStoreMem (void)
{
#ifdef _TRACE_OBJECTS
  printf ("         Delete rsvcDataStoreMem Class Object\n");
#endif
}

int
rsvcDataStoreMem::putValue (rsvcNetData& incoming,
			    rsvcNetData* out[], size_t* num, int overwrite)
{
  rsvcData& data = incoming.data ();
  int status = RSVC_SUCCESS;
  rsvcCacheData* cdata;

  if (tableDef_.tableDefined () && tableDef_.dataInsertable (data)) {
    if (tableDef_.hasKey (data)) {
      cdata = cachedData (data);
      if (cdata) {
#ifdef _RSVC_DEBUG
	printf ("Data with same key is already there\n");
#endif
	if (!overwrite)
	  status = RSVC_ERROR;
	else {
	  cdata->assign (data);
	  notifyAnEntryToChannels (data);
	}
      }
      else {
	cache_.add (new rsvcCacheData (data, database_, &tableDef_));
	notifyAnEntryToChannels (data);
      }
    }
    // check whether this data is compatable with table definition
    else if (tableDef_.keyValue (data) == RSVC_SUCCESS) {
      cdata = cachedData (data);
      if (cdata) {
#ifdef _RSVC_DEBUG
	printf ("Data with same key is already there\n");
#endif
	if (!overwrite)
	  status = RSVC_ERROR;
	else {
	  cdata->assign (data);
	  notifyAnEntryToChannels (data);
	}
      }
      else {
	cache_.add (new rsvcCacheData (data, database_, &tableDef_));
	notifyAnEntryToChannels (data);
      }
    }
    else
      status = RSVC_ERROR;
  }
  else
    status = RSVC_ERROR;

  // construct returning message
  out[0] = new rsvcNetData (incoming.cbk ());
  out[0]->cbkstatus (status);
  *num = 1;

  return status;
}

int
rsvcDataStoreMem::query (rsvcNetData& incoming, char* msg,
			 rsvcNetData* out[], size_t *num)
{
  rsvcData& data = incoming.data ();
  int status = RSVC_SUCCESS;
  rsvcCacheData* cdata;
  int i = 0;

  if (strcasecmp (msg, "all") == 0) // get all entries
    return getAll (incoming, out, num);

  // first check whether the query string is valid
  rsvcLogicQEng qe (msg);
  if (qe.parse () != 0) {
#ifdef _RSVC_DEBUG
    printf ("rsvcDataStoreMem: query msg <%s> systax error\n", msg);
#endif
    status = RSVC_QUERYMSG_ERR;
  }
  else {
    if (tableDef_.tableDefined ()) {
      rsvcHashIterator ite (cache_);
      
      for (ite.init (); !ite; ++ite) {
	cdata = (rsvcCacheData *) ite ();
	rsvcData& rdata = cdata->data ();
	if (qe.execute (rdata))  // match logic expression
	  if (i < *num) {
	    out[i] = new rsvcNetData (rdata, incoming.cbk ());
	    out[i]->cbkstatus (RSVC_INCOMPLETE);
	    i++;
	  }
      }
      if (i > 0) {
	*num = i;
	out[i - 1]->cbkstatus (RSVC_SUCCESS);  // turn last one to success
      }
      else
	status = RSVC_NOTFOUND;
    }
    else 
      status = RSVC_ERROR;
  }

  if (status != RSVC_SUCCESS) {
    out[0] = new rsvcNetData (incoming.cbk ());
    out[0]->cbkstatus (status);
    *num = 1;
  }

  return status;
}

int
rsvcDataStoreMem::getAll (rsvcNetData& incoming,
			  rsvcNetData* out[], size_t* num)
{
  int i = 0;
  rsvcHashIterator ite (cache_);
  rsvcCacheData* cdata = 0;
  
  for (ite.init (); !ite; ++ite) {
    cdata = (rsvcCacheData *) ite ();
    rsvcData& rdata = cdata->data ();
    if (i < *num) {
      out[i] = new rsvcNetData (rdata, incoming.cbk ());
      out[i]->cbkstatus (RSVC_INCOMPLETE);
      i++;
    }
  }

  if (i == 0) {
    *num = 1;
    out[0] = new rsvcNetData (incoming.cbk ());
    out[0]->cbkstatus (RSVC_NOTFOUND);
    return RSVC_NOTFOUND;
  }
  *num = i;
  out[i - 1]->cbkstatus (RSVC_SUCCESS);  // turn last one to success

  return RSVC_SUCCESS;
}

rsvcCacheData *
rsvcDataStoreMem::cachedData (rsvcData& key) 
{
  // create a fake cache data to do search
  rsvcCacheData keydata (key, database_, &tableDef_);
  rsvcHSlist& list = cache_.bucketRef (&keydata);
  rsvcHSlistIterator ite (list);
  rsvcCacheData* cdata;
  
  for (ite.init (); !ite; ++ite) {
    cdata = (rsvcCacheData *) ite ();
    if (cdata->sameKey (&keydata))
      return cdata;
  }
  return 0;
}

int
rsvcDataStoreMem::deleteCachedData (rsvcData& key) 
{
  // create a fake cache data to do search
  rsvcCacheData keydata (key, database_, &tableDef_);
  rsvcHSlist& list = cache_.bucketRef (&keydata);
  rsvcHSlistIterator ite (list);
  rsvcCacheData* cdata;
  int found = 0;
  
  for (ite.init (); !ite; ++ite) {
    cdata = (rsvcCacheData *) ite ();
    if (cdata->sameKey (&keydata)) {
      found = 1;
      break;
    }
  }
  if (found) {
    // call all monitor callbacks on this data
    cdata->notifyChannels (RSVC_CBK_FINISHED);
    list.remove (cdata);
    return RSVC_SUCCESS;
  }
  return RSVC_NOTFOUND;
}

int
rsvcDataStoreMem::getValue (rsvcNetData& incoming,
			    rsvcNetData* out[], size_t* num)
{
  // check whether this data is compatable with table definition
  rsvcData& data = incoming.data ();
  int       status = RSVC_SUCCESS;
  rsvcNetData* retdata = 0;

  if (!tableDef_.tableDefined ()) {
#ifdef _RSVC_DEBUG
    printf ("rsvcDataStoreMem: table definition is not defined\n");
#endif
    status = RSVC_ERROR;
  }
  else {
    if (!tableDef_.hasKey (data)) {
      if (tableDef_.keyValue (data) != RSVC_SUCCESS) {
#ifdef _RSVC_DEBUG
	printf ("rsvcDataStoreMem: cannot construct key value from data\n");
#endif
	status = RSVC_NOKEY;
      }
    }
  }

  if (status == RSVC_SUCCESS) {
    rsvcCacheData* cdata = cachedData (data);
    if (!cdata) {
      status = RSVC_NOTFOUND;
    }
    else
      retdata = new rsvcNetData (cdata->data (), incoming.cbk ());
  }
  
  if (!retdata) {
    retdata = new rsvcNetData (incoming.cbk ());
  }
  retdata->cbkstatus (status);
  out[0] = retdata;
  *num = 1;

  return status;
}


int
rsvcDataStoreMem::delValue (rsvcNetData& incoming,
			    rsvcNetData* out[], size_t* num)
{
  // check whether this data is compatable with table definition
  rsvcData& data = incoming.data ();
  int       status = RSVC_SUCCESS;

  if (!tableDef_.tableDefined () ) {
#ifdef _RSVC_DEBUG
    printf ("rsvcDataStoreMem: table definition is not valid\n");
#endif
    status = RSVC_ERROR;
  }
  else {
    if (!tableDef_.hasKey (data)) {
      if (tableDef_.keyValue (data) != RSVC_SUCCESS)
	status = RSVC_NOKEY;
    }
  }
  
  if (status == RSVC_SUCCESS) 
    status = deleteCachedData (data);
  
  out[0] = new rsvcNetData (incoming.cbk ());
  out[0]->cbkstatus (status);
  *num = 1;

  return status;
}

int
rsvcDataStoreMem::flush (void)
{
  return RSVC_SUCCESS;
}

int
rsvcDataStoreMem::setValue (rsvcNetData& incoming,
			    rsvcNetData* out[], size_t* num)
{
  // check whether this data is compatable with table definition
  rsvcData& data = incoming.data ();
  int       status = RSVC_SUCCESS;

  if (!tableDef_.tableDefined ()) {
#ifdef _RSVC_DEBUG
    printf ("rsvcDataStoreMem: table definition is not defined yet\n");
#endif
    status = RSVC_ERROR;
  }
  else {
    if (!tableDef_.dataValid (data)) {
#ifdef _RSVC_DEBUG
      printf ("rsvcDataStoreMem: data not valid for settting\n");
#endif
      status = RSVC_INVALIDARG;
    }
    else {
      if (!tableDef_.hasKey (data)) {
	if (tableDef_.keyValue (data) != RSVC_SUCCESS) {
#ifdef _RSVC_DEBUG
	  printf ("rsvcDataStoreMem: data has no key information for setting\n");
#endif
	  status = RSVC_NOKEY;
	}
      }
    }
  }
  
  if (status == RSVC_SUCCESS) {
    rsvcCacheData* cdata = cachedData (data);
    if (!cdata) 
      status = RSVC_NOTFOUND;
    else 
      status = cdata->assign (data);
  }

  if (*num > 0) {
    out[0] = new rsvcNetData (incoming.cbk ());
    out[0]->cbkstatus (status);
    *num = 1;
  }

  return status;
}

int
rsvcDataStoreMem::monitorIncomingEntries (rsvcNetData& incoming,
					  rsvcNetData* out[],
					  size_t* num)
{
  int          status = RSVC_SUCCESS;
  rsvcNetData* retdata = 0;
  int          i = 0;
  
  // get all existing entries
  rsvcHashIterator ite (cache_);
  rsvcCacheData* cdata = 0;

  for (ite.init (); !ite; ++ite) {
    cdata = (rsvcCacheData *) ite ();
    rsvcData& rdata = cdata->data ();
    if (i < *num) {
      out[i] = new rsvcNetData (rdata, incoming.cbk ());
      out[i]->cbkstatus (RSVC_INCOMPLETE);
      i++;
    }
  }
  if (i > 0) {
    *num = i;
    out[i - 1]->cbkstatus (RSVC_SUCCESS);
  }
  else
    status = RSVC_NOTFOUND;

  if (status != RSVC_SUCCESS) {
    out[0] = new rsvcNetData (incoming.cbk ());
    // empty table is ok
    out[0]->cbkstatus (RSVC_SUCCESS);
    *num = 1;
  }

  // add callback to monitor list
  rsvcCbk* tcbk = new rsvcCbk (incoming.cbk ());
  idataMonitorList_.add (tcbk);
    
  return status;
}

int
rsvcDataStoreMem::monitorOffIncomingEntries (rsvcNetData& incoming,
					     rsvcNetData* out[],
					     size_t* num)
{
  rsvcHSlistIterator ite (idataMonitorList_);
  rsvcCbk* tcbk = 0;
  int      found = 0;
  int      status = RSVC_SUCCESS;

  for (ite.init (); !ite; ++ite) {
    tcbk = (rsvcCbk *) ite ();
    if (rsvcCbk::sameCallback (tcbk, &incoming.cbk (), 1)) {
      found = 1;
      break;
    }
  }
  if (found) {
    idataMonitorList_.remove (tcbk);
    delete tcbk;
    status = RSVC_CBK_FINISHED;
  }
  else
    status = RSVC_NOTFOUND;

  out[0] = new rsvcNetData (incoming.cbk ());
  out[0]->cbkstatus (status);
  *num = 1;

  return status;
}

int
rsvcDataStoreMem::monitorValue (rsvcNetData& incoming,
				rsvcNetData* out[], size_t* num)
{
  // check whether this data is compatable with table definition
  rsvcData& data = incoming.data ();
  int       status = RSVC_SUCCESS;
  rsvcNetData* retdata = 0;

  if (!tableDef_.tableDefined ()) {
#ifdef _RSVC_DEBUG
    printf ("rsvcDataStoreMem: table definition is not defined\n");
#endif
    status = RSVC_ERROR;
  }
  else {
    if (!tableDef_.hasKey (data)) {
      if (tableDef_.keyValue (data) != RSVC_SUCCESS) {
#ifdef _RSVC_DEBUG
	printf ("rsvcDataStoreMem: data has no key for monitoring\n");
#endif
	status = RSVC_NOKEY;
      }
    }
  }
  
  if (status == RSVC_SUCCESS) {
    rsvcCacheData* cdata = cachedData (data);
    if (!cdata) {
      status = RSVC_NOTFOUND;
    }
    else 
      if ((status = cdata->monitorOn (incoming.cbk ())) == RSVC_SUCCESS) 
	retdata = new rsvcNetData (cdata->data (), incoming.cbk ());
  }

  if (!retdata) 
    retdata = new rsvcNetData (incoming.cbk ());

  retdata->cbkstatus (status);
  out[0] = retdata;
  *num = 1;

  return status;
}  


int
rsvcDataStoreMem::monitorAttr (rsvcNetData& incoming,
			       rsvcNetData* out[], size_t* num)
{
  // check whether this data is compatable with table definition
  rsvcData& data = incoming.data ();
  int       status = RSVC_SUCCESS;
  rsvcNetData* retdata = 0;

  if (!tableDef_.tableDefined ()) {
#ifdef _RSVC_DEBUG
    printf ("rsvcDataStoreMem: table definition is not defined\n");
#endif
    status = RSVC_ERROR;
  }
  else {
    if (!tableDef_.hasKey (data)) {
      if (tableDef_.keyValue (data) != RSVC_SUCCESS) {
#ifdef _RSVC_DEBUG
	printf ("rsvcDataStoreMem: data has no key for monitoring\n");
#endif
	status = RSVC_NOKEY;
      }
    }
  }
  
  if (status == RSVC_SUCCESS) {
    // get attribute name from incoming data
    char attribute[RSVC_TAG_MAX_LEN];
    if (data.get (rsvcServerConfig::monitorTag (), attribute, sizeof (attribute)) 
	!= RSVC_SUCCESS) 
      status = RSVC_INVALIDARG;
    else {
      rsvcCacheData* cdata = cachedData (data);
      if (!cdata) {
	status = RSVC_NOTFOUND;
      }
      else {
	if ((status = cdata->monitorAttr (attribute, incoming.cbk ())) == RSVC_SUCCESS) {
	  retdata = new rsvcNetData (cdata->data (), incoming.cbk ());
	  // put monitor and attaribute into the outbound data
	  retdata->data ().insert (rsvcServerConfig::monitorTag (), attribute);
	}
      }
    }
  }

  if (!retdata) 
    retdata = new rsvcNetData (incoming.cbk ());

  retdata->cbkstatus (status);
  out[0] = retdata;
  *num = 1;

  return status;
}  

int
rsvcDataStoreMem::monitorOffValue (rsvcNetData& incoming,
				   rsvcNetData* out[], size_t* num)
{
  // check whether this data is compatable with table definition
  rsvcData& data = incoming.data ();
  int       status = RSVC_SUCCESS;
  rsvcNetData* retdata = 0;

  if (!tableDef_.tableDefined ()) {
#ifdef _RSVC_DEBUG
    printf ("rsvcDataStoreMem: Table is not defined yet\n");
#endif
    status = RSVC_ERROR;
  }
  else {
    if (!tableDef_.hasKey (data)) {
      if (tableDef_.keyValue (data) != RSVC_SUCCESS) {
#ifdef _RSVC_DEBUG
	printf ("rsvcDataStoreMem: data has no key for monitoring off\n");
#endif
	status = RSVC_NOKEY;
      }
    }
  }
  
  if (status == RSVC_SUCCESS) {
    rsvcCacheData* cdata = cachedData (data);
    if (!cdata) {
      status = RSVC_NOTFOUND;
    }
    else 
      if ((status = cdata->monitorOff (incoming.cbk ())) == RSVC_SUCCESS) 
	status = RSVC_CBK_FINISHED;
  }
  if (!retdata) 
    retdata = new rsvcNetData (incoming.cbk ());

  retdata->cbkstatus (status);
  out[0] = retdata;
  *num = 1;

  return status;
}  


int
rsvcDataStoreMem::monitorOffAttr (rsvcNetData& incoming,
				  rsvcNetData* out[], size_t* num)
{
  // check whether this data is compatable with table definition
  rsvcData& data = incoming.data ();
  int       status = RSVC_SUCCESS;
  rsvcNetData* retdata = 0;

  if (!tableDef_.tableDefined ()) {
#ifdef _RSVC_DEBUG
    printf ("rsvcDataStoreMem: table definition is not defined\n");
#endif
    status = RSVC_ERROR;
  }
  else {
    if (!tableDef_.hasKey (data)) {
      if (tableDef_.keyValue (data) != RSVC_SUCCESS) {
#ifdef _RSVC_DEBUG
	printf ("rsvcDataStoreMem: data has no key for monitoring\n");
#endif
	status = RSVC_NOKEY;
      }
    }
  }
  
  if (status == RSVC_SUCCESS) {
    // get attribute name from incoming data
    char attribute[RSVC_TAG_MAX_LEN];
    if (data.get (rsvcServerConfig::monitorTag (), attribute, sizeof (attribute)) 
	!= RSVC_SUCCESS) 
      status = RSVC_INVALIDARG;
    else {
      rsvcCacheData* cdata = cachedData (data);
      if (!cdata) {
	status = RSVC_NOTFOUND;
      }
      else 
	if (status = cdata->monitorOffAttr (attribute, incoming.cbk ()) == RSVC_SUCCESS)
	  status = RSVC_CBK_FINISHED;
    }
  }

  retdata = new rsvcNetData (incoming.cbk ());

  retdata->cbkstatus (status);
  out[0] = retdata;
  *num = 1;

  return status;
}  


int
rsvcDataStoreMem::monitorOff (void* ioptr)
{
  rsvcCacheData* cdata = 0;
  rsvcHashIterator ite (cache_);

  int i = 0;
  for (ite.init (); !ite; ++ite) {
    cdata = (rsvcCacheData *) ite ();
    cdata->monitorOff (ioptr);
    i++;
  }

  // remove monitor entry callbacks for this client
  rsvcHSlistIterator eite (idataMonitorList_);
  rsvcCbk* cbk = 0;

  for (eite.init (); !eite; ++eite) {
    cbk = (rsvcCbk *) eite ();

    // connection channel
    if (cbk->userptr () == ioptr) {
      delete cbk;
      eite.removeCurrent ();
    }
  }
  return RSVC_SUCCESS;
}
