// Carnegie Mellon University
//   Information Networking Institute and
//   School of Computer Science
//
// Master Thesis: A Monitoring Tool for Overlay Network
// By: TungFai Chan and Annie Cheng
//
// File: LogFilesParser.java
// Path: monitor/parser/
// Description: Derived class from FilesParser


package parser;

import eventbase.*;
import eventbase.event.*;
import eventbase.neighbor.*;
import eventbase.link.*;
import eventbase.routing.*;
import java.io.*;
import java.util.*;

public class LogFilesParser extends FilesParser {

    String currentHost = null;
    String fileName = null;
    double save_time = -1;  // for delay

    private SpanningTreeGlobalConstruct sTreeGlobal = null;
    // 09/05/00 ahcheng - support VRT with time stamp and count
    private double vrtTimeStamp;
    // TODO:  can we put this value somewhere better than here?
    public static final double UPDATE_INTERVAL = 30;
    public SpanningTreeQueue sQueue;

    public LogFilesParser() {
	vrtTimeStamp = -1;
	sQueue = new SpanningTreeQueue();
	this.sTreeGlobal =
	    new SpanningTreeGlobalConstruct();
    }

    public void readFileIntoDB(BufferedReader reader, String filename) throws IOException {
        String curline = null;
        fileName = filename;

	while ( (curline = reader.readLine()) != null)
	    readEachStatement(reader, curline);

    }

    // in our case, we need to form a global view for the spanning tree and
    // dump the global spanning tree structure into the database
    // this has to be done after parsing all the files
    public void endOfParsingHandling() {
	Vector v;
	double time;
	int numEntries;
	int forwardingHostID;
	int sourceHostID;

	v = sQueue.getQueue();
	for (int i =0; i < v.size(); i++) {
	    SpanningTreeStoringObject obj = (SpanningTreeStoringObject) v.elementAt(i);
	    numEntries = (obj.numUniqueHosts() > dbAgent.getNumOfOverlayHosts())?obj.numUniqueHosts():dbAgent.getNumOfOverlayHosts();
	    forwardingHostID = dbAgent.getHostID(obj.getForwardingHost().toLowerCase());
	    if (!sTreeGlobal.isInit())
		sTreeGlobal.init(numEntries, dbAgent);
	    sTreeGlobal.VRTStart(obj.getTime(), numEntries, forwardingHostID);
	    Vector entries = obj.getEntries();
	    for (int j = 0; j< entries.size(); j++) {
		SpanningTreeStoringEntries entry = (SpanningTreeStoringEntries) entries.elementAt(j);
		sourceHostID = dbAgent.getHostID(entry.getSource().toLowerCase());
		sTreeGlobal.cleanRow(sourceHostID, forwardingHostID);
		String[] childList = entry.getChildArray();
		for (int k = 0; k < entry.getNumChild(); k++) {
		    sTreeGlobal.setMatrixCoordinate(sourceHostID,
						    forwardingHostID,
						    dbAgent.getHostID(childList[k].toLowerCase()));
		}
	    }
	    sTreeGlobal.VRTEnd();
	}
    }

