import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;

public class LinesFrame extends Frame {
     static final int MAX_TRANS = 100;
     static final int MAX_SESSION = 10;
     static final int TX_SEND = 0;
     static final int TX_RECV = 1;
     static final int MAX_TRANS_PER_SESSION = 20;
     
     String []TypeStrings = {"SYN","ACK","SYN+ACK","FIN","FIN+ACK", "DATA", "RST"}; 

     
     TransEvent []txlist_c2s=null, txlist_s2c=null;
     int count_c2s=0, count_s2c=0;        
     int current_session=0;
	 TxLine []lines_c2s=null, lines_s2c=null;
	 int start_time, end_time, lcount1=0, lcount2=0;
	 double scale; /*pix per unit time*/
	 
     public LinesFrame() {
        
        current_session = 0;        
        txlist_c2s = new TransEvent[MAX_TRANS]; 
        txlist_s2c = new TransEvent[MAX_TRANS]; 
        lines_c2s = new TxLine[MAX_TRANS_PER_SESSION];
        lines_s2c = new TxLine[MAX_TRANS_PER_SESSION];
                
        MenuBar menuBar = new MenuBar();
        Menu menuFile = new Menu();
        MenuItem menuFileExit = new MenuItem();
              
        menuFile.setLabel("File");
        menuFileExit.setLabel("Exit");
        
        // Add action listener.for the menu button
        menuFileExit.addActionListener
        (
            new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    LinesFrame.this.windowClosed();
                }
            }
        ); 
        menuFile.add(menuFileExit);
        menuBar.add(menuFile);
        
        setTitle("Lines");
        setMenuBar(menuBar);
        setSize(new Dimension(800, 600));
        
        // Add window listener.
        this.addWindowListener
        (
            new WindowAdapter() {
                public void windowClosing(WindowEvent e) {
                    LinesFrame.this.windowClosed();
                }
            }
        );  
        
        this.addKeyListener(
            new KeyListener(){
                public void keyPressed(KeyEvent e){
                    if (e.getKeyCode()==KeyEvent.VK_SPACE){
                        LinesFrame.this.current_session = (LinesFrame.this.current_session+1)%
                                                     LinesFrame.this.MAX_SESSION;
                    	LinesFrame.this.computeLines();
						LinesFrame.this.invalidate();
     					LinesFrame.this.repaint();
/*     					LinesFrame.this.setVisible(false);
     					LinesFrame.this.setVisible(true);
*/                    }
                } 
                public void keyReleased(KeyEvent e){}
                public void keyTyped(KeyEvent e){}

            } 
        );
        
      
    }
    
    protected int findnextTx_s2c(int session,int segment, int event, int startindex){
    	int i;
    	
    	for (i=startindex; i<count_s2c; i++){
    		if ((txlist_s2c[i].session == session) 
 				&& ((segment==-1)||(txlist_s2c[i].segment == segment) )
    		    && (txlist_s2c[i].event == event))
    		    return i;
    	}
    	
    	return -1;
    	
    }

    protected int findnextTx_c2s(int session, int segment, int event, int startindex){
    	int i;
    	
    	for (i=startindex; i<count_c2s; i++){
    		if ((txlist_c2s[i].session == session) 
 				&& ((segment==-1)||(txlist_c2s[i].segment == segment) )
	    		&& (txlist_c2s[i].event == event))
    		    return i;
    	}
    	
    	return -1;
    	
    }

	public void computeLines(){
		int i1=-1,j1=-1, i2=-1,j2=-1;
		double stime=0, etime=0;
		
		i1 = findnextTx_c2s(current_session, -1, TX_SEND, 0);
		if (i1 >= 0){
		   j1 = findnextTx_c2s(current_session,txlist_c2s[i1].segment, TX_RECV, i1+1);
		   stime = etime = txlist_c2s[i1].ts;
		}
		lcount1= lcount2 = 0;
		

		while (i1 >= 0 && j1 >=0){
			
			//System.out.println(i1+","+j1);
			
			lines_c2s[lcount1] = new TxLine();
			lines_c2s[lcount1].ts_send = txlist_c2s[i1].ts;
			lines_c2s[lcount1].ts_recv = txlist_c2s[j1].ts;
			lines_c2s[lcount1].type    = txlist_c2s[i1].type;
			lines_c2s[lcount1].len     = txlist_c2s[i1].len;

			lcount1++;
			
			i1 = findnextTx_c2s(current_session,-1, TX_SEND, i1+1);
			if (i1 < 0)
				break;
			j1 = findnextTx_c2s(current_session,txlist_c2s[i1].segment, TX_RECV, i1+1);
		}
		if (lcount1 >0)
		    etime = (lines_c2s[lcount1-1].ts_recv > etime)? lines_c2s[lcount1-1].ts_recv : etime;

		i2 = findnextTx_s2c(current_session, -1, TX_SEND, 0);
		if (i2 >= 0){
		    j2 = findnextTx_s2c(current_session, txlist_s2c[i2].segment, TX_RECV, i2+1);
		
		    stime = (txlist_s2c[i2].ts < stime) ? txlist_s2c[i2].ts : stime ;
	    }

		while (i2 >= 0 && j2 >=0){

			//System.out.println(i2+","+j2);
			
			lines_s2c[lcount2] = new TxLine();

			lines_s2c[lcount2].ts_send = txlist_s2c[i2].ts;
			lines_s2c[lcount2].ts_recv = txlist_s2c[j2].ts;
			lines_s2c[lcount2].type    = txlist_s2c[i2].type;
			lines_s2c[lcount2].len     = txlist_s2c[i2].len;

			lcount2++;

		
			i2 = findnextTx_s2c(current_session, -1, TX_SEND, i2+1);
			if (i2 < 0)
				break;
			j2 = findnextTx_s2c(current_session, txlist_s2c[i2].segment, TX_RECV, i2+1);
		}



		start_time = (new Double(stime)).intValue();
		end_time   = (new Double(etime)).intValue();
		
		start_time = (start_time / 10) * 10;
		end_time   = (end_time / 10 +1) * 10;
		scale = 400.0 / (end_time - start_time);
	}
    public void paint (Graphics page)
    {
    	
    	page.setColor(Color.black);
    	page.drawString("Trace of Session: "+Integer.toString(current_session),200,70);

    	page.drawLine(200,100,200,500);
    	page.drawLine(600,100,600,500);
    	page.drawString(Integer.toString(start_time), 150, 100);
    	page.drawString(Integer.toString(end_time), 150, 500);

		int i,j;
		
    	page.setColor(Color.blue);
		for (i=0; i<lcount1; i++){
			int y1,y2,y;
			int tsend, trecv;
			
			tsend = (new Double(lines_c2s[i].ts_send)).intValue();
			trecv = (new Double(lines_c2s[i].ts_recv)).intValue();
			
			y1 = (new Double(100+(lines_c2s[i].ts_send-start_time) * scale)).intValue();
			y2 = (new Double(100+(lines_c2s[i].ts_recv-start_time) * scale)).intValue();
			y = (y1+y2)/2;
	    	page.drawLine(200,y1,600,y2);
	    	page.drawString(TypeStrings[lines_c2s[i].type], 400,y);
	    	page.drawString(Integer.toString(tsend),150,y1);
	    	page.drawString(Integer.toString(trecv),605,y2);
		}    
    	
    	page.setColor(Color.red);
		for (i=0; i<lcount2; i++){
			int y1,y2,y;
			int tsend, trecv;
			
			tsend = (new Double(lines_s2c[i].ts_send)).intValue();
			trecv = (new Double(lines_s2c[i].ts_recv)).intValue();
			
			y1 = (new Double(100+(lines_s2c[i].ts_send-start_time) * scale)).intValue();
			y2 = (new Double(100+(lines_s2c[i].ts_recv-start_time) * scale)).intValue();
			y = (y1+y2)/2;
	    	page.drawLine(600,y1,200,y2);
	    	page.drawString(TypeStrings[lines_s2c[i].type], 400,y);
	    	page.drawString(Integer.toString(tsend),605,y1);
	    	page.drawString(Integer.toString(trecv),150,y2);
		}    
    	
    }
    
    /**
     * Shutdown procedure when run as an application.
     */
    protected void windowClosed() {
    	
    	// TODO: Check if it is save to close the application
    	
        // Exit application.
        System.exit(0);
    }
    
    public void prepareData(String c2sfile, String s2cfile) throws IOException{
    	
        // Read the files and prepare the data for output
         BufferedReader br_c2s = new BufferedReader(new FileReader(new File(c2sfile)));
         BufferedReader br_s2c = new BufferedReader(new FileReader(new File(s2cfile)));

         String s = null, tstr=null;
         double td;
         
         count_c2s = 0;
         while (true) {
             s = br_c2s.readLine();
             if (s == null)
             	break;
			 //System.out.println(s);	
             StringTokenizer stok = new StringTokenizer(s);

             
             
             txlist_c2s[count_c2s] = new TransEvent();
             
             txlist_c2s[count_c2s].ts      = Double.parseDouble(stok.nextToken());
             txlist_c2s[count_c2s].segment = Integer.parseInt(stok.nextToken());	
             String t = stok.nextToken();	
             txlist_c2s[count_c2s].event   = (t.compareTo("S") ==0)?TX_SEND:TX_RECV;
             txlist_c2s[count_c2s].session = Integer.parseInt(stok.nextToken());	
             txlist_c2s[count_c2s].type    = Integer.parseInt(stok.nextToken());	
             txlist_c2s[count_c2s].len     = Integer.parseInt(stok.nextToken());	
             count_c2s++;
         }
		
		 count_s2c = 0;	
         while (true) {
             s = br_s2c.readLine();
             if (s == null)
             	break;
			 //System.out.println(s);	
             StringTokenizer stok = new StringTokenizer(s);


			 txlist_s2c[count_s2c] = new TransEvent();
             txlist_s2c[count_s2c].ts      = Double.parseDouble(stok.nextToken());	
             txlist_s2c[count_s2c].segment = Integer.parseInt(stok.nextToken());	
             String t = stok.nextToken();	
             txlist_s2c[count_s2c].event   = (t.compareTo("S") == 0)?TX_SEND:TX_RECV;
             txlist_s2c[count_s2c].session = Integer.parseInt(stok.nextToken());	
             txlist_s2c[count_s2c].type    = Integer.parseInt(stok.nextToken());	
             txlist_s2c[count_s2c].len     = Integer.parseInt(stok.nextToken());	
             count_s2c++;
         }

    }
}


class TransEvent{
	double ts=0;
	int event=0, type=0, len=0, session=0, segment=0;  
	
	
	
}

class TxLine{
	double ts_send=0, ts_recv=0;
	int type=0, len=0;
}