/* Proto.C */

#include "xrmlP.H"

namespace xrml {

PoolImpl(Proto)

bool IsProto(SFNode *node)
{
  return dynamic_cast<Proto*>(node) != 0;
}

void Proto::Proto_construct(SFNode *m, MFNode *sg, const namedNodeTable& nn, const protoTable& pts)
{
  nrInterfaceMembers = m->nrInterfaceMembers;
  interface = m->interface;
  master = m;
  sceneGraph = sg;
  namedNodes = nn;
  protos = pts;
  parent = 0;
}

Proto::Proto(SFNode *m, MFNode *sg, const namedNodeTable& nn, const protoTable& pts)
{
  SFNode::construct(m->typeId);
  Proto_construct(m, sg, nn, pts);
}

void Proto::clone_interface(const SFNode& src)
{
  SFNode::clone_interface(src);
  for (int i=0; i<nrInterfaceMembers; i++) {
    if (is_field(interface[i]) || is_eventOut(interface[i]))
      interface[i]->value.duplicate();	// duplicate objects pointed to
  }
}

void Proto::clone(const SFNode& src)
{
  SFNode::construct(src.typeId);
  clone_interface(src);
}

void Proto::destruct(void)
{
  //  master->destruct();	// also destructs interface
  delete sceneGraph;
}

Proto::Proto(const Proto& src)
{
  clone(src);
}

Proto& Proto::operator=(const Proto& src)
{
  if (this != &src) {
    destruct();
    clone(src);
  }
  return *this;
}

Proto::~Proto()
{
  destruct();
}

void Proto::instantiate_implementation(Proto *master)
{
  this->parent = master;
  this->master = this;	// all references to PROTO interface must point
                        // to this node's interface

  namedNodes = master->namedNodes;	// doesn't copy the nodes
  for (int i=0; i<namedNodes.size; i++) {
    // temporarly let namedNodes[i] behave as a "normal" unnamed 
    // node, because otherwise, instantiate() would just return the 
    // (uninitialised) SFNode * in namedNodes[i]. 
    // See SFNode::instantiate().
    SFNode* namednode = master->namedNodes[i];
    int savedIndex = namednode->nameIndex; namednode->nameIndex = -1;
    const char *saveNameId = namednode->nameId;    namednode->nameId = 0;
    namedNodes[i] = namednode->instantiate(this);
    namedNodes[i]->nameIndex = namednode->nameIndex = savedIndex; // == i
    namedNodes[i]->nameId = namednode->nameId = saveNameId;
  }

  protos = master->protos;    // doesn't copy the nodes and doesn't need to

  if (master->sceneGraph) {
    // named nodes are replaced by their instance in the namedNodes table
    sceneGraph = master->sceneGraph->instantiate(this);
  }
}

SFNode *Proto::instantiate(Proto *enclosing_proto)
{
  Proto *instance = new Proto(*this);
  instance->instantiate_interface(enclosing_proto);
  instance->instantiate_implementation(this);
  return instance;
}

SFNode *Proto::firstnode(void)
{
  if (!sceneGraph || sceneGraph->size <= 0)
    return this;	// return something meaningful
  else
    return (*sceneGraph)[0]->firstnode();
}

void Proto::render(void)
{
  if (sceneGraph) {
    sceneGraph->render();
  }
}

ostream& Proto::print(ostream& s)
{
  SFNode::print(s) << '\n';
  if (sceneGraph)
    s << *sceneGraph << " # end " << typeId << '\n';
  else 
    s << "# no proto scene graph\n";
  return s;
}


} // namespace xrml