    private void readEachStatement(BufferedReader reader, String curline)
	throws IOException {

	//System.out.println(curline);
	if (curline.indexOf("HOSTNAME") != -1) {
	    currentHost = curline.substring(9);

            if (currentHost.indexOf(".") == -1 && currentHost.equals(fileName.substring(0, fileName.indexOf("."))))
                currentHost = fileName.substring(0, fileName.lastIndexOf("."));
           // System.out.println ("CurrentHost: " + currentHost);
    	}
	else if (curline.indexOf("KNOWN_MEMBER") != -1) {
	    String member = curline.substring(13);
	}
 	else if (curline.indexOf("New physical link estimate") != -1) {
	    
	    StringTokenizer tokenizer = new StringTokenizer(curline, " ");

	    tokenizer.nextToken();
	    tokenizer.nextToken();
	    tokenizer.nextToken();
	    tokenizer.nextToken();
	    tokenizer.nextToken();
	    tokenizer.nextToken();
	    String dest = tokenizer.nextToken();


	    int delayPos = curline.indexOf("LatencyMetric:");
	    int delayEndPos=curline.indexOf(" ",delayPos+15);

	    // System.out.println(delayPos + " " + delayEndPos);

	    int bwPos = curline.indexOf("BWMetric:");
	    int bwEndPos=curline.indexOf(" ",bwPos+10);	    	    

	    int delay;
	    int bw;
	    if(delayPos != -1){
		delay = Integer.parseInt(curline.substring(delayPos+15,delayEndPos));
	    }
	    else{
		delay = 0;
	    }
	    
	    if(bwPos != -1){
		 bw = Integer.parseInt(curline.substring(bwPos+10,bwEndPos));
	    }
	    else{
		bw = 0;
	    }

	    //System.out.println(curline);
	    //System.out.println(delay + " " + bw);
	    // System.exit(0);

	    int combined;

	    if(bw >= 0){
		if(delay >= 0){
		    combined = bw * 1000 + delay;
		}
		else{
		    combined = bw * 1000 - delay;
		}
	    }
	    else{
		if(delay >= 0){
		    combined = bw * 1000 - delay;
		}
		else{
		    combined = bw * 1000 + delay;
		}
	    }
	    

		
            dbAgent.InsertLinkInfoIntoTable(
              this.save_time,
              dbAgent.getHostID(currentHost.toLowerCase()),
              dbAgent.getHostID(dest.toLowerCase()),
              LinkInfoType.DELAY, combined);
	}

	/* new lines: Num Shortlisted JOIN */
	else if (curline.indexOf("JOIN:") != -1 &&
		 curline.indexOf("ShortListed JOIN:") == -1 &&
		 curline.indexOf("Num Shortlisted JOIN:") == -1) {
	    double time = Double.parseDouble(curline.substring(0, curline.indexOf(':')));
	    dbAgent.setLatestEventTime(time);
            this.save_time = time;
	    int lower = Integer.parseInt(
					 curline.substring(curline.indexOf("<") + 1,
							   curline.indexOf(",")));
	    int upper = Integer.parseInt(
					 curline.substring(curline.indexOf(",") + 1,
							   curline.indexOf(">")));
            OverlayHost host =
              new OverlayHost(dbAgent.getHostID(currentHost.toLowerCase()),
                              currentHost.toLowerCase());
            JoinGroupEvent join_event = new JoinGroupEvent(host);
            dbAgent.InsertEventIntoTables(time, join_event);
	}
	else if (curline.indexOf("VRT Begin") != -1) {
	    double time = Double.parseDouble(curline.substring(0, curline.indexOf(':')));
	    dbAgent.setLatestEventTime(time);
            this.save_time = time;
	    vrtTimeStamp = time;
	    StringTokenizer tokenizer = new StringTokenizer(curline, " ");
	    tokenizer.nextToken();
	    tokenizer.nextToken();
	    int numEntry = Integer.parseInt(tokenizer.nextToken());
	    SpanningTreeStoringObject obj = new SpanningTreeStoringObject(time, (numEntry>dbAgent.getNumOfOverlayHosts())?numEntry:dbAgent.getNumOfOverlayHosts(), currentHost);
            while (curline.indexOf("VRT End") == -1) {
             if (curline.indexOf("Addr:") != -1) {
	        int namePos = curline.indexOf("Name");
		int nameEndPos=curline.indexOf(" ",namePos+5);
	        int lcsnPos = curline.indexOf("LCSN");
		int lcsnEndPos=curline.indexOf(" ",lcsnPos+7);
	        int timePos = curline.indexOf("Time");
		int timeEndPos=curline.indexOf(" ",timePos+7);
	        int pdPos = curline.indexOf("PD =");
		int pdEndPos=curline.indexOf(" ",pdPos+5);
	        int rdPos = curline.indexOf("RD");
		int rdEndPos=curline.indexOf(" ",rdPos+5);
		int rbPos = curline.indexOf("RB");
		int rbEndPos=curline.indexOf(" ",rbPos+5);
	        int nhPos = curline.indexOf("NH");
		int nhEndPos=curline.indexOf(" ",nhPos+5);
		int numchildrenPos = curline.indexOf("numChildren");
		int numchildrenEndPos = curline.indexOf(" ",numchildrenPos+14);
		int deadFlgPos=curline.indexOf("DeadFlg");

	        String name = curline.substring(namePos + 5, nameEndPos);
                if (name.indexOf(".") == -1 && name.equals(fileName.substring(0, fileName.indexOf("."))))
		    name = fileName.substring(0, fileName.lastIndexOf("."));
		int pd = Integer.parseInt(curline.substring(pdPos + 5,pdEndPos));
		int rd = Integer.parseInt(curline.substring(rdPos + 5,rdEndPos));
		int rb = Integer.parseInt(curline.substring(rbPos + 5,rbEndPos));
		String neighbor = curline.substring(nhPos + 5, nhEndPos);
		if (neighbor.indexOf(".") == -1 && 
                    neighbor.equals(fileName.substring(0, fileName.indexOf(".")))
		    )
		    neighbor = fileName.substring(0, fileName.lastIndexOf("."));

	        int numChildren = Integer.parseInt(curline.substring(numchildrenPos + 14,
						 numchildrenEndPos));
		int deadFlg=Integer.parseInt(curline.substring(deadFlgPos+10));
		
                // insert VRT info to VRT table
                // TODO -- check whether neighbor is equal to 255.255.255.255 which means
                // no route, just replace with -1 instead of going thru dbAgent.
                // need to change that with the version that has the bug fix

                int nextHopID = -1;

                if (!(neighbor.toLowerCase().equals("255.255.255.255") ||
                   neighbor.toLowerCase().equals("-1.255.255.255")))
                     nextHopID = dbAgent.getHostID(neighbor.toLowerCase());

	        String[] children = new String[numChildren];
		int[] childrenIDList = new int[numChildren];
	        curline = reader.readLine();
		//System.out.println(curline);
		if(curline.indexOf("Path") != -1){
		    curline = reader.readLine();
		    // System.out.println(curline);
		}
	        tokenizer = new StringTokenizer(curline, " ");
	        tokenizer.nextToken();
	        tokenizer.nextToken();
	        for (int i = 0; i < numChildren; i++)
		    children[i] = tokenizer.nextToken();
		    
                int srcID = dbAgent.getHostID(name.toLowerCase());
                int forwardingHostID = dbAgent.getHostID(this.currentHost.toLowerCase());
		// 09/12/00 comment out dead flag in order to match the behavior with on-line mode
		//                if (deadFlg != 1) {
                  // 09/05/00 bug fix
                  // needs to clean up that row before adding new link information
                  // in case a forwarding host changes its child, db should
                  // not remember the history. -- don't need this for log file yet
                  // since now log file only reads in the last VRT dump
                  // this.sTreeGlobal.cleanRow(srcID, forwardingHostID);
		for (int i = 0; i < numChildren; i++) {
		    childrenIDList[i] = dbAgent.getHostID(children[i].toLowerCase());
		}
		
		//                }
		SpanningTreeStoringEntries sEntry = new SpanningTreeStoringEntries(name, numChildren, children);
		obj.insertEntry(sEntry);

		
		int combined;
		
		if(rb >= 0){
		    if(rd >= 0){
			combined = rb * 1000 + rd;
		    }
		    else{
			combined = rb * 1000 - rd;
		    }
		}
		else{
		    if(rd >= 0){
			combined = rb * 1000 - rd;
		    }
		    else{
			combined = rb * 1000 + rd;
		    }
		}
		
		dbAgent.insertVRTEntry(dbAgent.getHostID(currentHost.toLowerCase()),
				       this.vrtTimeStamp,
				       dbAgent.getHostID(name.toLowerCase()),
				       nextHopID,
				       rb * 1000 + rd, deadFlg, numChildren, childrenIDList);

		//System.out.println(name + " " + pd + " " +  rd + " " + neighbor +  " " + numChildren +  " " + deadFlg);

	     }
	     curline = reader.readLine();
	     // System.out.println(curline);
            }
            // finish reading in the VRT table, notify the GlobalConstruct
	    this.vrtTimeStamp = -1;
	    sQueue.insertPacket(obj);
      }else if (curline.indexOf("DEAD") != -1) {
            double time = Double.parseDouble(curline.substring(0, curline.indexOf(':')));
	    dbAgent.setLatestEventTime(time);
            this.save_time = time;
	    String deadNode = curline.substring(curline.indexOf("believes") + 9,
						curline.indexOf("DEAD") - 1);
            OverlayHost host =
              new OverlayHost(dbAgent.getHostID(currentHost.toLowerCase()),
                              currentHost.toLowerCase());
            OverlayHost deadhost =
              new OverlayHost (dbAgent.getHostID(deadNode.toLowerCase()),
                               deadNode.toLowerCase());
            DetectDeadHostEvent detect_dead_host_event =
              new DetectDeadHostEvent(host, deadhost);
            dbAgent.InsertEventIntoTables(time, detect_dead_host_event);
	}
        else if (curline.indexOf("INTENT_TO_CANCEL") != -1) {
            double time = Double.parseDouble(curline.substring(0, curline.indexOf(':')));
            if (curline.indexOf("Send") != -1) {
		dbAgent.setLatestEventTime(time);
                this.save_time = time;
                int toPos = curline.indexOf("to");
                String host = curline.substring(toPos + 3);
                OverlayHost leavehost =
                  new OverlayHost (dbAgent.getHostID(host.toLowerCase()),
                                   host.toLowerCase());
                IntentToLeaveGroupEvent intent_leave_event =
                  new IntentToLeaveGroupEvent(leavehost);
                dbAgent.InsertEventIntoTables(time, intent_leave_event);
            }
            else {
                // Do nothing
            }
        }
        else if (curline.indexOf("ADD_NBR_RESPONSE") != -1) {
	    if(curline.indexOf("Waiting") == -1){
		if(curline.indexOf("REJECTED") == -1){
		    String host;
		    double time = Double.parseDouble(curline.substring(0, curline.indexOf(':')));
		    dbAgent.setLatestEventTime(time);
		    this.save_time = time;
		    boolean recv = false;
		    
		    if (curline.indexOf("Send") != -1) {
			int toPos = curline.indexOf("to ");
			host = curline.substring(toPos + 3);
		    }
		    else {
			int fromPos = curline.indexOf("from");
			int lastSpacePos = curline.lastIndexOf(" ");
			host = curline.substring(fromPos + 5, lastSpacePos);
			recv = true;
		    }
		    OverlayHost homeHost =
			new OverlayHost (dbAgent.getHostID(currentHost.toLowerCase()),
					 currentHost.toLowerCase());
		    OverlayHost neighborHost =
			new OverlayHost (dbAgent.getHostID(host.toLowerCase()),
				     host.toLowerCase());
		    AddLinkEvent addLinkEvent =
			new AddLinkEvent(homeHost, neighborHost);
		    dbAgent.InsertEventIntoTables(time, addLinkEvent);
		}
	    }
	}
        else if (curline.indexOf("PROBE_RESPONSE") != -1) {
            String host;
            double time = Double.parseDouble(curline.substring(0, curline.indexOf(':')));
            if (curline.indexOf("Send") != -1) {
                int toPos = curline.indexOf("to");
                host = curline.substring(toPos + 3);
            }
            else {
		dbAgent.setLatestEventTime(time);
                this.save_time = time;
                int fromPos = curline.indexOf("from");
                int lastSpacePos = curline.lastIndexOf(" ");
                host = curline.substring(fromPos + 5, lastSpacePos);
            }
        }
        else if (curline.indexOf("ESTIMATE_DELAY_RESPONSE") != -1) {
            String host;
            double time = Double.parseDouble(curline.substring(0, curline.indexOf(':')));
            if (curline.indexOf("Send") != -1) {
                int toPos = curline.indexOf("to");
                host = curline.substring(toPos + 3);
            }
            else {
		dbAgent.setLatestEventTime(time);
                this.save_time = time;
                int fromPos = curline.indexOf("from");
                int lastSpacePos = curline.lastIndexOf(" ");
                host = curline.substring(fromPos + 5, lastSpacePos);
            }
        }
        else if (curline.indexOf("CANCEL_NBR") != -1) {
            String host;
            double time = Double.parseDouble(curline.substring(0, curline.indexOf(':')));
	    dbAgent.setLatestEventTime(time);
            this.save_time = time;
            if (curline.indexOf("Send") != -1) {
                int toPos = curline.indexOf("to");
                host = curline.substring(toPos + 3);
            }
            else {
                int fromPos = curline.indexOf("from");
                int lastSpacePos = curline.lastIndexOf(" ");
                host = curline.substring(fromPos + 5, lastSpacePos);
            }
            OverlayHost homeHost =
              new OverlayHost (dbAgent.getHostID(currentHost.toLowerCase()),
                               currentHost.toLowerCase());
            OverlayHost neighborHost =
              new OverlayHost (dbAgent.getHostID(host.toLowerCase()),
                                   host.toLowerCase());
            DropLinkEvent dropLinkEvent =
              new DropLinkEvent(homeHost, neighborHost);
            dbAgent.InsertEventIntoTables(time, dropLinkEvent);
        }
    }
}
