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

//custom component by callen shaw for cs2650 hw4
public class CtsEnumComp {
    private Socket s;
    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 CtsEnumComp (Socket s) {
        this.s = s;
        try{
            me = new MsgEncoder();
            md = new MsgDecoder(s.getInputStream());
            KeyValueList l = new KeyValueList();
            //KeyValueList prf = getDefaultProfile("profile.properties");
			System.out.println("Enumerator component.  Connecting to server (ID=23)...");
            l.addPair("MsgID", "23");
            l.addPair("Name", "CtsEnumComp");
            OutputStream sOut = s.getOutputStream(); 
            me.sendMsg(l, sOut);

            l = md.getMsg();
            
            if(l == null)
            	throw new RuntimeException("Init Msg(26) not received: connection closed early.");
            int msgID = Integer.parseInt(l.getValue("MsgID"));
            if(msgID != 26)
            	throw new RuntimeException("Init Msg(26) not received: wrong msgId: " + msgID);
            int numProcs = 8;
            int[] outIds = new int[]{23,42};
            int[] inIds = new int[]{26,41,25};
            Runtime rt = Runtime.getRuntime();
            System.out.println("Msg(26) received from server. init complete. spawning "+numProcs+" processes...");
            for(int i=0; i<numProcs; i++)
            {
                l = new KeyValueList();
            	int step = (int)(i * 100f / (numProcs - 1) + 50); //range is 50-150, equal sized segments
            	int low = step - 20;
            	int high = step + 25; //can be changed later if needed, but just a simple range now
            	//System.out.println("Sending server Create Msg(20)...");
            	l.addPair("MsgID", "20");
                l.addPair("Name", "c"+(i+1));
                l.addPair("Security Level", "1");
                l.addPair("Source Code", "baz");
                l.addPair("Passcode", "****");
                for(int j=0;j<inIds.length;j++)
                	l.addPair("InputMsgID "+(j+1), inIds[j]+"");
                for(int j=0;j<outIds.length;j++)
                	l.addPair("OutputMsgID "+(j+1), outIds[j]+"");
                System.out.println("Sending MsgID("+l.getValue("MsgID")+") Name("+l.getValue("Name")+") ...");
                me.sendMsg(l, sOut);
                System.out.println("Sent.");
                //System.out.println(l + "");
                String cmd = "cmd /c start java CtsBSComp "+low+" "+high+" c"+(i+1);
            	System.out.println("exec: "+cmd);
            	rt.exec(cmd);
            	System.out.println("Successfully spawned process!");
            }

/*            while(true){
                System.out.println("Listening for message.");
                l = md.getMsg();
                if(l == null)
                	continue;
                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 Enumerator shut down due to errors.");
            System.out.println("An exception occurred: "+e);
			e.printStackTrace();
        }
        System.out.println("Enumeration complete.");
    }
        
    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));
	    	}
	    	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;
        String name = "CtsEnumComp";
        if(args.length == 1 && args[0].equals("-?"))
        	System.out.println("Usage: java CtsEnumComp [serverIp=127.0.0.1] [serverPort=7999]");
        
        if(args.length > 0)
            address = args[0];
        else
            System.out.println("No address given, assuming " + (address = "127.0.0.1"));

        if(args.length > 1)
            try{
                port = Integer.parseInt(args[1]);
            }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);
            CtsEnumComp m = new CtsEnumComp(s);
            System.out.println("enumerator finished running.");
        }
         
        catch (Exception e) {
			e.printStackTrace();
			System.out.println("An error occurred during CtsEnumComp initialization. Now exiting. " + e);
        }
    }
}