// file: $isip/class/dstr/BiGraphArc/BiGraphArc.h
// version: $Id: BiGraphArc.h 9038 2003-03-10 16:46:41Z alphonso $
//

// make sure definitions are only made once
//
#ifndef ISIP_BIGRAPH_ARC
#define ISIP_BIGRAPH_ARC

// isip include files
//
#ifndef ISIP_BOOLEAN
#include <Boolean.h>
#endif

#ifndef ISIP_DOUBLE
#include <Double.h>
#endif

#ifndef ISIP_CONSOLE
#include <Console.h>
#endif

// forward class definitions:
//  we must define the BiGraphVertex class here first because the header files
//  might be short-circuited by the ifndef.
//
template<class TObject> class BiGraphArcDiagnose;
template<class TObject> class BiGraphVertex;

#ifndef ISIP_BiGraph_VERTEX
#include <BiGraphVertex.h>
#endif

// BiGraphArc: a generic arc in a BiGraph. the main purpose of an arc is
// to connect two BiGraph vertices.
//
template<class TObject>
class BiGraphArc {

  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:
  
  // define the class name
  //
  static const String CLASS_NAME;

  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------  
  
  static const String DEF_PARAM;

  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------

  // default values
  //
  
  // default arguments to methods
  //
  static const double DEF_WEIGHT = 0.0;
  static const boolean DEF_EPSILON = false;
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  
  
  static const long ERR = 41000;
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // vertex we are pointing to
  //
  BiGraphVertex<TObject>* vertex_d;
  
  // weight for the edge
  //
  Double weight_d;
  
  // is this an epsilon transition
  //
  Boolean is_epsilon_d;
  
  // declare a static debug level for all class instantiations
  //
  static Integral::DEBUG debug_level_d;

  // define the memory manager
  //
  static MemoryManager mgr_d;
  
  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:

  // static methods:
  //  diagnose method is moved outside the class header file and
  //  defined in the BiGraphArcDiagnose.h in order to avoid issues
  //  with preprocessing of the diagnose code.
  //
  static const String& name();

  // method: setDebug
  //
  static boolean setDebug(Integral::DEBUG level) {
    debug_level_d = level;
    return true;
  }

  // other debug methods
  //
  boolean debug(const unichar* message) const;
    
  // method: destructor
  //
  ~BiGraphArc() {
    clear(Integral::RESET);
  }
  
  // default constructor
  //
  BiGraphArc(BiGraphVertex<TObject>* = (BiGraphVertex<TObject>*)NULL,
	   double weight = DEF_WEIGHT, boolean is_epsilon = DEF_EPSILON);

  // copy constructor
  //  
  BiGraphArc(const BiGraphArc<TObject>& copy_arc);
  
  // method: assign
  //
  boolean assign(const BiGraphArc<TObject>& copy_arc) {
    return (setVertex(copy_arc.vertex_d) &&
	    setWeight(copy_arc.weight_d) &&
	    setEpsilon(copy_arc.is_epsilon_d));
  }

  // method: operator=
  //
  BiGraphArc<TObject>& operator=(const BiGraphArc<TObject>& arg) {
    assign(arg);
    return *this;
  }

  // method: eq
  //  determines if the endpoint, weights and epsilon settings of the
  //  respective arcs are equivalent.
  //
  boolean eq(const BiGraphArc<TObject>& compare_arc) const {
    return ((vertex_d->eq(*compare_arc.vertex_d)) &&
	    (weight_d.almostEqual(compare_arc.weight_d)) &&
	    (is_epsilon_d.eq(compare_arc.is_epsilon_d)));
  }

  // i/o methods:
  //  these methods are not needed since BiGraph takes care of it's own i/o.
  //

  // method: new
  //
  void* operator new(size_t size) {
    return mgr_d.get();
  }

  // method: new[]
  //
  void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: delete
  //
  void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }

  // method: delete[]
  //
  void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }

  // method: setGrowSize
  //  
  static boolean setGrowSize(long grow_size) {
    return (mgr_d.setGrow(grow_size));
  }

  // other memory management methods:
  //  
  boolean clear(Integral::CMODE cmode = Integral::DEF_CMODE);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  vertex get and set methods
  //
  //---------------------------------------------------------------------------

  // method: getVertex
  //
  BiGraphVertex<TObject>* getVertex() const {
    return vertex_d;
  }
  
  // method: setVertex
  //
  boolean setVertex(BiGraphVertex<TObject>* dest) {
    vertex_d = dest;
    return true;
  }

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  arc weight get and set methods
  //
  //---------------------------------------------------------------------------

  // method: getWeight
  //
  double getWeight() const {
    return (double)weight_d;
  }
  
  // method: setWeight
  //
  boolean setWeight(double weight) {
    weight_d = weight;
    return true;
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  arc epsilon get and set methods
  //
  //---------------------------------------------------------------------------

  // method: getEpsilon
  //
  boolean getEpsilon() const {
    return (boolean)is_epsilon_d;
  }
  
  // method: setEpsilon
  //
  boolean setEpsilon(boolean is_epsilon = DEF_EPSILON) {
    is_epsilon_d = is_epsilon;
    return true;
  }

  // method: containsData
  //  does this arc have any information that needs to be written to a file?
  //
  boolean containsData() const {
    return ((is_epsilon_d != DEF_EPSILON) ||
	    (vertex_d->getParentBiGraph()->isWeighted()));
  }

  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

  // friend class
  //
  template <class TObject_diagnose> 
  friend class BiGraphArcDiagnose;
};

