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

#include "TestAggregation.hxx"

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

CODE_MODULE_DECLARATION( TestAggregation, TestAggregation, "TestAggregation" );
CODE_MODULE_DECLARATION( TestAggregation2, TestAggregation, "TestAggregation2" );


using namespace std;

TestAggregation::TestAggregation(catomID _hostCatom, string _hierarchyName) 
  : TESTAGG_SUPER(_hostCatom, _hierarchyName) 
  , testAggregationBox("TestAggregationBox_" + _hierarchyName) 
{ signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 
  myAggregateValue = random();
  lastAggregateReceived = -1;
}

TestAggregation::~TestAggregation() { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__);  }

void TestAggregation::simulationStart() { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 
  TESTAGG_SUPER::simulationStart();
  
  worldPtr->catomHash[hostCatom]->C.mailboxManager.registerHandler(testAggregationBox,
								   this,
								   (msgHandlerPtr)&TestAggregation::aggMessageHandler);
}

bool TestAggregation::aggMessageHandler(Message* _msg) { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 
  TestAggregationMsg* msg = (TestAggregationMsg*)_msg;
	
  map<catomID,void*>::const_iterator childDataEntry = childData.find(msg->from);
  TestAggregationChildData* theChildData = ((TestAggregationChildData*)((childDataEntry == childData.end()) ? NULL : (*childDataEntry).second));
  
  if(theChildData) {
    theChildData->value = msg->value;
    theChildData->weight = msg->weight;
    lastAggregateReceived = worldPtr->current_time;
  }
  
  delete msg;
  return true;
}

void TestAggregation::sendAggToParent() { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 
  double ourVal = myAggregateValue;
  unsigned long ourWeight = 1;
  
  map<catomID, void*>::iterator childDataIterator = childData.begin();
  while(childDataIterator != childData.end()) {
    TestAggregationChildData* theChildData = ((TestAggregationChildData*) (*childDataIterator).second);
    
    ourVal += theChildData->value * theChildData->weight;
    ourWeight += theChildData->weight;
    
    childDataIterator++;
  }
  
  ourVal /= ourWeight;
  
  TestAggregationMsg* msg = new TestAggregationMsg(testAggregationBox, hostCatom, ourVal, ourWeight);
  if(!sendMsgToParent(msg)) {
    worldPtr->oStart();
    cerr << worldPtr->current_time << " root " << hostCatom << "(level " << level << ") emits aggregate value " << ourVal << " (weight " << ourWeight << ")\n";
    //cerr << "    Peers count: " << peers.size() << endl;
    worldPtr->oEnd();
  }
}

void* TestAggregation::newChildDataObject() { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 
  return new TestAggregationChildData();
}

void TestAggregation::endTick() { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 
  if(((worldPtr->current_time >= 100) && ((worldPtr->current_time) % 25 == 0)) ||
     ((lastAggregateReceived != -1) && (worldPtr->current_time - lastAggregateReceived == 3)))
    sendAggToParent();
  
  if(getParent() == 0) {
    worldPtr->catomHash[hostCatom]->C.setColor(255, 0, 255, 0);
  } else {
    worldPtr->catomHash[hostCatom]->C.setColor(0, 0, 0, 255);
  }
  
  TESTAGG_SUPER::endTick();
}
