PROGRAM ServerSim2;

USES cs65;

TYPE
	AniBar = OBJECT
		yLow, yHigh, xHigh, CurrX : INTEGER;
		DrawColor, EraseColor : INTEGER;
		PROCEDURE Initialize(X, Y, Height, DColor, EColor : INTEGER);
		PROCEDURE Update(Size : INTEGER);
	END;
	
PROCEDURE AniBar.Initialize(AnchorX, AnchorY, Height, DColor, EColor : INTEGER);
BEGIN
	yLow := AnchorY;
	yHigh := AnchorY + Height;
	xHigh := AnchorX;
	DrawColor := DColor;
	EraseColor := EColor;
	CurrX := AnchorX;
END;

PROCEDURE AniBar.Update(Size : INTEGER);
VAR X : INTEGER;
BEGIN
	X := XHigh + Size;
	IF X < CurrX THEN {Bar must contract to left}
		BEGIN
			SetColor(EraseColor);
			Bar(X, yLow, CurrX, yHigh);
		END
	ELSE
		BEGIN		  {Bar must expand to right}
			SetColor(DrawColor);
			Bar(CurrX, yLow, X, yHigh);
		END;
	CurrX := X;
END;

FUNCTION Message : LONGINT;
VAR Event : REAL;
BEGIN
	Message := 0;
	Event := Random;
	IF Event < 0.05 THEN
		Message := 50 * (RandomInt(39) + 1);
END;

PROCEDURE Server(VAR PSize, MSize : LONGINT);
BEGIN
	IF PSize = 1000 THEN
		PSize := 0;
	PSize := PSize + 50;
	MSize := MSize - 50;
END;

FUNCTION DigitToChar(D : INTEGER) : Char;
{Converts a digit to a character (e.g. 3 becomes '3').  
  Numbers other than a single digit become an 'X' }
BEGIN
	IF (D > 9) OR (D < 0) THEN
		DigitToChar := 'X'
	ELSE
	    DigitToChar := CHR(D+48);
END;
	
PROCEDURE IntToStr( X, Width:INTEGER; VAR Result:STRING);
{Converts an Integer into a String suitable for outTextXY.  If X has
  fewer than Width digits, it is padded on the left with blanks.  If
  X has more than Width digits, Result will be whatever length is
  required to store the digits}
VAR Length,Digit, i, Index : INTEGER;
    tempStr : STRING;
BEGIN {IntToStr}
	{First decode digits into tempStr}
	Length := 0;
	IF X = 0 THEN
	    BEGIN
	        Length := 1;
	        tempStr := "0";
	    END
	ELSE WHILE X > 0 DO
	    BEGIN
	        Length := Length + 1;
	        Digit := X MOD 10;
	        TempStr[Length] := DigitToChar(Digit);
	        X := X DIV 10;
	    END;
	{Pad to appropriate width}
	WHILE Length < Width DO
	    BEGIN
	        Length := Length + 1;
	        TempStr[Length] := ' ';
	    END;
	{Copy into Reslt in reverse order}
	Index := 1;
	FOR i := Length DOWNTO 1 DO
	    BEGIN
	        Result[Index] := tempStr[i];
	        Index := Index + 1;
	    END;
	{Set length of Result}
	Result[0] := CHR(Length);
END; {IntToStr}

CONST Inc = 2.5;
	  Scale = 10;
	  MaxTicks = 1000;
	  
VAR MessFile, MessMax, LastMess, Tick, Packet : LONGINT;
VAR MessBar, MessFileBar, PacketBar, TickBar : AniBar;
VAR TickDisplay : INTEGER;
VAR Num : STRING;

BEGIN  {main program}

SetGraph;
ClrScr;

{Screen title and key display module}
OUTTEXTXY(220, 40, 'Internet Server Simulation');
OUTTEXTXY(465, 65, 'Display Color Key');
Line(420, 70, 626, 70);
Line(626, 70, 626, 148);
Line(626, 148, 420, 148);
Line(420, 148, 420, 70);
SetColor(4);
Bar(430, 80, 454, 104);
SetColor(0);
OUTTEXTXY(464, 96, 'Current Size');
Bar(430, 114, 454, 138);
OUTTEXTXY(464, 130, 'Maximum Size Attained');

{Incoming message display module}
New(MessBar);
MessBar.Initialize(10, 70, 50, 4, 0);
OUTTEXTXY(10, 65, 'Incoming Messages (in hundreds of characters)');
FOR TickDisplay := 0 TO 10 DO
	BEGIN
		IntToStr(TickDisplay*2, 2, Num);
		OUTTEXTXY((TRUNC(TickDisplay*200/Scale))+2, 143, Num);
		OUTTEXTXY((TRUNC(TickDisplay*200/Scale))+9, 130, '|');
	END;

{Message queue display module}
New(MessFileBar);
MessFileBar.Initialize(10, 310, 50, 4, 0);
OUTTEXTXY(10, 305, 'Message Queue (in thousands of characters)');
FOR TickDisplay := 0 TO 15 DO
	BEGIN
		IntToStr(TickDisplay, 2, Num);
		OUTTEXTXY((TRUNC(TickDisplay*1000/(Scale*Inc)))+2, 383, Num);
		OUTTEXTXY((TRUNC(TickDisplay*1000/(Scale*Inc)))+9, 370, '|');
	END;
	
{Packet processing display module}
New(PacketBar);
PacketBar.Initialize(10, 190, 50, 4, 15);
OUTTEXTXY(10, 185, 'Current Packet (in hundreds of characters)');
FOR TickDisplay := 0 TO 5 DO
	BEGIN
		IntToStr(TickDisplay*2, 2, Num);
		OUTTEXTXY((TRUNC(TickDisplay*200/Scale))+2, 263, Num);
		OUTTEXTXY((TRUNC(TickDisplay*200/Scale))+9, 250, '|');
	END;

{Run time tickbar display module}
New(TickBar);
TickBar.Initialize(0, 425, 25, 2, 1);
OUTTEXTXY(10, 420, 'Simulation Run Time');
OUTTEXTXY(1, 465, 'Start');
OUTTEXTXY(600, 465, 'Finish');

RANDOMIZE;

Packet := 0;
MessFile := 0;
MessMax := 0;

FOR Tick := 1 TO MaxTicks DO
	BEGIN
		IF ButtonPressed THEN HALT;  {Abort Button}
		LastMess := Message;
		MessFile := MessFile + LastMess;
		
		IF MessFile > 0 THEN
			Server(Packet, MessFile);
			
		TickBar.Update(TRUNC(Tick*640/MaxTicks));
		MessFileBar.Update(TRUNC(MessFile/(Scale*Inc)));
		PacketBar.Update(TRUNC(Packet/Scale));
		MessBar.Update(TRUNC(LastMess/Scale));
		
		Delay(500);
		
	END;
	
Pause;

END.