/**************************************************************
 * You can modify the template of this file in the
 * directory ..\JCreator\Templates\Template_1\Project_Name.java
 *
 * You can also create your own project template by making a new
 * folder in the directory ..\JCreator\Template\. Use the other
 * templates as examples.
 */

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.lang.Math;

class Nets2
{


	//________Parameters for simulation
	public static double alpha=.6;
	public static double beta=.8;
	static int N=10000; // ___Each source
	public static int buffers=N*4+1; //____N+1 for infinite buffers___

	public static double peakrates[]=new double[4];
	public static double averagerates[]=new double[4];
	
	public static double servicerate=60;
	
	
	static boolean commentary=false;

	//_______Other vars____
	public static double at[][]=new double[N+2][4];
	public static double st[]=new double[N*4+2];
	public static double tcat[][]=new double[N+2][4];
	public static double cat[]=new double[N*4+2];
	
	public static double cdt[]=new double[N*4+2];
	public static double idt[]=new double[N*4+2];
	public static int ql[]=new int[N*4+2];
	public static double tql=0;
	public static double pclock=0;
	public static int pql=0;
	public static double talpha,tbeta;

	public static int in,out;
	public static double nat,ndt,clock,dif;
	
	public static int customers_dropped=0;
	
	
	public Nets2()
	{
		
	}
	

