//-----------------------------------------------------------------------------
// 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.
//
// CEBAF Data Acquisition Group, 12000 Jefferson Ave., Newport News, VA 23606
//       coda@cebaf.gov  Tel: (804) 249-7030     Fax: (804) 249-5800
//-----------------------------------------------------------------------------
//
// Description:
//      Implementation of simple computing machine for query
//
// Author:  
//      Jie Chen
//      CEBAF Data Acquisition Group
//
// Revision History:
//   rsvcLogicQEng.cc,v
// Revision 1.1  1998/01/22  17:08:16  akers
// Addition of new NameServer
//
//
//
#include "rsvcLogicQEng.h"
#include "y.tab.h"

extern "C" int yyparse (void);

rsvcLogicQEng::rsvcLogicQEng (char* qstr)
:result_ (-1)
{
#ifdef _TRACE_OBJECTS
  printf ("Create rsvcLogicQEng Class Object\n");
#endif
  stackp_ = stack_;
  progp_ = prog_;
  pc_ = prog_;

  qstr_ = new char[::strlen (qstr) + 1];
  ::strcpy (qstr_, qstr);

  int i = 0;

  for (i = 0; i < RSVC_NSTACK; i++)
    stack_[i] = 0;

  for (i = 0; i < RSVC_NPROG; i++)
    prog_[i] = RSVC_LOGIC_STOP;
}

rsvcLogicQEng::~rsvcLogicQEng (void)
{
#ifdef _TRACE_OBJECTS
  printf ("Delele rsvcLogicQEng Class Object\n");
#endif
  // delete data item on the stack
  rsvc_logic_data** ptr = stack_;
  while (ptr < stackp_) {  // stackp_ is the next free slot
    free_logic_data (*ptr);
    ptr++;
  }

  delete []qstr_;
}

int
rsvcLogicQEng::parse (void)
{
  // need mutex lock here for MT case
  set_input_text (qstr_);
  set_query_engine ((void *)this);

  if (yyparse ())
    return -1;
  else
    return 0;
}

int
rsvcLogicQEng::execute (rsvcData& data)
{
  pc_ = prog_;
  while (*pc_ != RSVC_LOGIC_STOP) {
    (*(*pc_)) ((void *)&data);
    pc_++;
  }

  return result_;
}

int
rsvcLogicQEng::clean (void)
{
  pc_ = prog_;
  while (*pc_ != RSVC_LOGIC_STOP) {
    (*(*pc_)) ((void *)0);
    pc_++;
  }

  return result_;
}


int
rsvcLogicQEng::push (rsvc_logic_data* data)
{
  if (stackp_ > &stack_[RSVC_NSTACK-1]) {
    fprintf (stderr, "Rsvc Logic Stack Overflow\n");
    return -1;
  }
  *stackp_ = data;
  stackp_++;
  return 0;
}

rsvc_logic_data*
rsvcLogicQEng::pop (void)
{
  if (stackp_ <= stack_) {
    fprintf (stderr, "Rsvc Logic Stack Underflow\n");
    return 0;
  }
  // since stackp is the next free slot
  stackp_ --;
  rsvc_logic_data* data = *stackp_;
  return data;
}

rsvcLogicInst*
logic_code (rsvcLogicInst f)
{
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcLogicInst* oprogp = eng->progp_;
  if (eng->progp_ > &(eng->prog_[RSVC_NPROG - 1]) ) {
    fprintf (stderr, "Programm is too big\n");
    return 0;
  }
  *(eng->progp_) = f;
  (eng->progp_)++;

  return oprogp;
}

int
logic_val_push (void* arg)
{
  rsvc_logic_data* tmp = 0;
  rsvc_logic_data* data0 = 0;
  rsvc_logic_data* data1 = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcLogicInst* pc; 
  // increment program counter
  (eng->pc_)++;
  pc = eng->pc_;

  tmp = (rsvc_logic_data *)(*pc);
  if (arg == 0)
    free_logic_data (tmp);
  else
    data0 = logic_data_dup (tmp);

  // increment program counter
  (eng->pc_)++;
  pc = eng->pc_;
  tmp = (rsvc_logic_data *)(*pc);
  if (arg == 0)
    free_logic_data (tmp);
  else
    data1 = logic_data_dup (tmp);

  if (arg != 0) {
    eng->push (data0);
    eng->push (data1);
  }

  return 0;
}
  

