/* xtype.cc */

#include "xtype.h"
#include "symbol.h"

bool xtype::operator==( const xtype &xt ) const {
  if( subT != xt.subT ) return false;

  /* types with units must not return true from this switch block.  they must
     oass through to unit check below */
  switch( subT ) {
  case Rect_Matrix_t : case Vector_t : case Triple_t :
    if( inf.dim[0] != xt.inf.dim[0] || inf.dim[1] != xt.inf.dim[1] ) 
      return false;
  case Symbol_t :
    if( inf.svec == no_svec || xt.inf.svec == no_svec ) return true;
    return inf.svec == xt.inf.svec;
  default :;
  }
  if( has_units() ) return uv == xt.uv;
  return true;
}

xtype &xtype::operator=( const xtype &xt ) {
  T = xt.T;
  subT = xt.subT;

  switch( T ) {
  case Matrix_t :
    inf.dim[0] = xt.inf.dim[0];
    inf.dim[1] = xt.inf.dim[1];
  case Symbol_t :
    inf.svec = xt.inf.svec;
  default :;
  }

  if( has_units() ) uv = xt.uv;
  return *this;
}

bool xtype::has_units( void ) const {
  switch( T ) {
  case Int_t : case Matrix_t : case Real_t :
    return true;
  default : 
    return false;
  }
}

bool castable( cxtype from, cxtype to ) {
  /* types with units must not return true from this switch block.  they must
     oass through to unit check below */
  switch( from.T ) {
  case Int_t :
    switch( to.T ) {
    case Int_t : case Real_t : break;
    default : return false;
    }
    break;
  case Matrix_t :
    if( to.T != Matrix_t ) return false;
    break;
  case Real_t :
    if( from.subT != to.subT && to.subT != Distrib_t ) return false;
    break;
  case Symbol_t :
    if( to.T != Symbol_t || ( from.inf.svec != no_svec && 
			      from.inf.svec != to.inf.svec ) ) 
      return false;
    break;
  default : if( from.T != to.T ) return false;
  }
  
  /* assumes a non-united type is not castable to a united type or vice-versa */
  if( from.has_units() ) {
    return( from.uv == to.uv );
  }
  return true;
}

ostream &operator<<( ostream &stream, cxtype xt ) {
  switch( xt.subT ) {
  case Symbol_t :
    if( xt.inf.svec == no_svec ) {
      stream << "<nil> ";
    } else {
      stream << sb.svec_string( xt.inf.svec ) << " ";
    }
    break;
  default : ;
  }
  stream << dc_type_string[xt.subT];
  switch( xt.subT ) {
  case Rect_Matrix_t :
    stream << "( " << xt.inf.dim[0] << ", " << xt.inf.dim[1] << " )";
    break;
  case Vector_t :
    stream << "( " << xt.inf.dim[0] << " )";
    break;
  default : ;
  }
  if( xt.has_units() ) {
    stream << xt.uv;
  }
  return stream;
}
