(*
 
	Component :	ACCSUMM.PAS  --  Summarize usage
 
	Date:		January 13, 1980
			August 18, 1980		-- disk data from ACCDISKA.DAT
			August 27, 1980		-- no more ACCWOHST.NEW
			September 24, 1980	-- BIOMETRICS version
			October 21, 1980	-- Complete adjustments handled
 
	Author:		Tom Mathieu
			Battelle-Northwest
			Box 999
			Richland, Washington 99352
			(509) 375-3711
 
	Source:		Swedish Pascal
 
	Calling Seq:	RUN [11,1]ACCSUMM
 
	Inputs:		ACCOUNTS.DAT
			ACCTSSES.DAT
			ACCDISKA.DAT
 
	Outputs:	ACCTSSUM.DAT
 
	Comments:
*)

 
PROGRAM SUMMARY(TTY);		(***   System Utilization Summary Analysis   ***)
 
CONST	FDOY = 3;	(** FIRST DAY OF YEAR, 1=MON, ETC **)
	LEAPYEAR = 0;
 
TYPE	UIC   =  ARRAY [1..7] OF CHAR;
 
	SHIFT = (PRIME,DISC);
	WKO   = ARRAY [1..6] OF CHAR;
	ACCNM = ARRAY [1..9] OF CHAR;
 
	USEPTR = ^USAGE;
 
	USAGE = RECORD		(***   List of (uid,wko) users to be charged   ***)
		UACC : ACCNM;
		UID  : UIC;
		USED : BOOLEAN;
		USES : ARRAY [PRIME .. DISC] OF
			RECORD
			MIN,BAMIN : INTEGER;
			MCT,BAMCT,DISKB : REAL
			END;
		SUPPL : REAL;
		ADJST : REAL;
		NU : USEPTR
		END;
 
 
VAR	TF,LU,FU,PU : USEPTR;	TACC : ACCNM;
	F : TEXT;		ENDDT : WKO;
	TUIC : UIC;		MCTS,MAXD,R,TBLKS,DBLKS,PBLKS : REAL;
	CH,USETP : CHAR;	I,HR,J,NUSERS,LAPSE,NJ,AM,PM,MINS,L  : INTEGER;
	NOTFND   : BOOLEAN;	W : WKO;
	R1,R2,R3,R4 : REAL;	S:SHIFT;
 
	UIC1,UIC2 : ARRAY[1..3] OF CHAR;
	CH2	  : ARRAY[1..2] OF CHAR;
	DT	  : ARRAY[1..6] OF CHAR;
	FUFD	  : ARRAY[1..10] OF CHAR;
	DAYM	  : ARRAY[1..12] OF INTEGER;
 
	DREC : ARRAY [1..60] OF CHAR;
	TODAY : ARRAY [1..10] OF CHAR;
	SYSNAME : ARRAY [1..14] OF CHAR;
	TOSNM   : ARRAY [PRIME..DISC,1..6] OF INTEGER;

FUNCTION DEC(VAR A : WKO; N : INTEGER) : INTEGER;
  BEGIN
  IF NOT (A[N] IN ['0'..'9']) THEN A[N] := '0';
  IF NOT (A[SUCC(N)] IN ['0'..'9']) THEN A[SUCC(N)] := '0';
  DEC := (ORD(A[N]) - ORD('0'))*10 + ORD(A[SUCC(N)]) - ORD('0')
  END;
 
FUNCTION DAYOFYEAR (VAR DT:WKO) : INTEGER;
  BEGIN
  DAYOFYEAR := DAYM[DEC(DT,3)] + DEC(DT,5) ;
  END;
 
PROCEDURE TIMEOUT(T:USEPTR);	(***  PRINT DETAIL LINE  ***)
  VAR	S:SHIFT;
  BEGIN
  WITH T^ DO  IF USED THEN
    BEGIN
    WRITE(F,UACC,'  ','[',UID,']');
    FOR S := PRIME TO DISC DO WITH USES[S] DO
      WRITE(F,MIN:6,MCT:8:1,BAMIN:6,BAMCT:8:1,DISKB:10:0,' ');
    WRITELN(F,SUPPL:10:2,ADJST:10:2);
    END;
  END;
 
 
