/* shape.h */

#ifndef SHAPE__H
#define SHAPE__H

#include "data.h"
#include <coriolis/kernel.h>
#include "cor_syn_iface.h"
#include "view3d.h"

struct dc_shape;

/* one shape_core kept for each coriolis object.  then several dc_shapes can
   reference it, and temporary createion/deletion do not create addition
   coriolis objects */
class dc_shape_core {
private:
  list_item global_loc; /* location in global list of shapes */
  int nrefs; /* number of references to this */
  dc_view *V;

protected:
  RigidBody rbody;

  string shape_fname;
  triple scale; 

  void add_ref( void ) { nrefs++; }
  void remove_ref( void ) { if( !( --nrefs ) ) delete( this ); }

public:
  dc_shape_cor( void );

  bool set( cstring shapefile, ctriple scale );
  bool set( dc_shape_core &S ) { return set( S.shape_fname, S.scale ); }  

  color disp_color;

  void draw( void ) const;

  friend struct dc_shape;
};

/* dc_shape
   - is a coriolis shape and body associated with a component
   - coriolis pipes will look for an element with name equal to the string 
   coriolis_shape_label defined in cor_syn_iface.h with return type
   Shape_t.
   - shapes are initialized with a filename along with parent and label
   - shapes will be invalid if the file does not exist or if it is not a valid
   shape file */
class dc_shape : public dc_data {
protected:
  dc_shape_core *shape;

public:
  dc_shape( void );
  dc_shape( cstring shapefile, ctriple scale );
  dc_shape( cstring shapefile, ctriple scale, 
	    cstring label, dc_component *paremt = nil );
  ~dc_shape();

  /* if shapefile is not a valid shapefiles, this will become invalid, and true 
     will be returned */
  bool set( cstring shapefile, ctriple scale );
  bool set( const dc_shape &S );

  /* inherited functions */
  const dc_type type( void ) const { return Shape_t; }
  string type_string( void ) const { return string( "%sshape", 
						    valid ? "" : "invalid " ); }

  Shape *get_shape( void ) { return shape ? shape->rbody.shape : nil; }

  /* do not delete or unset_geometry or remove from bodysystem */
  RigidBody *get_rbody( void ) { return shape ? &( shape->rbody ) : nil; }

  void draw( void ) const { if( shape ) shape->draw(); }

  ostream &display_c( ostream & = cout ) const;
  ostream &display( ostream &stream = cout ) { return display_c( stream ); }

  dc_label *duplicate( dc_node *parent ) const;
};

inline ostream &operator<<( ostream &stream, const dc_shape &S ) { 
  return S.display_c( stream ); }

/* - for every shape_core s will call op( s, vp ). s must not be deleted by op.
   - check for validity in op using dc_common::is_valid() if necessary */
void forall_shapes( void op( dc_shape_core &, void * ), void* = nil );

#endif