int
rsvc_data_equal_int (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_INT) {
    int temp;

    if (data->get (d1->u.string, &temp) == RSVC_SUCCESS) {
      if (temp == d2->u.ival)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}


int
rsvc_data_equal_dbl (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_DBL) {
    double temp;

    if (data->get (d1->u.string, &temp) == RSVC_SUCCESS) {
      if (temp == d2->u.dval)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}

int
rsvc_data_equal_str (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_STR) {
    char temp[256];

    if (data->get (d1->u.string, temp, sizeof (temp)) == RSVC_SUCCESS) {
      if (strcmp (temp, d2->u.string) == 0)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}

int
rsvc_data_less_int (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_INT) {
    int temp;

    if (data->get (d1->u.string, &temp) == RSVC_SUCCESS) {
      if (temp < d2->u.ival)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}


int
rsvc_data_less_dbl (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_DBL) {
    double temp;

    if (data->get (d1->u.string, &temp) == RSVC_SUCCESS) {
      if (temp < d2->u.dval)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}

  
int
rsvc_data_greater_int (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_INT) {
    int temp;

    if (data->get (d1->u.string, &temp) == RSVC_SUCCESS) {
      if (temp > d2->u.ival)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}

int
rsvc_data_greater_dbl (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_DBL) {
    double temp;

    if (data->get (d1->u.string, &temp) == RSVC_SUCCESS) {
      if (temp > d2->u.dval)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}  

int
rsvc_data_lesseq_int (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_INT) {
    int temp;

    if (data->get (d1->u.string, &temp) == RSVC_SUCCESS) {
      if (temp <= d2->u.ival)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}

int
rsvc_data_lesseq_dbl (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_DBL) {
    double temp;

    if (data->get (d1->u.string, &temp) == RSVC_SUCCESS) {
      if (temp <= d2->u.dval)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}  

int
rsvc_data_greatereq_int (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_INT) {
    int temp;

    if (data->get (d1->u.string, &temp) == RSVC_SUCCESS) {
      if (temp >= d2->u.ival)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}

int
rsvc_data_greatereq_dbl (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_DBL) {
    double temp;

    if (data->get (d1->u.string, &temp) == RSVC_SUCCESS) {
      if (temp >= d2->u.dval)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}  

int
rsvc_data_noequal_int (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_INT) {
    int temp;

    if (data->get (d1->u.string, &temp) == RSVC_SUCCESS) {
      if (temp != d2->u.ival)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}

int
rsvc_data_noequal_dbl (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_DBL) {
    double temp;

    if (data->get (d1->u.string, &temp) == RSVC_SUCCESS) {
      if (temp != d2->u.dval)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}  

int
rsvc_data_noequal_str (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_STR) {
    char temp[256];

    if (data->get (d1->u.string, temp, sizeof (temp)) == RSVC_SUCCESS) {
      if (strcmp (temp, d2->u.string) != 0)
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}

int
rsvc_data_has_str (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvcData* data = (rsvcData *)d;
  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_STR && d2->type == RSVC_LOGIC_STR) {
    char temp[256];

    if (data->get (d1->u.string, temp, sizeof (temp)) == RSVC_SUCCESS) {
      if (strstr (temp, d2->u.string))
	res = 1;
    }
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}

int
rsvc_logic_and (void* d)
{
  if (d == 0)
    return 0;


  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_INT && d2->type == RSVC_LOGIC_INT) {
    if (d1->u.ival && d2->u.ival)
      res = 1;
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}


int
rsvc_logic_or (void* d)
{
  if (d == 0)
    return 0;


  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvc_logic_data* d2 = eng->pop ();
  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_INT && d2->type == RSVC_LOGIC_INT) {
    if (d1->u.ival || d2->u.ival)
      res = 1;
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);
  free_logic_data (d2);

  return res;
}


int
rsvc_logic_neg (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_INT) {
    if (d1->u.ival > 0)
      res = 0;
    else
      res = 1;
  }

  rsvc_logic_data* ndata = new_logic_data ();
  logic_data_assign_int (ndata, res);

  // push new data onto the stack
  eng->push (ndata);

  // release memory of old data
  free_logic_data (d1);

  return res;
}

int
rsvc_logic_end (void* d)
{
  if (d == 0)
    return 0;

  int res = 0;
  // this routine is called with mutex lock held
  rsvcLogicQEng* eng = (rsvcLogicQEng *)_logic_q_eng;

  rsvc_logic_data* d1 = eng->pop ();

  // check stack varaibles
  if (d1->type == RSVC_LOGIC_INT) {
    res = d1->u.ival;
  }

  // release memory of old data
  free_logic_data (d1);

  eng->result_ = res;
  return res;
}
