/***
* Switch1.java v1.0 - Discrete Event Simulation of a single mobile
* radio base station in Java
*
*       Copyright (c) 2009-, Dr Adrian Muscat. All rights reserved.
*
*       This code can be used for academic and non-commerial research
*       and academic activities only.
*
* Purpose:
*       This file calculates the blocking probability in a single
*       mobile radio base station
****/

import java.io.*;
import java.util.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;


class Main
{
    private static Random myRandom = new Random();
    private static SimulationPara SimTime=new SimulationPara();
    private static List EventList=new List();

    public static void main(String[] args)
    {
        Resource ACell=new Resource(3);
        double MaxTime=1500;
        ListItem NewEvent=new ListItem(SimTime.EventSequence,
                SimTime.NOW, 1, null);
        EventList.AddEventToList(NewEvent);

        while(EventList.HeadOfList!=null && SimTime.NOW<MaxTime)
        {
            SimTime.NOW=EventList.HeadOfList.TimeOfEvent;
            switch (EventList.HeadOfList.EventType) {
                    case 1: EventRoutineArrival(ACell); break;
                    case 2: EventRoutineBeginService(ACell); break;
                    case 3: EventRoutineEndService(ACell); break;
                    default: System.out.println("Invalid Event Type");break;
            }
        //EventList.DisplayList();
        //System.out.println();
        }

        EventList.DisplayList();
        ACell.DisplayStatistics();
    }

    private static void EventRoutineArrival(Resource Server)
    {
        //Generate Next Arrival
        ListItem NextArrival=new ListItem(SimTime.EventSequence++,
                SimTime.NOW+InterArrivalTime(5), 1, null);
        EventList.AddEventToList(NextArrival);
        //Schedule Begin Service event
        Server.CallsAttempted++;
        ListItem NewEvent=new ListItem(SimTime.EventSequence++,
                SimTime.NOW, 2, null);
        EventList.AddEventToList(NewEvent);
        //Remove First Item From List
        EventList.RemoveFirstItem();
    }

    private static void EventRoutineBeginService(Resource Server)
    {
        if (Server.Status<Server.MaxNoChn){
            //there exists a free resource
            Server.Status++;
            ListItem NewEvent=new ListItem(SimTime.EventSequence++,
                SimTime.NOW+ServiceTime(5), 3, null);
            EventList.AddEventToList(NewEvent);
        }
        else {
            //No free resources; Block Call
            Server.CallsBlocked++;
        }
        EventList.RemoveFirstItem();
    }

    private static void EventRoutineEndService(Resource Server)
    {
        Server.CallsServiced++;
        Server.Status--;
        EventList.RemoveFirstItem();
    }
    
    private static double InterArrivalTime(double a)
    {
        double x;
        x=myRandom.nextDouble()*a;
        return x;
    }

    private static double ServiceTime(double a)
    {
        double x;
        x=myRandom.nextDouble()*a;
        return x;
    }
} //end class main
//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////
class SimulationPara
{
    double NOW;
    int EventSequence;

    SimulationPara()
    {
        NOW=0.0;
        EventSequence=0;
    }
} //end class SimulationPara
//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////
class Resource
{
    int Status;
    int MaxNoChn;
    int CallsAttempted;
    int CallsServiced;
    int CallsBlocked;

    Resource(int NoOfChannels){
        Status=0;
        MaxNoChn=NoOfChannels;
        CallsAttempted=0;
        CallsServiced=0;
        CallsBlocked=0;
    }
    
    void DisplayStatistics(){
        System.out.println("Attempted = "+CallsAttempted);
        System.out.println("Serviced  = "+CallsServiced);
        System.out.println("Blocked   = "+CallsBlocked);
        System.out.println("Pb        = "
                +100.0*CallsBlocked/CallsAttempted+"%");
    }
} //end class Resource
//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////
class ListItem
{
    int EventNumber;
    double TimeOfEvent;
    int EventType;
    ListItem next;

    ListItem(int n, double t, int p, ListItem v)
    {
        EventNumber=n;
        TimeOfEvent=t;
        EventType=p;
        next=v;
    }
} //end class ListItem
//////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Class List
// This class takes care of the Event simulator List
// creation and maintenance
class List
{
    ListItem HeadOfList;
    int SizeOfList;

    List()
    {
        HeadOfList=null;
        SizeOfList=0;
    } //end List constructor

    void AddEventToList(ListItem NewEvent)
    {
        ListItem current=null, previous=null, following=null;

        if (HeadOfList==null){
            HeadOfList=NewEvent;
            NewEvent.next=null;
            SizeOfList++;
        }
        else if (NewEvent.TimeOfEvent<HeadOfList.TimeOfEvent){
            NewEvent.next=HeadOfList;
            HeadOfList=NewEvent;
            SizeOfList++;
        }
        else{
            current=HeadOfList;
            while(current!=null && NewEvent.TimeOfEvent>=current.TimeOfEvent){
                previous=current;
                current=current.next;
            }
            following=previous.next;
            previous.next=NewEvent;
            NewEvent.next=following;
            SizeOfList++;
        }
    } //end AddEventToList

    void RemoveFirstItem()
    {
        ListItem current=null, previous=null;

        if (HeadOfList!=null){
            previous=HeadOfList;
            HeadOfList=previous.next;
            SizeOfList--;
        }
    } //end RemoveFirstItem

    void DisplayList()
    {
       ListItem current=HeadOfList;
       NumberFormat myIFormat = new DecimalFormat("0000");
       NumberFormat myDFormat = new DecimalFormat("00000.00");

       System.out.println("Event List");
       if (HeadOfList==null){
           System.out.println("List is Empty");
       }
       else {
           System.out.println("Event Time   Type   Event #    ");
           while (current!=null )
           {
               System.out.println(myDFormat.format(current.TimeOfEvent)+"     "
                       +myIFormat.format(current.EventType)+"   "
                       +myIFormat.format(current.EventNumber));
               current=current.next;
           }
       }
    } //end DisplayList
    
} //end class List
///////////////////////////////////////////////////////////////////




