import java.io.*;
import java.net.*;

//custom component by callen shaw for cs2650 hw4
public class CtsBSComp {
   
    private MsgEncoder me;
    private MsgDecoder md;
    
    //specify the server socket, and limits for blood sugar.  anything lower
    //than or equal to lowBs or >= highBs will return an "abnormal" diagnosis.
    public CtsBSComp (Socket s, int lowBs, int highBs, String name) {
        
        try{
            me = new MsgEncoder();
            md = new MsgDecoder(s.getInputStream());
            KeyValueList l = new KeyValueList();
            KeyValueList prf = getDefaultProfile("profile.properties");
			System.out.println("BS-Monitor component (low="+lowBs+",high="+highBs+").  Connecting to server (ID=23)...");
            l.addPair("MsgID", "23");
            l.addPair("Name", name);
            me.sendMsg(l, s.getOutputStream());

            while(true){
                System.out.println("Listening for message...");
                l = md.getMsg();
                if(l == null)
                	throw new RuntimeException("The connection was closed.");
                System.out.println("debug: got msg. " + l);
                int msgID = Integer.parseInt(l.getValue("MsgID"));
				System.out.println("Message Received. ID="+msgID);
				 
				 switch(msgID){
					 case 22: 
						 System.out.println("KillComponent (22) not expected, but still will die.");
						 System.exit(-1);
						 break;
					 case 25:
						System.out.println("Received Deactivate Component (25).  Shutting down.");
						System.exit(0);
					 break;
					 case 26: 
						System.out.println("Init ACK from server. (ID=26)");
					 break;
					 case 41:
						 // take in 41 return 42
						 int bs = Integer.parseInt(l.getValue("Blood Sugar"));
						 String alertStr = "normal";
						 if(bs <= lowBs || bs >= highBs)
							 alertStr = "ab" + alertStr;
						 KeyValueList msgRet = new KeyValueList();
						 msgRet.addPair("MsgID", "42");
						 msgRet.addPair("Description", "Component '" + name + "' generates BS Alert " + alertStr);
						 msgRet.addPair("Name", name);						 
						 msgRet.addPair("Diagnosis", alertStr);
						 msgRet.addPair("Blood Sugar", bs+"");
						 msgRet.addPair("DateTime", l.getValue("DateTime"));
						 for(int i=0; i<prf.size(); i++)
							 msgRet.addPair(prf.keyAt(i), prf.valueAt(i));
						 me.sendMsg(msgRet,s.getOutputStream());
						 System.out.println("Sending (42):\n"+msgRet);
					 break;
					 
					 default: System.out.println("BS-monitor does not recognize server msg: ID="+msgID);break;
				 }
            }
        }
        catch (Exception e) {
			System.out.println("The monitor shut down due to errors.");
            System.out.println("An exception occurred: "+e);
			e.printStackTrace();
        }
        try { System.in.read(); } catch( Throwable thr ) {};

    }
        
    private static KeyValueList cacheProfile = null;
    private static KeyValueList getDefaultProfile(String propertiesFile)
    {
    	if(cacheProfile != null)
    		return cacheProfile;
    	try{
	    	KeyValueList newKVL = new KeyValueList();
	    	BufferedReader r = new BufferedReader(new FileReader(propertiesFile));
	    	String line;
	    	while((line=r.readLine()) != null){
	    		int splitLoc = line.indexOf(':');
	    		if(splitLoc < 0)
	    			splitLoc = line.indexOf('=');
	    		else if(line.indexOf('=') >= 0)
	    			splitLoc = Math.min(line.indexOf('='), splitLoc);
	    		newKVL.addPair(line.substring(0, splitLoc), line.substring(splitLoc+1));
	    	}
	    	if(cacheProfile == null)
	    		cacheProfile = newKVL;
	    	return newKVL;
    	}catch(Exception ex){
			throw new RuntimeException("Could not read property file: " + propertiesFile);
    	}
    }
    
    public static void main(String[] args) {
        String address;
        int port;
        int bsLow = 0;
        int bsHigh = 0;
        String name = null;
        if(args.length < 3)
        	System.out.println("Usage: java CtsBSComp bsLow bsHigh CompName [serverIp=127.0.0.1] [serverPort=7999]");
        
        bsLow = Integer.parseInt(args[0]);
        bsHigh = Integer.parseInt(args[1]);
        name = args[2];
        
        if(args.length > 3)
            address = args[3];
        else
            System.out.println("No address given, assuming " + (address = "127.0.0.1"));

        if(args.length > 4)
            try{
                port = Integer.parseInt(args[4]);
            }catch(Exception e){
				e.printStackTrace();
				System.out.println("No port given, assuming " + (port = 7999));
            }
        else
            System.out.println("No port given, assuming " + (port = 7999));

        try {
            System.out.println("Address: "+address);
            System.out.println("Port: "+port);
            
            Socket s = new Socket(address,port);
            CtsBSComp m = new CtsBSComp(s, bsLow, bsHigh, name);
            System.out.println("monitor done running.");
        }
         
        catch (Exception e) {
			e.printStackTrace();
			System.out.println("An error occurred during CtsBSComp initialization. Now exiting. " + e);
        }
    }
}