PROCEDURE NEWUSER;	(***  CREATE NEW USER RECORD   ***)
  VAR E : USEPTR;  S:SHIFT;
  BEGIN
  NEW(E);
  WITH E^ DO
    BEGIN
    FOR S := PRIME TO DISC DO WITH USES[S] DO
      BEGIN
      MIN := 0;  BAMIN := 0;  MCT := 0;  BAMCT := 0;  DISKB := 0
      END;
    SUPPL := 0;  ADJST := 0;  UID := TUIC;  UACC := TACC;  NU := TF;  USED := FALSE;
    IF PU = NIL THEN FU := E
		ELSE PU^.NU := E
    END;
  TF := E;   NOTFND := FALSE;
  IF TF^.NU=NIL THEN LU := TF;
  END;
 
PROCEDURE FINDU;	(*** FIND THE USER RECORD ***)
  BEGIN
  TF := FU;  NOTFND := TRUE;    PU := NIL;
  WHILE NOTFND  & (TF <> NIL) DO
    BEGIN
    NOTFND := (TF^.UID < TUIC);
    IF NOTFND THEN BEGIN PU := TF;  TF := TF^.NU END;
    END;
  IF TF^.UID <> TUIC THEN NEWUSER;
  END;

(*******************************************************************)
 
		(***  MAIN LINE  ***)
BEGIN
 
(**************  INITIALIZE   ************************)
 
 
FU := NIL;  LU := NIL;
 
DAYM[10] :=0;	DAYM[11] := 31;
DAYM[1] := 92;	DAYM[12] := 61;
DAYM[2] := 123;	DAYM[9]  := 335;
DAYM[3] := 151;	DAYM[4] := 182;
DAYM[5] := 212;	DAYM[6] := 243;
DAYM[7] := 273;	DAYM[8] := 304;
FOR I := 3 TO 9 DO DAYM[I] := DAYM[I] + LEAPYEAR;
 
RESET(F,'ACCOUNTS.DAT');
READ(F,SYSNAME,R1,R2,UIC1,CH2,MAXD);
FOR S := PRIME TO DISC DO
  FOR I := 1 TO 6 DO READ(F,TOSNM[S,I],R,R);
 
(*****************    READ SESSION FILE    **********************)
 
RESET (F,'ACCTSSES.DAT');
WHILE NOT EOF(F) DO
  BEGIN
  READ(F,TACC,USETP,CH2,CH2,TUIC,CH,MINS,MCTS);
  IF TACC =  'SCITERMIN' THEN MINS := 0;
  IF TACC <> '         ' THEN
    BEGIN
    FINDU;
    WITH TF^ DO CASE USETP OF
     'B' : WITH USES[PRIME] DO
  	     BEGIN
  	     BAMIN := BAMIN + MINS;  BAMCT := BAMCT + MCTS;
	     USED := USED OR (BAMIN<>0) OR (BAMCT<>0);
	     END;
     'N' : WITH USES[DISC] DO
	     BEGIN
	     MIN := MIN + MINS;  MCT := MCT + MCTS;
	     USED := USED OR (MIN<>0) OR (MCT<>0);
	     END;
     OTHERS : WITH USES[PRIME] DO
	     BEGIN
	     MIN := MIN + MINS;  MCT := MCT + MCTS;
	     USED := USED OR (MIN<>0) OR (MCT<>0);
	     END
      END;
    END;
  END;
 
R := 1;	(***  ASSUME ONE WEEK  ***)

 
(****************   READ DISK USAGE FILE   ***********************)
 
