/* pipe_iface.h */

#ifndef PIPE_IFACE__H
#define PIPE_IFACE__H

#include "types.h"
#include <LEDA/basic.h>
#include "agent_circuit.h"

struct dc_pipe;
struct dc_data;
struct dc_component;

/* indices into table */
enum cpipe_type { undef_cpt = 0, mass_cpt = 1, position_cpt, orientation_cpt,
		  force_cpt, torque_cpt, vel_cpt, omega_cpt,
		  /* circuit pipe types */
#ifdef COMPILE_AGENT_CIRCUIT
		  circ_dV,
		  circ_I,
		  circ_Q,
		  circ_Res,
		  circ_Cap,
		  circ_Ind,
		  circ_dVMax,
		  circ_dVMin,
		  circ_IMax,
		  circ_IMin,
		  circ_VZn,
		  circ_Spd,
		  circ_kI,
		  circ_kV,
		  circ_On,
		  circ_Y,
		  circ_Ig,
		  circ_Nu,
		  circ_T,
		  circ_TMax,
		  circ_TMin,
#endif
		  /* finish */
		  NUM_CPT };

/* - allocates and returns a dc_pipe corresponding to label 
   or nil if no match or parent fails validity_fn
   - also attaches to whatever clocks are necessary if any.
   - be careful with pipes constructed without this function since some get/set
   functions typecast pipes.  example( get_velocity expects a dc_cor_pipe
*/
dc_pipe *alloc_pipe( const string &label, dc_component *parent );

/* a valid_pfn returns valid if the given component( may be nil ) is valid for 
   the pipe type it corresponds to */
typedef bool ( *valid_pfn )( dc_component * );

/* a set_pfn sets the object piped to with the data given.  
   returns true on error, false otherwise */
typedef bool ( *set_pfn )( dc_pipe &, dc_data & );

/* queries the object refered to by pipe and returns a dc_data * of the type
   given in pipe_entry.rtype.  returns nil on error */
typedef dc_data *( *get_pfn )( dc_pipe & );

struct pipe_entry {
  const char *const name;
  const valid_pfn valid; /* true if valid given parent */
  /* given a pipe, set whatever object it pipes to with the relevant value.  
     true on error */
  const set_pfn set;
  /* given a pipe, return the value that should be set to the pipe */
  const get_pfn get;
  const dc_type rtype; /* return type for this type of pipe */

  pipe_entry( const char *const Name, const valid_pfn Vfn, const set_pfn Set_fn,
	      const get_pfn Get_fn, dc_type RType )
    : name(Name), valid(Vfn), set(Set_fn), get(Get_fn), rtype(RType) {;}
};

/* VALIDITY FNS */
inline bool is_invalid_pfn( dc_component * ) { return false; }
bool is_physical_pfn( dc_component *parent );

/* PIPE SET FNS */
bool cor_set_mass( dc_pipe &, dc_data & );
bool cor_set_X( dc_pipe &, dc_data & );
bool cor_set_Q( dc_pipe &, dc_data & );
bool cor_set_F( dc_pipe &, dc_data & );
bool cor_set_T( dc_pipe &, dc_data & );
bool cor_set_V( dc_pipe &, dc_data & );
bool cor_set_U( dc_pipe &, dc_data & );

/* PIPE GET FNS */
dc_data *cor_get_mass( dc_pipe & );
dc_data *cor_get_X( dc_pipe & );
dc_data *cor_get_Q( dc_pipe & );
dc_data *cor_get_F( dc_pipe & );
dc_data *cor_get_T( dc_pipe & );
dc_data *cor_get_V( dc_pipe & );
dc_data *cor_get_U( dc_pipe & );

/* must be same order as cpipe_type defs since cpipe_types are indices into this
   table.  names should be all lowercase if parser is case insensitive */
const pipe_entry pipe_table[NUM_CPT] = 
{ pipe_entry( "invalid", is_invalid_pfn, nil, nil, Undef_t ),
  pipe_entry( "mass", is_physical_pfn, cor_set_mass, cor_get_mass, Real_t ),
  pipe_entry( "position", is_physical_pfn, cor_set_X, cor_get_X, Triple_t ),
  pipe_entry( "orientation", is_physical_pfn, cor_set_Q, cor_get_Q, Vector_t ),
  pipe_entry( "force", is_physical_pfn, cor_set_F, cor_get_F, Triple_t ),
  pipe_entry( "torque", is_physical_pfn, cor_set_T, cor_get_T, Triple_t ),
  pipe_entry( "velocity", is_physical_pfn, cor_set_V, cor_get_V, Triple_t ),
  pipe_entry( "omega", is_physical_pfn, cor_set_U, cor_get_U, Triple_t )
  /* circuit stubs */
#ifdef COMPILE_AGENT_CIRCUIT
, pipe_entry( dc_agent_circuit::info_name[0],
	      is_circuit_pfn, cir_set_dV,    cir_get_dV, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[1],
	      is_circuit_pfn, cir_set_I,     cir_get_I, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[2],
	      is_circuit_pfn, cir_set_Qheat, cir_get_Qheat, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[3],
	      is_circuit_pfn, cir_set_Res,   cir_get_Res, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[4],
	      is_circuit_pfn, cir_set_Cap,   cir_get_Cap, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[5],
	      is_circuit_pfn, cir_set_Ind,   cir_get_Ind, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[6],
	      is_circuit_pfn, cir_set_dVMax, cir_get_dVMax, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[7],
	      is_circuit_pfn, cir_set_dvMin, cir_get_dvMin, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[8],
	      is_circuit_pfn, cir_set_IMax,  cir_get_IMax, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[9],
	      is_circuit_pfn, cir_set_IMin,  cir_get_IMin, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[10],
	      is_circuit_pfn, cir_set_VZn,   cir_get_VZn, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[11],
	      is_circuit_pfn, cir_set_Spd,   cir_get_Spd, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[12],
	      is_circuit_pfn, cir_set_kI,    cir_get_kI, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[13],
	      is_circuit_pfn, cir_set_kV,    cir_get_kV, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[14],
	      is_circuit_pfn, cir_set_On,    cir_get_On, Boolean_t ),
  pipe_entry( dc_agent_circuit::info_name[15],
	      is_circuit_pfn, cir_set_Y,     cir_get_Y, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[16],
	      is_circuit_pfn, cir_set_Ig,    cir_get_Ig, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[17],
	      is_circuit_pfn, cir_set_Nu,    cir_get_Nu, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[18],
	      is_circuit_pfn, cir_set_T,     cir_get_T, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[19],
	      is_circuit_pfn, cir_set_TMax,  cir_get_TMax, Real_t ),
  pipe_entry( dc_agent_circuit::info_name[20],
	      is_circuit_pfn, cir_set_TMin,  cir_get_TMin, Real_t ),
#endif
};


#endif
