/***************************************************************************
  This is part of the evolver toolkit for exploring genetic progamming.
  Copyright (C) 1996 Benjamin Bennett and Yeasah G. Pell

  This library is free software; you can redistribute it and/or modify
  it under the terms of the GNU Library General Public License as
  published by the Free Software Foundation; either version 2 of the
  License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

  Contact information: Benjamin Bennett<fiji@limey.net> and Yeasah
    G. Pell<yeasah@wpi.edu>
  *************************************************************************/

#ifndef __OPTABLE_NET1_H
#define __OPTABLE_NET1_H

/**************************************************************************
  GOperatorTable class - allows creation and querying of arbitrary
  operator types (without knowledge of derivation structure)
  ************************************************************************/

/* prerequisites */
#include "generic.H"
#include "type_net1.H"

/// SYSTEM DEFINE - the total number of known operators
#define NUM_OPERATORS 33

/// SYSTEM DEFINE - the maximum number of children any operator may have
#define MAX_CHILDREN 3

/// All of the operators for the network model
/*@Doc: An enumeration containing all of the operators for the network
  model. */
enum oper_enum
{
	/// {\Large Environment interaction operations}
	//@{
	/// Increase flow: int (int pipe)
    OP_INC_FLOW,
	/// Decrease flow: int (int pipe)
	OP_DEC_FLOW,
	/// Query flow in: int (int pipe)
	OP_QFLOW_IN,
	/// Query flow out: int (int pipe)
	OP_QFLOW_OUT,
	/// Query num pipes: in int ()
	OP_QPIPES_IN,
	/// Query num pipes: out int ()
	OP_QPIPES_OUT,
	/// Query capacity in: int (int pipe)
	OP_QCAP_IN,
	/// Query capacity out: int (int pipe)
	OP_QCAP_OUT,
	/// Send message 1: int (int pipe, int msg)
	OP_SMSG_OUT_1,
	/// Recieve message 1: int (int pipe)
	OP_RMSG_OUT_1,
	/// Send message 2: int (int pipe, int msg)
	OP_SMSG_OUT_2,
	/// Recieve message 2: int (int pipe)
	OP_RMSG_OUT_2,
	/// Send message 1: int (int pipe, int msg)
	OP_SMSG_IN_1,
	/// Recieve message 1: int (int pipe)
	OP_RMSG_IN_1,
	/// Send message 2: int (int pipe, int msg)
	OP_SMSG_IN_2,
	/// Recieve message 2: int (int pipe)
	OP_RMSG_IN_2,
	/// Test for source node: bool ()
	OP_IS_SOURCE,
	/// Test for sink node: bool ()
	OP_IS_SINK,
	//@}

	/// {\Large Control operations}
	//@{
	/// If: int (bool cond, int if, int then)
	OP_IF,
	/// While: int (bool cond, int loop)
	OP_WHILE,

	// {\Large Logic operations}
	/// Logical and: bool (bool a, bool b)
	OP_AND,
	/// Logical or: bool (bool a, bool b)
	OP_OR,
	/// Logical not: bool (bool a)
	OP_NOT,
	/// Less than: bool (int a, int b)
	OP_LT,
	/// Equal to: bool (int a, int b)
	OP_EQ,
	/// Returns true always: bool ()
	OP_TRUE,
	//@}

	/// {\Large Variable operations}
	//@{
	/// Variable 1: int ()
	OP_VAR_1,
	/// Variable 2: int ()
	OP_VAR_2,
	/// Variable assignment int (int val, bool dest)
	OP_ASSN_VAR,
	//@}

	/// {\Large Arithmetic operations}
	//@{
	/// The number 1: int ()
	OP_DATA_INT,
	/// Addition: int (int a, int b)
	OP_ADD_INT,
	/// Subtraction: int (int a, int b)
	OP_SUB_INT,
	/// Multiplication: int (int a, int b)
	OP_MUL_INT
	//@}
};

/// This knows about all operators and types and can create them based on enums
/*@Doc: This class contains all of the information about the
  operators.  If is is necessary to change the operators then the
  enumeration {\tt oper\_enum} and {\tt NUM\_OPERATORS} need to be
  changed, then the tables in this class need to be updated to reflect
  the new operator mix.  Finally the functionality needs to be changed
  in the model. */
class GOperatorTable : public GObject
{
	/// Table containing information about the number of children
	static int num_children[NUM_OPERATORS];

	//@Man: types[NUM_OPERATORS][MAX_CHILDREN+1]
	//@Type: static type_enum
	//@Memo: Table containing information about the child types
	static type_enum types[NUM_OPERATORS][(MAX_CHILDREN+1)];

	/// The names of the operators
	static char *names[NUM_OPERATORS];

	/// Table associating operator name with conditionality
	static int cond_type[NUM_OPERATORS];

public:
	/// Returns number of known operators 
	int GetNumOperators()
	{
		return NUM_OPERATORS;
	}

	/// Returns number of children, -1 if bad operator 
	int GetNumChildren(oper_enum op)
	{
		if(op >= 0 && op < NUM_OPERATORS)
			return num_children[op];
		else
			return -1;
	}

	/// Returns name of operator 
	char *GetName(oper_enum op)
	{
		if(op >= 0 && op < NUM_OPERATORS)
			return names[op];
		else
			return NULL;
	}

	/// Returns required child type 
	type_enum GetChildType(oper_enum op, int child_id)
	{
		if((op >= 0 && op < NUM_OPERATORS) &&
		   (child_id >= 0 && child_id < MAX_CHILDREN))
      
			return types[op][child_id+1];
		else
			return TYPE_INVALID;
	}

	/// Returns the type enumeration value 
	type_enum GetType(oper_enum op)
	{
		if(op >= 0 && op < NUM_OPERATORS)
			return types[op][0];
		else
			return TYPE_INVALID;
	}

	/// Returns 1 if a conditional 0 otherwise, -1 if bad operator 
	int CondType(oper_enum op)
	{
		if(op >= 0 && op < NUM_OPERATORS)
			return cond_type[op];
		else
			return -1;
	}
};

/// Global table to allow creation and verification of operators
extern GOperatorTable optable;

#endif // __OPTABLE_NET1_H