/* shape.cc */

#include "shape.h"
#include "simple3d.h"
#include "body_def.h"

static list<dc_shape_core *> shape_list;

dc_shape_core::dc_shape_core( void ) {
  global_loc = shape_list.append( this );
  disp_color = black_col;
  V = new dc_view( "", rbody.x );
  nrefs = 0;
}

dc_shape_core::~dc_shape_core( void ) {
  if( rbody.bs != nil ) rbody.bs->remove( rbody );
  if( rbody.shape ) {
    if( rbody.shape->user_data != nil ) /* get rid of triple array used in
					   draw_shape */
      delete( rbody.shape->user_data );
    delete( rbody.unset_geometry() );
  }

  /* delete here in case coriolis doesn't */
  if( rbody.entity_name ) {
    delete( rbody.entity_name );
    rbody.entity_name = nil;
  }

  if( V ) delete( V );
  
  shape_list.del_item( global_loc );
}

bool dc_shape_core::set( cstring shapefile, ctriple Scale ) {
  cerr << "SETTING SHAPE_CORE " << shapefile << "\n";

  shape_fname = shapefile;
  V->set_label( shape_fname );

  /* set entity name of rbody */
  int len = shape_fname.length();
  if( rbody.entity_name ) delete( rbody.entity_name );
  rbody.entity_name = new char[ len + 1 ];
  for( int i = 0 ; i < len ; i++ ) {
    rbody.entity_name[i] = shape_fname[i];
  }
  rbody.entity_name[len] = '\0';

  scale = Scale;
 
  if( rbody.shape ) {
    if( rbody.bs ) rbody.bs->remove( rbody );
    delete( rbody.unset_geometry() );
  }

  Shape *shape = load_shape( shape_fname, scale(0), scale(1), scale(2),
			     shape_fname );
  if( shape != nil ) {
    rbody.set_geometry( *shape );
    universe.add( rbody );
  } else {
    return true;
  }

  return false;
}

void dc_shape_core::draw( void ) const {
  if( rbody.shape ) 
    draw_shape( *( rbody.shape ), disp_color );
}

dc_shape::dc_shape( void ) {
  shape = nil;
  valid = false;
}

dc_shape::dc_shape( cstring shapefile, ctriple Scale ) {
  shape = new dc_shape_core();
  shape->add_ref();
  valid = !shape->set( shapefile, Scale );
}

dc_shape::dc_shape( cstring shapefile, ctriple Scale, cstring label, 
		    dc_component *parent = nil ) {
  shape = new dc_shape_core();
  shape->add_ref();
  valid = !shape->set( shapefile, Scale );
  set_both( label, parent );
}

dc_shape::~dc_shape( void ) {
  if( shape ) shape->remove_ref();
}

bool dc_shape::set( cstring shapefile, ctriple scale ) {
  if( shape ) {
    shape->remove_ref();
  }

  shape = new dc_shape_core();
  shape->add_ref();
  valid = !shape->set( shapefile, scale );
  return !valid;
}

bool dc_shape::set( const dc_shape &S ) {
  if( shape ) shape->remove_ref();
  shape = S.shape;
  valid = S.valid;
  if( shape ) shape->add_ref();
  return !valid;
}

ostream &dc_shape::display_c( ostream &stream = cout ) const {
  if( shape ) {
    if( !valid ) stream << "invalid ";
    stream << "shape \"" << shape->shape_fname << "\"";
    if( shape->scale != triple( 1, 1, 1 ) ) {
      stream << " * triple" << shape->scale;
    }
  } else {
    stream << "invalid shape";
  }
  return stream;
}

dc_label *dc_shape::duplicate( dc_node *parent ) const {
  dc_shape *dupe = new dc_shape;
  if( shape ) dupe->set( *this );

  if( !is_temporary() ) {
    if( dupe->set_both( local_label(), parent ) ) {
      delete( dupe );
      return nil;
    }
  }
  dupe->set_visible( is_visible() );
  return ( dc_label * )dupe;
}

void forall_shapes( void op( dc_shape_core &, void * ), void *vp ) {
  dc_shape_core *s;
  forall( s, shape_list ) {
    op( *s, vp );
  }
}