RESET(F,'ACCDISKA.DAT');
S := PRIME;
WHILE NOT EOF(F) DO
   BEGIN
   READLN(F,FUFD,DBLKS);
   IF FUFD = 'DR1:DSKUSE'  THEN S := DISC ELSE
   BEGIN
   TF := FU;  NOTFND := TRUE;
   FOR I := 1 TO 7 DO TUIC[I] := FUFD[I+1];
   WHILE (TF <> NIL) AND NOTFND DO
     BEGIN
     NOTFND := TF^.UID <> TUIC;
     IF NOTFND THEN TF := TF^.NU;
     END;
   IF NOTFND THEN
      BEGIN
      TUIC[5] := '3';  TUIC[6] := '7';  TUIC[7] := '7';
      TACC := 'Unknown  ';
      FINDU;
      END;
   TF^.USES[S].DISKB := TF^.USES[S].DISKB +  DBLKS*R;
   TF^.USED := TF^.USED OR (DBLKS<>0);
   END;
   END;
 
%(***********   DETERMINE PREMIUM DISK STORAGE   ***************)
 
TF := FU;    MAXD := MAXD*R;
WHILE TF <> NIL DO WITH TF^ DO
  BEGIN
  IF USES[DISC].DISKB > MAXD THEN
    BEGIN
    USES[PRIME].DISKB := USES[DISC].DISKB - MAXD;  USES[DISC].DISKB := MAXD;
    END;
  TF := TF^.NU;
  END;\

%(**********    ACCEPT MANUAL ENTRIES / ADJUSTMENTS    ***********)
 
LOOP
  WRITE('ANY MANUAL ENTRIES [Y/N] >'); BREAK; READLN; READ(CH);
  EXIT IF CH = 'N';
  WRITELN('0=ADJUST USAGES,  1=ENTER SUPPLIES CHARGE');
  WRITE('ENTER ENTRY TYPE [0..1] >');  BREAK;  READLN;  READ(I);
  IF I IN [0..1] THEN 
    BEGIN
    WRITE('ENTER WORK ORDER NUMBER >');  BREAK;  READLN;  READ(W);
    WRITE('ENTER USER ID ([O,O])   >');  BREAK;  READLN;
    READ(CH);  IF CH='[' THEN READ(CH);
    TUIC.U1 := 0;  J := 1;
    WHILE (CH IN ['0'..'7']) AND (J<=3) DO WITH TUIC DO
      BEGIN
      U1 := U1*8 + ORD(CH) - ORD('0');  READ(CH);  J := SUCC(J);
      END;
    TUIC.U2 := 0;  J := 1;
    WHILE NOT (CH IN ['0'..'7']) & NOT EOLN(TTY) DO READ(CH);
    WHILE (CH IN ['0'..'7']) AND (J <= 3) DO WITH TUIC DO
      BEGIN
      U2 := U2*8 + ORD(CH) - ORD('0');  J := SUCC(J);
      IF NOT EOLN(TTY) THEN READ(CH) ELSE CH := ' ';
      END;
    FINDU;
    CASE I OF 
      1: BEGIN
	 WRITE('ENTER NUMBER OF DOLLARS >'); BREAK; READLN; READ(R);
	 WITH TS^ DO SUPPL := SUPPL + R
	 END;
      0: BEGIN
         WRITE('ENTER NUMBER OF MCTS        >');  BREAK;  READLN;  READ(R1);
         WRITE('ENTER NUMBER OF REG MINS    >');  BREAK;  READLN;  READ(R2);
         WRITE('ENTER NUMBER OF DISK BLOCKS >');  BREAK;  READLN;  READ(R4);
         WITH TS^ DO WITH SYSUSE[PRIME] DO
	   BEGIN  MCT := MCT + R1;
	   MIN := MIN + ROUND(R2);
	   DK[REG] := DK[REG] + R4;
	   END;
         WRITE('IS THIS A CORRECTION FOR A PREVIOUSLY UNSET WORK ORDER ? [Y/N] >');
         BREAK; READLN; READ(CH);
         IF CH = 'Y' THEN
	  BEGIN  W := 'U00000';  FINDU;
	  WITH TS^ DO WITH SYSUSE[PRIME] DO
	    BEGIN
	    MCT := MCT - R1;
	    MIN := MIN - ROUND(R2);
	    DK[REG] := DK[REG] - R4
	    END;
	  END;
	END		(** CASE 0 **)
      END;		(** ALL CASES **)
    END ELSE WRITELN('WRONG -- TRY AGAIN');
  END;   (*** LOOP ***)		\

