// -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*-
/*
# Copyright (c) 2000-2001 by the University of Southern California.
# All rights reserved.
#
# Permission to use, copy, modify, and distribute this software and its
# documentation in source and binary forms for non-commercial purposes and
# without fee is hereby granted, provided that the above copyright notice
# appear in all copies and that both the copyright notice and this permission
# notice appear in supporting documentation, and that any documentation,
# advertising materials, and other materials related to such distribution and
# use acknowledge that the software was developed by the University of
# Southern California, Information Sciences Institute.  The name of the
# University may not be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THE UNIVERSITY OF SOUTHERN CALIFORNIA MAKES NO REPRESENTATIONS ABOUT THE
# SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS PROVIDED "AS
# IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
# LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE.
#
# Other copyrights might apply to parts of this software and are so noted when
# applicable.
# ----------------------------------------------------------------------------
#
# Primary author: Purushotham Kamath
#                 January 2001

#This material is based upon work supported by the Defense Advanced Research
#Projects Agency Information Technology Office, (NGI Multicast Applications 
#and Architecture (NMAA-ADDON), ARPA Order No. H645, Program Code No. 9A20, 
#Issued by DARPA/CMD under Contract No. MDA972-99-C-0022.
*/

#include <stdlib.h>
#include <stdio.h>
#include <eventhandler.h>
#include <packet.h>
#include <queue.h>
#include <component.h>
#include <scheduler.h>

extern Scheduler * sched;

Component::Component(int qsize)
{
	queue = new Queue(qsize);
	state = IDLE;
	next = NULL;
	prev = NULL;
}

Component::~Component()
{
	delete queue;
}


//Virtual function that decides the next component to send the packet to.
void Component ::nextnode( Packet *p)
{

}

//The main message handling function of the component class. 
//Usually called by the previous component in the list. The funtion checks 
//if the component is idle. If so it processes it. If not it puts
//the packet in the queue.

int Component::process(Packet *packet)
{
	dprintf("component.cc: Component::process(): Entered function\n");
	if(!(queue->enqueue(packet)))
	{
		dprintf("component.cc: Component::process(): Buffer overflow: Dropping packet\n");
		return 0;
	}


	if(state == IDLE) 
	{
		dprintf("component.cc: Component::process(): Packet id: %d\n", packet->id);
		dprintf("component.cc: Component::process(): Component idle, processing packet.\n");
		//Implements the processing time 
		dprintf("component.cc: Component::process(): Scheduling delay: %.12f\n", latency);
		if (latency != 0)
		{
			state = BUSY;
			sched->scheduleevent(this);
		}
		else
			handleevent();

	}
	else
	{
		dprintf("component.cc:Component:process(): Packet id: %d\n", packet->id);
		dprintf("component.cc:Component::process(): Component busy, queueing packet.\n");
	}
	return state;
}

void Component::dumpstats()
{
	queue->dumpstats();
}


//Connects two components to form a list.
void couple(Component *c1, Component *c2)
{
	c1->next = c2;
	c2->prev = c1;
}


//Processing function of the component. Will be called either when a message
//arrives (and the component is idle) or if there is a packet in the queue 
//awaiting processing.

void Component::handleevent()
{
	dprintf("res.cc: Component::handleevent(): Entered function\n");

	Packet *p = queue->dequeue();

	dprintf("res.cc: Component::handleevent(): Packet id: %d\n", p->id);
	dprintf("res.cc: Component::handleevent(): Packet processing complete, passing it on to the next component.\n");
	nextnode(p);
	Component::next->process(p);
	if(queue->head != NULL)
	{
		dprintf("res.cc: Component::handleevent(): Processing next packet in queue.\n");
		//Implements the processing time 
		state = BUSY;
		sched->scheduleevent(this);
	}
	else 
	{
		state = IDLE;
		dprintf("res.cc: Component::handleevent(): No more packets to process.\n");
	}

}


