///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Copyright (C) 2006 by Intel Coproration and Carnegie Mellon University    //
// Contacts: casey.j.helfrich @ intel.com                                    //
//           bdr @ cs.cmu.edu                                                //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "GradientHierarchy.hxx"

#include "CatomSim.hxx"
#include "CatomWorld.hxx"

using namespace std;

GradientMsg::GradientMsg(GradientHierarchy* _hierarchy) :
  Message(_hierarchy->gradientBox) { }

GradientMsg::GradientMsg(MailboxID _mailboxID) :
  Message(_mailboxID) { }

GradientHierarchy::GradientHierarchy(catomID _hostCatom, string _hierarchyName) :
  Hierarchy(_hostCatom, _hierarchyName),
  gradientBox("_gradient_" + _hierarchyName),
  upstreamFeature(0),
  isRoot(false) { }

GradientHierarchy::~GradientHierarchy() { }

void GradientHierarchy::simulationStart() {
  Hierarchy::simulationStart();

  worldPtr->catomHash[hostCatom]->C.mailboxManager.registerHandler(gradientBox,
								   this,
								   (msgHandlerPtr)&GradientHierarchy::gradientHandler);
}

bool GradientHierarchy::gradientHandler(Message* _msg) {
  if(!isRoot && (upstreamFeature == 0)) {
    upstreamFeature = _msg->arrivalContact;

    // Propagate the gradient
    for(unsigned int i=1; i<=NUM_FEATURES; i++) {
      Feature* contact = &((worldPtr->catomHash[hostCatom]->C.getFeatureMap())[i]);
      contact->getNetworkAdapter()->sendMessage(new GradientMsg(this));
    }
  }

  return false;
}

void GradientHierarchy::emitGradient() {
  isRoot = true;
  for(unsigned int i=1; i<=NUM_FEATURES; i++) {
    Feature* contact = &((worldPtr->catomHash[hostCatom]->C.getFeatureMap())[i]);
    contact->getNetworkAdapter()->sendMessage(new GradientMsg(this));
  }
}

bool GradientHierarchy::sendMsgToParent(Message* msg) {
  if(isRoot) {
    // Root doesn't need to send anything to the parent
    delete msg;
    return false;
  } else if (upstreamFeature == 0) {
    delete msg;
    return false;
  } else {
    Feature* contact = &((worldPtr->catomHash[hostCatom]->C.getFeatureMap())[upstreamFeature]);
    return contact->getNetworkAdapter()->sendMessage(msg);
  }
}
