/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package sumulationsecondlab.New;

import java.util.LinkedList;


public class SingleServerqQueue {
  State s;
  EventList FutureEventList;
  WaitingList Customers;

 public static final int ARRIVAL = 1, DEPARTURE = 2, STOP = 3;
 public static double Clock, LastEventTime,TotalBusyTime, TotalResponseTime;
 public static long  TotalCustomers, NumberOfDepartures,MaxQueueLength;

    public SingleServerqQueue() {

      Initialization();
      simulate();
      ReportGeneration();

    }

public static void main(String[] args){

    new SingleServerqQueue();


}

public void Initialization()   {
    s=new State();
    FutureEventList = new EventList();
    Customers = new WaitingList();
    TotalCustomers  = 1000;
    Clock = 0.0;
    s.queueLength = 0;
    s.serverStatus = 0;;
    LastEventTime = 0.0;
    TotalBusyTime = 0.0 ;
    MaxQueueLength = 0;
    TotalResponseTime = 0.0;
    NumberOfDepartures = 0;
    // create first arrival event
    Event evt = new Event(ARRIVAL, nextArrivalTime());
    FutureEventList.insert( evt );
 }
public void simulate()
{

     while(NumberOfDepartures < TotalCustomers ) {
        Event evt = FutureEventList.pop();  // get the imminent event
        Clock = evt.eventTime;              // advance simulation time
        if( evt.eventType == ARRIVAL )
            ProcessArrival(evt);
        else
            ProcessDeparture(evt);
        }
   }

 public void ProcessArrival(Event evt) {
  Customers.add(evt);
  s.queueLength++;
  // if the server is idle, fetch the event, do statistics
  // and put into service
  if(s.serverStatus == 0)
      ScheduleDeparture();
  else
      TotalBusyTime += Clock - LastEventTime;  // server is busy

  // adjust max queue length statistics
  if (MaxQueueLength < s.queueLength)
      MaxQueueLength = s.queueLength;

  // schedule the next arrival
  Event next_arrival = new Event(ARRIVAL, nextArrivalTime());
  FutureEventList.insert( next_arrival );
  LastEventTime = Clock;
 }

 public  void ScheduleDeparture() {
  Event depart = new Event(DEPARTURE,nextServiceTime());
  FutureEventList.insert(depart);
  s.serverStatus = 1;
  s.queueLength--;
 }

public void ProcessDeparture(Event e) {
 // get the customer description
 Event finished = (Event) Customers.remove();
 // if there are customers in the queue then schedule
 // the departure of the next one
  if( s.queueLength > 0 )
      ScheduleDeparture();
  else
      s.serverStatus = 0;
  TotalResponseTime += Clock - finished.eventTime;
  TotalBusyTime += Clock - LastEventTime ;
  NumberOfDepartures++;
  LastEventTime = Clock;
 }

public static void ReportGeneration() {
double serverUtilization   = (TotalBusyTime/Clock)*100; //server busy time in percent
double avgResponseTime  = TotalResponseTime/TotalCustomers;

System.out.println( "\tNumber of Customers Served        " + TotalCustomers );
System.out.println( "\tServer Utilization                   " + serverUtilization+"%" );
System.out.println( "\tMaximum Queue Length                     " + MaxQueueLength );
System.out.println( "\tAverage Response Time  " +avgResponseTime+"minutes");

System.out.println( "\tSimulation Run Length        " + Clock + " minutes" );
System.out.println( "\tNumber of Departures     " + NumberOfDepartures );
}



 protected double nextArrivalTime(){
           return Clock+1+Math.random()*6;
    }
protected double nextServiceTime(){
           return Clock+1+Math.random()*4;
    }


}
class Event{
    public double eventTime;
    public int eventType;

    public Event(int type, double time)
    {
    this.eventType = type;
    this.eventTime = time;
    }
}

class EventList extends LinkedList {


    public EventList() {
    }

    public void insert(Event e){
        int index=-1;

            for(int i=0;i<size();i++){
            if(e.eventTime<(double)((Event)get(i)).eventTime)
            {
                index=i;
                break;
            }
        }
        if(index==-1)
            addLast(e);
        else
            add(index,e);
        }

    public Event pop() {
        Event e=(Event)remove();

        return e;
    }


}

class State{
   int queueLength, serverStatus;
   public State(){
   queueLength=0;
   serverStatus=0;
   }

}

class WaitingList extends LinkedList {

       public WaitingList() {
    }

}

