/* data.h */

#ifndef DATA__H
#define DATA__H

#include "id.h"
#include "xtype.h"

/* - the dc_data class is the base class for
   -   dc_boolean - see bool.h
   -   dc_string - see string.h
   -   dc_symbol - see symbol.h
   -   dc_udata - base for data types that require units.  see udata.h, units.h
   -     dc_int - see integer.h
   -     dc_matrix - base for data types that use newmat libs. see matrix.h
   -       dc_rect_matrix - see rmatrix.h
   -       dc_triple - see triple.h
   -       dc_vector - see vector.h
   -     dc_real - see real.h
   -       dc_distrib - see distrib.h
 */

class dc_data : public dc_label {
public:
  dc_data();

  const dc_type type( void ) const { return Generic_t; }
  string type_string( void ) const { return string( "generic data" ); }
  virtual void get_xtype( xtype &xt );

  /* defined as virtual in dc_label */
  const bool is_data( void ) const { return true; } 

  ostream &display( ostream &stream = cout );
  friend ostream &operator<<( ostream &stream, dc_data &D )
    { return D.display( stream ); }

  /* - all these ops delete temporaries */
  dc_data &operator=( dc_data &D ); /* assignment - will not delete this */
  /* arithmetic operations */
  dc_data &operator+( dc_data &D ); /* addition */
  dc_data &operator-( dc_data &D ); /* subtraction */
  dc_data &operator*( dc_data &D ); /* cross multiplication */
  dc_data &dot( dc_data &D ); /* dot product */
  dc_data &operator/( dc_data &D ); /* division */
  dc_data &operator%( dc_data &D ); /* modulus */
  /* arithmetic assignment operations */
  dc_data &operator+=( dc_data &D ); /* add and assign */
  dc_data &operator-=( dc_data &D ); /* subtract and assign */ 
  dc_data &operator*=( dc_data &D ); /* multiply and assign */
  dc_data &operator/=( dc_data &D ); /* divide and assign */
  /* logical operations */
  dc_data &operator!( void ); /* logical not */
  dc_data &operator&&( dc_data &D ); /* logical and */
  dc_data &operator||( dc_data &D ); /* logical or */
  dc_data &operator^( dc_data &D ); /* logical xor */
  /* equality operations */
  bool lessthan( dc_data &D );
  dc_data &operator==( dc_data &D ); /* equality */
  dc_data &operator!=( dc_data &D ); /* inequality */
  dc_data &operator<( dc_data &D ); /* less than */
  dc_data &operator<=( dc_data &D ); /* less than or equal to */
  dc_data &operator>( dc_data &D ); /* greater than */
  dc_data &operator>=( dc_data &D ); /* greater than or equal to*/
  /* conditional operator since ?: cannot be overloaded */
  dc_data &If( dc_data &Then, dc_data &Else ); /* conditional */
  /* magnitude operator */
  dc_data &mag( void ); /* magnitude */
  /* solve matrix equation Ax = B for x */
  dc_data &solve( dc_data &B ); /* this is &A */
  /* negation */
  dc_data &operator-( void );

  virtual const bool has_units( void ) const { return false; }
  
  /* assigns source to a generic dc_data *. reallocates space if necessary 
   dest must be nil or allocated */
  friend dc_data &assign( dc_data *&dest, dc_data &source );
};

inline dc_data &dot( dc_data &A, dc_data &B ) { return A.dot( B ); }
inline dc_data &solve( dc_data &A, dc_data &B ) { return A.solve( B ); }
inline dc_data &If( dc_data &I, dc_data &T, dc_data &E ) {
  return I.If( T, E ); 
}

/* does assignment without deleting any temporaries 
   returns true on failure. */
bool set_data( dc_data &dest, dc_data &src );

/* returns true if both have units and units are consistent.
   prints warning message and returns true if only one has units or if both do 
   and units are inconsistent.
   returns true without warning if neither have units */
bool check_units( const dc_data *d1, const dc_data *d2, 
		  const char *func_name = "check_units" );

/* returns true if both have quivalent units or no units, false otherwise */
bool equiv_units( const dc_data *d1, const dc_data *d2 );

/* returns a temporary and deletes d if it is temporary.
   returns nil if d is not castable to to. see castable in types.h */
dc_data *cast( dc_data &d, const dc_type to );


/* operations called by operators.  operators return references.  these return
   pointer and default value on failure */
dc_data *op_add( dc_data &, dc_data & );
dc_data *op_subtract( dc_data &, dc_data & );

/* - allocates a sub-class of dc_data corresponding to the given type
   - first version adds to hierarchy wth given label and parent.
   - second version will create a temporary */
dc_label *allocate( dc_type T, cstring label, dc_node *parent = nil );
dc_label *allocate( dc_type T );

#endif