	public static void main(String args[])
	{
		
/*		if(args.length==3)
		{
			alpha=Double.parseDouble(args[0]);
			beta=Double.parseDouble(args[1]);
			buffers=Integer.parseInt(args[2]);
		}
		
		print("\nAlpha : " + alpha + "\nBeta : " + beta + "\nMaximum Queue Length : " + buffers+ " \n \n");*/
		
		
		

		
		peakrates[0]=5000; averagerates[0]=.3;
		peakrates[1]=5000; averagerates[1]=.3;
		peakrates[2]=5000; averagerates[2]=.3;
		peakrates[3]=5000; averagerates[3]=.3;
		servicerate=1.3;
		buffers=16;


		if(args.length<=10 && args.length>=9)
		{
		
			int i;
			for(i=0;i<4;i++)
				peakrates[i]=Double.parseDouble(args[i]);
			for(i=0;i<4;i++)
				averagerates[i]=Double.parseDouble(args[i+4]);
				
			servicerate=Double.parseDouble(args[8]);
	
		}
	
		buffers=N*4+1;
		if(args.length==10)
			buffers=Integer.parseInt(args[9]);

			if(buffers==-1)
				buffers=N*4+1;
				
				
		

		
		beta=servicerate;
		alpha=averagerates[0]+averagerates[1]+averagerates[2]+averagerates[3];
		
		print("\nInput Data\n---------------");
		for(int i=0;i<4;i++)
		{
			print("\nSource : " +i + "\nPeak rate : " + peakrates[i] + "   Average rate : " + averagerates[i]);
		}

		print("\nNet Arrival Rate : " + alpha + "\nService Rate : " + beta + "\nMaximum Queue Length : " + ((buffers==N*4+1) ? "Infinite" : (new Integer(buffers).toString()) ) + " \n \n");
		print("\n \n \nStarting Simulation");

		//____Computer at and st
		Random rnd=new Random();
		int i,j;
		double maxat=0;
		
		
		for(j=0;j<4;j++)
		{
			tcat[0][j]=0;
	
		for(i=1;i<=N;i++)
		{
			
			at[i][j]=1.0/peakrates[j]+rnd.nextDouble()*(2.0/averagerates[j]-2.0/peakrates[j]);
			
			if(i==1)
				at[1][j]=0;
				
			tcat[i][j]=tcat[i-1][j]+at[i][j];
		
	
			if(tcat[i][j]>maxat)
				maxat=tcat[i][j]+1;
		}
		
		}
		
		
		//print("maxat : " + maxat);
		cat[0]=0;
		
		//_____Merge the cat from 4 arrays_________
		
		int p[]=new int[4];
		p[0]=p[1]=p[2]=p[3]=1;
		
		double min;
		int minj;
		min=maxat;minj=0;
		for(i=1;i<=N*4;i++)
		{

				min=maxat;
			
			for(j=0;j<4;j++)
			{
				if(p[j]<=N && tcat[p[j]][j]<min)
				{
					minj=j;
					min=tcat[p[j]][j];
				}
			}			
			

			cat[i]=min;
			p[minj]++;			
			
			idt[i]=ql[i]=0;
			st[i]=1.0/servicerate;

		}
				
		N=N*4;
		
		/*print("printing cats");
		for(i=1;i<=N;i++)
			print(" " + cat[i]);
		*/	
		
		//System.exit(0);

		
		in=2; out=1;
		nat=cat[2];
		ndt=cdt[1]=st[1];
		clock=0;
		
		//_____Start the simulation____
		
		if(commentary)
			print("Arrival at : 0");
		while(out<=N)
		{
			if(in<=N) //______still arrivals are left
			{
				dif=nat-ndt; //__see arrival or departure ?
				if(dif<0) //___arrival
				{
					if(commentary)
						print("Arrival at : " + nat);

					if(ql[in-1]>=buffers)
					{
						if(commentary)
							print("Customer dropped !");
						
						customers_dropped++;
						st[in]=0;
						ql[in]=buffers;
						
					}
					else
						ql[in]=in-out;

		tql+=pql*(clock-pclock);
					
					pclock=clock;
					pql=in-out-1;
											
					clock=nat;
					nat=cat[in+1];
					
					in++;
					continue;
				}
				else if(dif>0) //____departure
				{
					if(in-out>1) //___queue is not empty
					{
					
							tql+=pql*(clock-pclock);
					
					pclock=clock;
					pql=in-out-1;
					
						clock=ndt;
					if(commentary && !iszero(st[out]))
						print("Departure at : " + clock);
						


						cdt[out+1]=cdt[out]+st[out+1];
						ndt=cdt[out+1];
						out++;
					}
					else //___queue is empty
					{
						idt[in]=dif;

						if(commentary && !iszero(st[out]))
						
							print("Departure at : " + ndt);


		tql+=pql*(clock-pclock);
					
					pclock=clock;
					pql=in-out-1;
					
						clock=nat;
						if(commentary)
						{
							print("Server is idle for : " + dif);
							print("Arrival at : " + clock);
						}


						nat=cat[in+1];
						cdt[out+1]=cat[in]+st[out+1];
						ndt=cdt[out+1];
						out++;
						in++;
					}
				}
				else if(iszero(dif))
				{
						ql[in]=ql[in-1];
					
					
							tql+=pql*(clock-pclock);
					
					pclock=clock;
					pql=in-out-1;
					
						clock=nat;

						if(commentary)
						{

							if(!iszero(st[out]))
								print("Departure at : " + clock);
							print("Arrival at : " + clock);
						}
						
						nat=cat[in+1];
						cdt[out+1]=cat[in]+st[out+1];
						ndt=cdt[out+1];
						out++;
						in++;
				
				}
			}
			else //___All arrivals have exhausted
			{
				
						tql+=pql*(clock-pclock);
					
					pclock=clock;
					pql=in-out-1;
					
				clock=ndt;
				if(commentary && !iszero(st[out]))
					print("Departure at : " + clock);

				cdt[out+1]=cdt[out]+st[out+1];
				ndt=cdt[out+1];
				out++;
			}
				
		}

		//____Print statistics
		
		
		print("Simulation Finished");

		double tot_waiting,max_waiting,tot_idle,tot_time;
		int non_zero_ele,que_len,max_que;
		
		que_len=max_que=ql[1];
		tot_waiting=max_waiting=cdt[1]-cat[1]-st[1];
		if(st[1]==0)
			tot_waiting=max_waiting=0;
		
		tot_time=cdt[1]-cat[1];
		if(st[1]==0)
			tot_time=0;
		
		tot_idle=idt[1];
		non_zero_ele=0;

		for( i = 2;i<=N;i++)
		{
			que_len+=ql[i];
			if(max_que<ql[i])
				max_que=ql[i];
				
			if(ql[i]!=0)
				non_zero_ele++;
			tot_idle+=idt[i];
		
			double ttime=cdt[i]-cat[i];
			if(st[i]==0)
				ttime=0;
			tot_time+=ttime;
			
			//____Don't add waiting times for dropped packets
			double wtime=cdt[i]-cat[i]-st[i];
			if(st[i]==0) 
				wtime=0;
			tot_waiting+=wtime;
			
			if(max_waiting<(wtime))
			max_waiting=wtime;
		}


		printtheory(tot_time,que_len,tot_waiting);

		print(" ");
		print(" ");

		print("\nOther statistics");
		print("---------------------");
		System.out.println("The average length of a non-empty queue is " + (((double)(que_len))/non_zero_ele));
		System.out.println("The maximum length of a queue is "+max_que);
		System.out.println("The maximum waiting time of a customer is " + max_waiting);
		System.out.println("The total idle time of the server is " + tot_idle);
		System.out.println("No. of Packets dropped are : " + customers_dropped);
		
		System.out.flush();

	}
				
	
	static void print(String s)
	{
		System.out.println(s);
		System.out.flush();
				

	}
	
	static boolean iszero(double d)
	{
		if(d<0.0001)
			return true;
			
		return false;
	}
	
	static void printtheory(double tot_time,int que_len,double tot_waiting)
	{
		double ro=alpha/beta;
		print("\n \n \nResults");
		print("--------------------");
		print("Average time spent by a customer (delay)");
		print("Theoretical : " + 1.00/(beta-alpha) + " Simulation Result : " + (tot_time/(N-customers_dropped)));
		print("Average queue length");
	//	print("Theoretical : " + ro*ro/(1-ro)+ " Simulation result : " + (((double)(que_len))/N));
			print("Theoretical : " + ro*ro/(1.0-ro)+ " Simulation result : " + tql/pclock);

		print("Average Waiting time");
		print("Theoretical : " + ro/(beta-alpha) + " Simulation result : " + (tot_waiting/(N-customers_dropped)));
		
	
		
	}
	
						
		
	
}

				
					
			
					
					

				
			
			
			
		
		
			
	