(****************    READ MONEY.LOG ENTRIES	****************)
 
RESET (F,'MONEY.LOG');
IF IORESULT(F) <> 1 THEN WRITELN('NO MONEY.LOG DATA.')
ELSE
  BEGIN
  FOR I := 1 TO 6 DO READLN(F);
  WHILE NOT EOF(F) DO
    BEGIN
    FOR I := 1 TO 20 DO READ(F,CH);
    FOR I := 1 TO 3 DO READ(F,TACC[I]);
    READ(F,CH);
    FOR I := 4 TO 9 DO READ(F,TACC[I]);
    FOR I := 1 TO 10 DO READ(F,CH);
    READLN(F,L,R);
    TF := FU;  NOTFND := TRUE;    PU := NIL;
    WHILE NOTFND  & (TF <> NIL) DO
      BEGIN
      NOTFND := (TF^.UACC <> TACC);
      IF NOTFND THEN BEGIN PU := TF;  TF := TF^.NU END;
      END;
    IF TF^.UACC <> TACC THEN BEGIN TUIC := '377,377';  NEWUSER; END;
    I := 0;
    IF L = TOSNM[PRIME,6] THEN TF^.SUPPL := TF^.SUPPL + R ELSE
    IF L = TOSNM[DISC ,6] THEN TF^.ADJST := TF^.ADJST + R ELSE
    FOR S := PRIME TO DISC DO WITH TF^.USES[S] DO
      IF L = TOSNM[S,1] THEN MIN := MIN + TRUNC(R) ELSE
      IF L = TOSNM[S,2] THEN MCT := MCT + R ELSE
      IF L = TOSNM[S,3] THEN BAMIN := BAMIN + TRUNC(R) ELSE
      IF L = TOSNM[S,4] THEN BAMCT := BAMCT + R ELSE
      IF L = TOSNM[S,5] THEN DISKB := DISKB + R ELSE
      I := I+1;
    IF I=2 THEN WRITELN('TOS',L:4,' from MONEY.LOG not found.');
    END;
  END;

(****************    WRITE OUT SUMMARY FOR EACH USER   ******************)
 
  REWRITE(F,'ACCTSSUM.DAT');
  WRITELN(F,'SYSTEM SUMMARY FOR ':68,SYSNAME);
  DATE (TODAY);
  FOR I := 1 TO 2 DO ENDDT[I] := TODAY[I+2];
  FOR I := 3 TO 4 DO ENDDT[I] := TODAY[I+3];
  FOR I := 5 TO 6 DO ENDDT[I] := TODAY[I+4];
  J := ( DAYOFYEAR(ENDDT) + FDOY + 5 ) DIV 7;
  WRITELN(F,'PREPARED : ':15,TODAY,
	    'ENDING : ':66,ENDDT,'WEEK : ':20, J:3);
  WRITELN(F);
  WRITELN(F,'Prime':43,'Discount':39);
  WRITELN(F,' ':22,'------------------------------------',
	    '   ------------------------------------');
  WRITE(F,' ':20);
  FOR I := 1 TO 2 DO WRITE(F,'   TS     TS   Batch   Batch    Disk   ');
  WRITELN(F);
  WRITE(F,' Account      UIC   ');
  FOR I := 1 TO 2 DO WRITE(F,'  Mins   MCTS   Mins   MCTS    Blocks  ');
  WRITELN(F,'  Supplies  Adjustments');
  WRITELN(F,'---------  ---------  ----  ------  ',
	    '----  ------  --------   ----  ',
	    '------  ----  ',
	    '------  --------   --------   -------');
  TF := FU;   NUSERS := 0;
  WHILE TF <> NIL DO
    BEGIN
    TIMEOUT(TF);
    WITH TF^ DO
      IF (UID>='300,000') AND (UID<'311,000') OR (UID>'311,377') THEN
	NUSERS := NUSERS+1;
    TF := TF^.NU
    END;
WRITELN(NUSERS:4,' user accounts found.');
WRITELN('ACCSUMMARY -- All done');
END.
