import java.util.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;

/*       A viewer for SMV traces generated from the
 *       Cybernetix Smart Card Personalization Machine model.
 *
 *       Date: 24-5-2002
 *       Authors:        Biniam Gebremichael     biniam@cs.kun.nl
 *                       Martijn Hendriks        martijnh@cs.kun.nl
 *                       University of Nijmegen, The Netherlands
 */

class TraceViewer extends Frame
{
         public static final int MAX_STATES = 1000, MAX_STATIONS = 10, MAX_BELT_POSITIONS = MAX_STATIONS+2;
         public static final int WIDTH=300, HEIGHT=150;
         public static int actual_stations = -1, last_state = -1, current_state = -1, max_c = -1;

         public static int frame_time = 1000;

         public static int a[][] = new int[MAX_STATES][MAX_STATIONS];
         public static int c[][] = new int[MAX_STATES][MAX_STATIONS];
         public static int b[][] = new int[MAX_STATES][MAX_BELT_POSITIONS];

public static int different(int r){
	int  z;
	if(r==0) return 1;
	for(z=0;z<MAX_BELT_POSITIONS;z++){
	    if(b[r][z]!=b[r-1][z]){
		return 1;
	    }}
	return 0;
    }
         public static  void init (String[] args)
         {
                 String filename = "pcard2.tra";

                 for(int x=0;x<MAX_STATES;x++)
                         for(int y=0;y<MAX_STATIONS;y++)
                         {
                                 a[x][y] = -4;
                                 c[x][y] = 0;
                         }
                 for(int x=0;x<MAX_STATES;x++)
                         for(int y=0;y<MAX_BELT_POSITIONS;y++)
                                 b[x][y] = -4;

                 if (args.length != 1)
                 {
                         System.err.println("Usage: java TraceViewer <trace-file>");
                         System.err.println("Warning: Using default value!");
                 }
                 else
                         filename = args[0];
                 try
                 {
                         parseTrace(filename);
                 }
                 catch (IOException e)
                 {
                         fatal("Cannot open "+filename+"!");
                 }
         }

         public static int myMax (int a, int b)
         {
                 if (a<b)
                         return b;
                 else
                         return a;
         }

         public static void fatal (String msg)
         {
                 System.err.println(msg);
                 System.exit(1);
         }

         public static void parseTrace (String file_name) throws IOException
         {
                 BufferedReader in = new BufferedReader(new FileReader(file_name));
                 int t=-1;

                 try
                 {
                         String s = in.readLine();
                         while(s != null)        // or until an EOF exception is thrown...
                         {
                                 if (s.startsWith("/* state"))
                                         t++;
                                 else if (s.startsWith("\\b [") || s.startsWith("\\a [") || s.startsWith("\\c ["))
                                 {
                                         char k;
                                         int i=-2, j=-2;
                                         StringTokenizer st = new StringTokenizer(s," =[],");
                                         st.nextToken();
                                         k = s.charAt(1);
                                         try
                                         {
                                                 i = Integer.parseInt(st.nextToken());
                                                 j = Integer.parseInt(st.nextToken());
                                         }
                                         catch (NumberFormatException e)
                                         {
                                                 fatal("Syntax error....");
                                         }
                                         if (k=='a')
                                         {
                                                 if (i>=MAX_BELT_POSITIONS)
                                                         fatal("Array overflow: increase MAX_STATIONS to at least "+(i+1)+" and recompile!");
                                                 b[t][i] = j;
                                         }
                                         else if (k=='b')
                                         {
                                                 actual_stations = myMax(actual_stations,i);
                                                 if (i>=MAX_STATIONS)
                                                         fatal("Array overflow: increase MAX_STATIONS to at least "+(i+1)+" and recompile!");
                                                 a[t][i] = j;
                                         }
                                         else if (k=='c')
                                         {
                                                 if (i>=MAX_STATIONS)
                                                         fatal("Array overflow: increase MAX_STATIONS to at least "+(i+1)+" and recompile!");
                                                 c[t][i] = j;
                                                 max_c = myMax(max_c,j);
                                         }
                                         else
                                                 fatal("Syntax error...");                                       
                                 }
                                 s = in.readLine();
                         }
                 }
                 catch (EOFException e)
                 {;}
                 in.close();
                 last_state = t;
                 if (last_state>=0)
                         current_state=0;
                 actual_stations++;
         }

         public void drawContents (Graphics g, int c, int x, int y, int bd, int pers_time)
         {
                 if (c<-3)
                         fatal("Something strange happened!");
                 else if (c==-3 || c==-2)        // empty slot
                         ;
                 else if (c==-1)                 // empty card
                 {
                         g.setColor(Color.gray);
                         g.fillRect(x+5,y+5,bd-10,bd-10);
                 }
                 else                    // personalized card
                 {
                         if (pers_time>=0)
                         {
                                 Color mgreen;
                                 int green = 100+((155/max_c)*pers_time);
                                 if (green>255)
                                         green = 255;
                                 g.setColor(new Color(50,green,50));
                         }
                         else
                         {
                                 g.setColor(Color.green);
                         }
                         g.fillRect(x+5,y+5,bd-10,bd-10);
                         g.setColor(Color.black);
                         g.drawString(Integer.toString(c),x+(bd/2)-4,y+(bd/2));
                 }
         }

         public void paint (Graphics g)
         {
                 int w = this.getWidth()-60, bd = w/(actual_stations+2), xo = 30, yo=60;
                 g.setColor(Color.black);
                 g.drawString("State "+current_state+" of "+last_state,20,40);
                 // Draw the machine outline
                 for (int i=0; i<actual_stations; i++)
                 {
                         int x=((i+1)*bd)+xo, y=yo;
                         g.setColor(Color.black);
                         g.drawRect(x,y,bd,bd);
                         drawContents(g,a[current_state][i],x,y,bd,c[current_state][i]);
                 }
                 for (int i=0; i<actual_stations+2; i++)
                 {
                         int x=(i*bd)+xo, y=yo+bd;
                         g.setColor(Color.black);
                         g.drawRect(x,y,bd,bd);
                         drawContents(g,b[current_state][i],x,y,bd,-1);
                 }
         }

         public TraceViewer ()
         {               
                 setBackground(Color.white);
                 setForeground(Color.black);
                 setTitle("Smart Card Trace Viewer");
                 setSize(WIDTH,HEIGHT);
                 setResizable(false);
                 setVisible(true);
                 addWindowListener(new WindowAdapter()
                 {
                         public void windowClosing(WindowEvent e)
                         {
                                 System.exit(0);
                         }
                 });
         }

         public static void main (String[] args)
         {
                 init(args);

                 Frame f = new TraceViewer();
                 // Animate the trace
		 
                 for (int t=0; t<=last_state; t++)
                 {
		     if(different(t)==1){
                         try
                         {
                                 Thread.sleep(frame_time);
                         }
                         catch(InterruptedException e)
                         {;}
                         f.repaint();
		     }
                         current_state++;
                 }
                 current_state-=1;
         }
}
