// -*- 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 <stdio.h>
#include <stdlib.h>
#include <math.h>

#include <eventhandler.h>
#include <packet.h>
#include <queue.h>
#include <component.h>
#include <scheduler.h>
#include <ipport.h>
#include <opport.h>
#include <debug.h>


extern Scheduler * sched;
extern int numIPPorts;
extern int numOPPorts;
extern OPPort **op;
extern IPPort **ip;




OPPort::OPPort(int qsize, char *opfile): Component(qsize), drops(0)
{
fout = fopen(opfile, "w");
//Output port delay

//The latency will be calculated dynamically for each packet based on packet size and linespeed
//Latency = Packet size in bits/ Line speed in bps
//We fill a default value here based on packet size = 1500 bytes and linespeed = 10Gbps
//Latency = 1500 * 8 / 10 *10^9 = 1.2 usecs
latency =1.2E-6;

}

OPPort::~OPPort()
{
fclose(fout);
}

//The OPPOrt message handling function: It queues the packet, checks if the port is busy, processes it if not.
int OPPort::process(Packet  *packet)
{
dprintf("res.cc: OPPort::process(): Entered function\n");
dprintf("res.cc: OPPort::process(): Scheduling delay: %.12f\n", latency);
if(!(queue->enqueue(packet)))
{
         dprintf("res.cc: OPPort::process(): Buffer overflow: Dropping packet\n");
         return 0;
}
return maybe_service(packet );
}

// service a new packet on the queue, if any
// returns state of the queue
int OPPort::maybe_service(Packet *packet)
{
if (state == IDLE)
        {
         dprintf("res.cc: OPPort::maybe_service(): Packet id: %d\n", packet->id);
         dprintf("res.cc: OPPort::maybe_service(): OPPort idle, processing packet.\n");
         //Implements the processing time

         latency = ((packet->size) * 8) / (linespeed); //Delay in terms of secs
         dprintf("res.cc: OPPort::maybe_service(): Packet size: %d\n", packet ->size);
         dprintf("res.cc: OPPort::maybe_service(): Linespeed: %f\n", linespeed);
         dprintf("res.cc: OPPort::maybe_service(): Scheduling delay: %.12f\n", latency);
         if (latency != 0)
         {
                 state = BUSY;
#ifdef SCHEDULING_PRIORITY
                 priority = EH_HIGH;
#endif
                 sched->scheduleevent(this);
         }
         else
                 handleevent();
}
else
{

         dprintf("res.cc: OPPort::maybe_service(): Packet id: %d\n", packet->id);
         dprintf("res.cc: OPPort::maybe_service(): OPPort busy, queuing packet.\n");

}
return state;
}



//The OPPort event handling fucntion: Dequeues a packet, processes it,
//checks if an input interface is waiting and schedules it if it is.
void OPPort::handleevent()
{

dprintf("res.cc: OPPort::handleevent(): Entered function\n");

Packet *p = queue->dequeue();
dprintf("res.cc: OPPort::handleevent(): Packet id: %d\n", p->id);
dprintf("res.cc: OPPort::handleevent(): Packet processing complete.\n");
dprintf("res.cc: OPPort::handleevent(): Dumping output.\n");

fprintf(fout, "%.12f %d:%d %d %d %d %d %d\n", sched->currenttime, p->ipport ,p->id, p->srcaddr, p->srcport, p->dstaddr, p->dstport, p->size);
dprintf("res.cc: OPPort::handleevent(): Dumping output.\n");
delete p;
fflush(fout);

	if(queue->head != NULL)
	{
		state = IDLE;  // done servicing, but maybe_service() might push us back to busy
		maybe_service(queue->head);
	}
	else 
		state = IDLE;

}

void OPPort::dumpstats()
{
printf("res.cc: OPPort::dumpstats(): Number of packets dropped: %d\n", drops);
Component::dumpstats();
}
