// field.C

#include "nodeInterface.H"
#include "world.H"
#include "file.H"

namespace xrml {

void field::init(field* ref)
{
  init((char *)ref->Id, (fieldValue&)ref->value, ref->do_assign);
  timestamp = ref->timestamp;
}

interfaceMember* field::clone(void)
{
  return new field(*this);
}

void field::instantiate(class SFNode*, class Proto *master)
{
  value.instantiate(master);
}

void field::assign_forward(const fieldValue& value)
{
  if (busy_forwarding) 
    return;
  busy_forwarding = true;

  for (forward_link_list* f=forward_links; f; f=f->next) {
    interfaceMemberRef* forward = (interfaceMemberRef*)(*f);
    forward->ref()->assign(forward->refnode, value);
  }

  busy_forwarding = false;
}

bool field::assign_here(SFNode *thisnode, const fieldValue& value)
{
  if (!check_type(value))
    return false;		// value type mismatch

  bool succes = true;
  if (do_assign) {
    succes = do_assign(thisnode, value);
  } else {	// PROTO interface members e.g. have no do_assign function.
    this->value.assign(value);
    thisnode->status = 1;
    thisnode->timestamp = timestamp = thisnode->world->time;
  }

  return succes;
}

bool field::assign(SFNode *thisnode, const fieldValue& value)
{
  if (timestamp > thisnode->world->time || busy_forwarding)	// don't assign old values
    return false;

  bool succes = assign_here(thisnode, value);
  assign_forward(value);
  return succes;
}

void field::initialize(SFNode *thisnode, const fieldValue& value)
{
  assign(thisnode, value);
}

ostream& field::print(ostream& s)
{
  return print_Id_value(s << "field       ");
}


//////////////////////////////////////////////////////////////////////////////

class fieldLink: public field, public link {
public:
  PoolDecl(fieldLink, "fieldLink")

  fieldLink(void) {};

  inline fieldLink(SFNode* thisnode, field *thisifm, SFNode *srcnode, field *srcifm)
  {
    field::init(thisifm);
    link::init(srcnode, srcifm, thisnode, thisifm);
    assign_here(thisnode, ref()->value);
  }

  virtual interfaceMember* clone(void) { return new fieldLink(*this); }

  virtual void instantiate(class SFNode* thisnode, Proto *master =0)
  {
    field::instantiate(thisnode, master);
    link::instantiate(master, thisnode, this);
    assign_here(thisnode, ref()->value);
  }

  virtual bool assign(SFNode *thisnode, const fieldValue& value)
  {
    return (!(dynamic_cast<field*>(ref()))->busy_forwarding) ?
      ref()->assign(refnode, value) : field::assign(thisnode, value);
  }

  virtual ostream& print(ostream& s)
  {
    field::print(s);
    link::print(s);
    return s
      << ' '
      << ref()->value
      << (ref()->timestamp > timestamp ? " (to be updated)" : " (up to date)");
  }
};

interfaceMember* field::link_field(SFNode *thisnode, SFNode* node, field* ifm)
{
  return new fieldLink(thisnode, this, node, ifm);
}

PoolImpl(field)
PoolImpl(fieldLink)

} // namespace xrml