//-----------------------------------------------------------------------------
//
// we define non-integral constants at the end of class definition for
// templates (for non-templates these are defined in the default constructor)
//      
//-----------------------------------------------------------------------------

// constants: required constants such as the class name
//
template <class TObject>
const String BiGraphArc<TObject>::CLASS_NAME(L"BiGraphArc");

template <class TObject>
const String BiGraphArc<TObject>::DEF_PARAM(L"arc");

// static instantiations: debug level and memory manager
//
template<class TObject>
Integral::DEBUG BiGraphArc<TObject>::debug_level_d = Integral::NONE;

template <class TObject>
MemoryManager BiGraphArc<TObject>::mgr_d(sizeof(BiGraphArc<TObject>), CLASS_NAME);

//-----------------------------------------------------------------------------
//
// below are all the methods for the BiGraphArc template class
//      
//-----------------------------------------------------------------------------

//----------------------------------------------------------------------
//
// required static methods
//
//----------------------------------------------------------------------

// method: name
//
// arguments: none
//
// return: a static String& containing the class name
//
// this method returns the class name
//
template<class TObject>
const String& BiGraphArc<TObject>::name() {

  // create the static name string for this class and return it
  //
  static String cname(CLASS_NAME);
  cname.clear(Integral::RESET);
  cname.concat(CLASS_NAME);
  cname.concat(L"<");
  cname.concat(TObject::name());
  cname.concat(L">");

  // return the name
  //
  return cname;
}

//----------------------------------------------------------------------
//
// required debug methods
//
//----------------------------------------------------------------------

// method: debug
//
// arguments:
//  const unichar* message: (input) information message
//
// return: a boolean value indicating status
//
// this method dumps the contents of an object to the console
// 
template<class TObject>
boolean BiGraphArc<TObject>::debug(const unichar* message_a) const {

  // declare local variables
  //
  String output;
  String val;
  
  Console::increaseIndention();

  // dump the this pointer
  //
  val.assign(this);
  output.debugStr(name(), message_a, L"this", val);
  Console::put(output);

  // dump the internal item if it exists
  //
  vertex_d->getItem()->debug(L"item");
  
  // dump a pointer to the destination vertex
  //
  val.assign(vertex_d);
  output.debugStr(name(), message_a, L"vertex_d", val);
  Console::put(output);
  
  // dump the weight
  //
  val.assign(weight_d);
  output.debugStr(name(), message_a, L"weight_d", val);
  Console::put(output);

  // dump the epsilon flag
  //
  val.assign(is_epsilon_d);
  output.debugStr(name(), message_a, L"is_epsilon_d", val);
  Console::put(output);

  Console::decreaseIndention();
  
  // exit gracefully
  // 
  return true;
}

//------------------------------------------------------------------------
//
// required destructor/constructor(s)
//
//-----------------------------------------------------------------------

// method: default constructor
//
// arguments:
//  BiGraphVertex<TObject>* vertex: (input) the endpoint vertex
//  double weight: (input) the arc weight
//  boolean is_epsilon: (input) is this arc an epsilon transition
//
// return: none
//
// this is the default constructor for the BiGraphArc class
//
template<class TObject>
BiGraphArc<TObject>::BiGraphArc(BiGraphVertex<TObject>* vertex_a, double weight_a,
			    boolean is_epsilon_a) {

  // initialize data
  //
  vertex_d = (BiGraphVertex<TObject>*)NULL;
  weight_d = DEF_WEIGHT;
  is_epsilon_d = DEF_EPSILON;
 
  // set the class data
  //
  setVertex(vertex_a);
  setWeight(weight_a);
  setEpsilon(is_epsilon_a);
  
  // exit gracefully
  //
}

// method: copy constructor
//
// arguments:
//  const BiGraphArc<TObject>& copy_arc: (input) the arc to copy
//
// return: none
//
// this is the copy constructor for the BiGraphArc class
//
template<class TObject>
BiGraphArc<TObject>::BiGraphArc(const BiGraphArc<TObject>& copy_arc_a) {

  // initialize data
  //
  vertex_d = (BiGraphVertex<TObject>*)NULL;
  weight_d = DEF_WEIGHT;
  is_epsilon_d = DEF_EPSILON;
 
  // call the copy assign method
  //
  assign(copy_arc_a);

  // exit gracefully
  //
}

//-------------------------------------------------------------------------
//
//  required clear methods
//
//-------------------------------------------------------------------------

// method: clear
//
// arguments:
//  Integral::CMODE cmode_a: (input) clear mode
//
// return: a boolean value indicating status
//
// this method clears the reference to the internal data.
// 
template<class TObject>
boolean BiGraphArc<TObject>::clear(Integral::CMODE cmode_a) {

  // clear the references to the data
  //
  weight_d = DEF_WEIGHT;
  is_epsilon_d = DEF_EPSILON;

  if (cmode_a != Integral::RETAIN) {
    vertex_d = (BiGraphVertex<TObject>*)NULL;
  }
  
  // exit gracefully
  // 
  return true;
}

// end of include file
//
#endif
