/***************************************************************************
*   Copyright (C) 2006 by Intel and Carnegie Mellon                       *
*   Contacts: bdr@cs.cmu.edu                                              *
***************************************************************************/

#include "Ellipsis.hxx"

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

CODE_MODULE_DECLARATION( Ellipsis, Ellipsis, "Ellipsis" );
CODE_MODULE_DECLARATION( Ellipsis2, Ellipsis, "Ellipsis2" );

using namespace std;

void EllipsisChildData::add(EllipsisChildData otherData) { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 
	n += otherData.n;
	sx += otherData.sx;
	sy += otherData.sy;
	sz += otherData.sz;
	sxx += otherData.sxx;
	sxy += otherData.sxy;
	sxz += otherData.sxz;
	syy += otherData.syy;
	syz += otherData.syz;
	szz += otherData.szz;
}

string EllipsisChildData::toString() { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 
	ostringstream str;

	str << sx  << " "
			<< sy  << " "
			<< sz  << " "
			<< sxx << " "
			<< sxy << " "
			<< sxz << " "
			<< syy << " "
			<< syz << " "
			<< szz << " "
			<< n;
	return str.str();
}

Ellipsis::Ellipsis(catomID _hostCatom,  string _hchyName) :
  DPRHierarchy(_hostCatom, _hchyName),
  ellipsisBox("EllipsisBox" + _hchyName),
  lastAggregateReceived(-1) { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 

}

void Ellipsis::simulationStart() { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 
  Hierarchy::simulationStart();
  
  worldPtr->catomHash[hostCatom]->C.mailboxManager.registerHandler(getHierarchyName() + ellipsisBox,
								   this,
								   (msgHandlerPtr)&Ellipsis::aggMessageHandler);
}

void Ellipsis::simulationEnd() { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 
	dumpEllipses();

	DPRHierarchy::simulationEnd();
}

void Ellipsis::dumpEllipses() { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 
	// Calculate our ellipse
	// (yanked from sendAggToParent below)
	Point3D myLoc = worldPtr->catomHash[hostCatom]->C.getLocation();
	double my_x = myLoc.getX();
	double my_y = myLoc.getY();
	double my_z = myLoc.getZ();
	EllipsisChildData aggregatedData(1,
					 my_x, my_y, my_z,
					 my_x*my_x, my_x*my_y, my_x*my_z,
					 my_y*my_y, my_y*my_z,
					 my_z*my_z);
	
	map<catomID, void*>::iterator childDataIterator = childData.begin();
	while(childDataIterator != childData.end()) {
		EllipsisChildData* theChildData = ((EllipsisChildData*) (*childDataIterator).second);
		aggregatedData.add(*theChildData);
		childDataIterator++;
	}
	worldPtr->oStart();

	cerr << "ellipse " << getLevel() << " " << aggregatedData.toString() << endl;

	worldPtr->oEnd();
}

void Ellipsis::aggMessageHandler(Message* _msg) { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 
	EllipsisMsg* msg = (EllipsisMsg*)_msg;
	
	map<catomID,void*>::const_iterator childDataEntry = childData.find(msg->from);
	EllipsisChildData* theChildData = ((EllipsisChildData*)((childDataEntry == childData.end()) ? NULL : (*childDataEntry).second));
	
	if(theChildData) {
		(*theChildData) = msg->data;
		lastAggregateReceived = worldPtr->current_time;
	}
	
	delete msg;
}

void Ellipsis::sendAggToParent() { signpost dprdebug_block_signpost(__FILE__,__LINE__,__FUNCTION__); 	
	Point3D myLoc = worldPtr->catomHash[hostCatom]->C.getLocation();
	double my_x = myLoc.getX();
	double my_y = myLoc.getY();
	double my_z = myLoc.getZ();
	EllipsisChildData aggregatedData(1,
					 my_x, my_y, my_z,
					 my_x*my_x, my_x*my_y, my_x*my_z,
					 my_y*my_y, my_y*my_z,
					 my_z*my_z);

	map<catomID, void*>::iterator childDataIterator = childData.begin();
	while(childDataIterator != childData.end()) {
		EllipsisChildData* theChildData = ((EllipsisChildData*) (*childDataIterator).second);
		aggregatedData.add(*theChildData);
		childDataIterator++;
	}
	
	EllipsisMsg* msg = new EllipsisMsg(ellipsisBox, hostCatom, aggregatedData);
	sendMsgToParent(msg); // if this function returns false, that means we're the root
}

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

void Ellipsis::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();
  
  DPRHierarchy::endTick();
}
