/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */

/* By Pablo Martin and Paula Ballester,
 * Strathclyde University, Glasgow.
 * June, 2003.
*/

/* Copyright (c) 2003 Strathclyde University of Glasgow, Scotland.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code and binary code must contain
 * the above copyright notice, this list of conditions and the following
 * disclaimer.
 *
 * 2. All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 * This product includes software developed at Strathclyde University of
 * Glasgow, Scotland.
 *
 * 3. The name of the University may not be used to endorse or promote
 * products derived from this software without specific prior written
 * permission.
 * STRATHCLYDE UNIVERSITY OF GLASGOW, MAKES NO REPRESENTATIONS
 * CONCERNING EITHER THE MERCHANTABILITY OF THIS SOFTWARE OR THE
 * SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE.  The software
 * is provided "as is" without express or implied warranty of any kind.
*/

#ifndef ns_ll_ue_h
#define ns_ll_ue_h

#include "marshall.h"
#include <connector.h>
#include <random.h>
#include <mac.h>

#include "packet.h"
#include "delay.h"
#include <queue.h>
#include "phy-umts.h"
#include "rlc-umts.h"
#include "fc-queue.h"
#include <ll.h>
#include <arp.h>
#include <classifier.h>
#include <lanRouter.h>
#include <varp.h>

/*************************** Timers *****************************/

class LLUE;
class AppsTimer : public Handler {
public:
	AppsTimer(LLUE* m, double s = 0) : ll(m), Next(0) {
		busy_ = paused_ = 0;stime = rtime = 0.0; flow_ = -1;}

	virtual void handle(Event *e);
	virtual void start(double time);
	virtual void stop(void);
	virtual void pause(void) { assert(0); }
	virtual void resume(void) { assert(0); }

	LLUE 		*ll;
  	int 		flow_;
	int		busy_;
	int		paused_;
	Event		intr;
	double	stime;	// start time
	double	rtime;	// remaining time
	AppsTimer* 	Next;
};

typedef AppsTimer* TimerPtr;

class TUEList
{ public:
  TUEList(LLUE* m) : ll(m) {
   	Head = new AppsTimer(ll); Tail=Head; CurrentPtr = Head;
  }
  ~TUEList();
  TimerPtr Previous(TimerPtr);
  void AddANode(int flow);
  void DeleteANode(TimerPtr);
  void DeleteANode(int flow);
  TimerPtr GetNode(int flow);

  void start(int flow, double time);
  void stop(int flow);

  LLUE *ll;
  TimerPtr Head,Tail,CurrentPtr;
};


///////////////////////////////////////////////////////////////////////////////
/*                             Class LLUE                                    */
///////////////////////////////////////////////////////////////////////////////


struct apps_info{
	int flowid_;		// flow id
	nsaddr_t dest_;		// IP address of node destiny
	int wait_;			// 0, the flow has asked for resources to the Node B
					// and is waiting for them; 1, resources allocated
	int sf_;			// spreading factor assigned to that application
	double rate_;		// physical rate of that application
	double user_rate_;	// rate coming from the applicatin
	double interval_;		// interval between the arrival of two packets
	Chan_Coding c_coding_;	// channel coding applied to that application
};

class LLUE : public LL {
	friend class AppsTimer;
	friend class TUEList;

public:
	LLUE();
	virtual void recv(Packet* p, Handler* h);
	virtual void switch_on(void);		// for switching ON the mobile
	virtual void update_flow(int acked, int fraged, int flowid);	// register a new flow in RLC layer
	virtual void configure_flow(int flow, const char*const& type , double rate);   // configure a new flow in RRC layer


protected:
	int command(int argc, const char*const* argv);

	int detect_flow(Packet* p);	// check if the packet received is part of a current application
	int insert_flow(int flow, double rate, Chan_Coding coding); // register a new application in RRC layer
	void remove_flow(Packet* p);	// remove resources allocated for a flow
	double get_rate(double rate, Chan_Coding code, int psize); // calculate the physical rate
	double get_bytes(int pos);	// bytes in ifq per tti
	void send_res_req(Packet* p, int i);	// send a resource request message
	void send_release_reply(Packet* p);  // for release procedure: send a release reply message
	void send_msg(Packet* p);	// send data packets received from the application to the IFQ
	void send_setup(void);	// for setup and handover procedures: send a setup request message
	void send_paging_ok(Packet* p);	// for paging procedure: send the paging response
	void update_phy_bytes_slot(void);	// calculate bytes per slot in physical layer and update them
	void AppsHandler(int flow);	// begin the release procedure

	int freq_;					// uplink frequence assigned to the UE
	int ue_address_;				// UE physical address
	int nodeb_address_;			// Node B physical address
	nsaddr_t ip_ue_;				// UE IP address
	nsaddr_t ip_nodeb_;			// Node B IP address
	int handover_;				// 1, UE in handover procedure

      int ue_state_;				// UE state, 0 OFF, 1 waiting to turn on, 2 ON
	apps_info apps_[MAX_NUM_FLOWS];	// information about applications in the UE

	PacketQueue* q_[MAX_NUM_FLOWS];	// Queue for bloquing flows until resource reply.
	PhyUmts* phy_;				// physical layer
	RlcUmts* rlc_;				// rlc layer
	FCQueue* ifq_;				// ifq

	static int verbose_;
	TUEList	*appstimer_;		// list of timers for detecting when an application
							// has finished

};

#endif
