/*
 * Delivered to the U.S. Government in Accordance with Contract FA8650-10-C-7080.
 *
 * EXPORT CONTROLLED
 * ECCN#   EAR99
 * Warning:  This document contains technical data which is controlled under the
 * Bureau of Industry & Security's Export Administration Regulations and may not be
 * exported or re-exported without authorization by the Bureau of Industry & Security.
 * Diversion contrary to US law is prohibited.
 *
 * (c) 2011 United Technologies Corp.
 * Developed with the sponsorship of the Defense Advanced Research Projects Agency (DARPA).
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this data,
 * including any software or models in source or binary form, as well as any drawings, 
 * specifications, and documentation (collectively "the Data"), to deal in the Data without 
 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Data, and to permit persons to whom the Data
 * is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Data.
 *
 * THE DATA IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS, SPONSORS, DEVELOPERS, CONTRIBUTORS, OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE DATA OR THE
 * USE OR OTHER DEALINGS IN THE DATA.
 */

package meta.model.ampl;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.rmi.Naming;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import meta.ampl.runner.AMPLException;
import meta.ampl.runner.Variable;
import meta.model.Architecture;
import meta.rmi.Service;
import meta.util.FileUtils;


public class AMPLresults {
   private 	Map<String,Variable> map;
   private Map<String,String> devMap = new HashMap<String,String>();
   private Architecture arch;
   public AMPLresults(Architecture arch, Map<String,Variable> map) 	{
	  this.arch = arch;
	  this.map = map; 
   }
   private String getCost(String id) {
	   String scost = String.format("cost%s", id);
	   String cost = "0.0";
	   Variable varCost = map.get(scost); 
	   if ( varCost != null) {
		   cost = varCost.value();
	   }
	   return cost;
   }
   private Element doCoreXML(String odev,String[] tokens) {
	   String cost = getCost(odev);    
	   Variable w = map.get("aircraftweight");
	   Variable totalfuel = map.get("total_fuel");
	   Variable min = map.get("M_in");
	   Variable tsfc = map.get("TSFC");
	   Variable fn = map.get("Thrust_Takeoff_Req");
	   Variable ne = map.get("NumEngines");
	   Variable bpr = map.get("BPR");
	   Variable mcore = map.get("m_core");
	   Variable opr = map.get("OPR");
	   Variable effComp = map.get("IsentropicEfficiency_compressor");
	   Variable effTurb = map.get("Efficiency_turbine");
	   Variable toOut = map.get("To_out_combustor10");
	   toOut.rename("TurbineInletTemperature");
	   Element device = new Element("device");
	   String id = tokens[0];
	   String dn = tokens[1];
	   device.setAttribute("id",id);
	   device.setAttribute("name",dn);
	   device.addContent(w.toElement()); // aircraftweight
	   device.addContent(totalfuel.toElement()) ; 
	   device.addContent(min.toElement());
	   device.addContent(tsfc.toElement());
	   Element eCost = new Element("var");
	   eCost.setAttribute("name","cost");
	   eCost.setAttribute("value",cost);
	   eCost.setAttribute("type","real");
	   device.addContent(eCost);
	   device.addContent(fn.toElement()); // Thrust_Takeoff_Req
	   device.addContent(ne.toElement());
	   device.addContent(mcore.toElement()); 
	   device.addContent(bpr.toElement());
	   device.addContent(opr.toElement()) ;
	   device.addContent(effComp.toElement()); // IsentropicEfficiency_compressor
	   device.addContent(effTurb.toElement());
	   device.addContent(toOut.toElement()) ; 
	   
	   
	   Element engType = new Element("var");
	   engType.setAttribute("name","engine_type");
	   engType.setAttribute("value",arch.getEngineType());
	   device.addContent(engType);
	   
	   return device;
   }
private String doCore(String odev,String[] tokens) {
	   String cost = getCost(odev);    
	   Variable w = map.get("aircraftweight");
	   Variable totalfuel = map.get("total_fuel");
	   Variable min = map.get("M_in");
	   Variable tsfc = map.get("TSFC");
	   Variable fn = map.get("Thrust_Takeoff_Req");
	   Variable ne = map.get("NumEngines");
	   Variable bpr = map.get("BPR");
	   Variable mcore = map.get("m_core");
	   Variable opr = map.get("OPR");
	   Variable effComp = map.get("IsentropicEfficiency_compressor");
	   Variable effTurb = map.get("Efficiency_turbine");
	   Variable toOut = map.get("To_out_combustor10");
	   StringBuilder sb = new StringBuilder();
	   sb.append(tokens[0]);
	   sb.append("\t ");
	   sb.append(tokens[1]);
	   sb.append(": ");
	   add(sb,"aircraftweight",w);
	   add(sb,"totalfuel",totalfuel);
	   add(sb,"M_in",min);
	   add(sb,"TSFC",tsfc);
	   sb.append("cost=");
	   sb.append(cost);
	   sb.append(",");
	   add(sb,"Thrust_Takeoff_Req",fn);
	   add(sb,"NumEngines",ne); 
	   add(sb,"m_core",mcore);
	   add(sb,"BPR",bpr); 
	   add(sb,"OPR",opr);
	   add(sb,"IsentropicEfficiency_compressor",effComp);
	   add(sb,"Efficiency_turbine",effTurb);
	   add(sb,"TurbineInletTemperature",toOut);
	   sb.append("engine_type=");
	   sb.append(arch.getEngineType());
	    
	   
	   return sb.toString();
   }
   private void add( StringBuilder sb, String n, Variable v) {
	  sb.append(n);
	  sb.append("=");
	  String value = "0.0";
	  if ( v != null )value = v.value();
	  sb.append(value);
	  sb.append(", ");
   }
   private Element doComponentXML(String odev,String[] tokens) {
	   Element device = new Element("device");
	   String id = tokens[0];
	   String dn = tokens[1];
	   String cost = getCost(odev);
	   device.setAttribute("id",id);
	   device.setAttribute("name",dn);
	   Element eCost = new Element("var");
	   eCost.setAttribute("name","cost");
	   eCost.setAttribute("value",cost);
	   eCost.setAttribute("type","real");
	   device.addContent(eCost);
	   return device;
   }
private String doComponent(String odev,String[] tokens) {
	   String cost = getCost(odev);
	   String line = String.format("%s\t %s: cost=%s",tokens[0],tokens[1],cost );
	   return line;
   }
  
   public void outXML() {
	   Element root = new Element("architecture");
	   Document doc = new Document(root);
	   String [] toks = arch.getName().split("_");
	   String id = toks[1];
	   root.setAttribute("id",id);
	   root.setAttribute("platform","engine");
	   root.setAttribute("level","0");
	   int dev = 1; // renumber devices sequentially 
	    
	   List<String> lines = arch.getNodeTable();
	   for (String line : lines) {
		   Element outline;
		   String[] tokens = line.split("\\s+");
		   String ds = Integer.toString(dev);
		   String odev = new String(tokens[0]);
		   tokens[0] = ds;
		   devMap.put(odev, ds);
		   dev++;
		   String token = tokens[1];
		   if ( token.equals("Core") ) {
			outline =   doCoreXML(odev,tokens);
		   }
		   else {
			 outline = doComponentXML(odev,tokens);  
		   }
		   root.addContent(outline) ; 
	   }
	   String a = arch.getName();
	   String name = a.replace("Arch", "AMPLOutput");
	   String[] tokens = name.split("_");
	   name = String.format("%s_NT%s", tokens[0],tokens[1]);
	   String tmp = System.getProperty("java.io.tmpdir");
	   tmp = "."; // write to working directory instead
	   String fn = String.format("%s\\a.%s", tmp, id);
	   String t = String.format("AMPL Results for %s written to %s",a,fn);
	   System.out.println(t);
	 //  <flow id="1" name="Gas" />
	 //  <flow id="2" name="Mechanical" />
	   Element eflow = new Element("flow");
		  eflow.setAttribute("id","1");
		  eflow.setAttribute("name","Gas");
		  root.addContent(eflow);
		  Element eflow2 = new Element("flow");
		  eflow2.setAttribute("id","2");
		  eflow2.setAttribute("name","Mechanical");
		  root.addContent(eflow2);
		  
		  
	   // Now process updated link table with sequential device mappings.
	    
	   String nameOutLT = name.replace("NT", "LT");
	   String nameInLT = nameOutLT.replace("AMPLOutput", "AEEOutput");
	   nameInLT = String.format("data\\AEEOutput\\%s.txt", nameInLT);
	   nameOutLT = String.format("%s.txt",nameOutLT);
	   try {
		List<String>  inLT = FileUtils.read(nameInLT);
		 
		inLT.remove(0);
		for ( String line : inLT) {
			  tokens = line.split("\\s+");
			  String src = devMap.get(tokens[1]);
			  String sink = devMap.get(tokens[2]);
			  String n = String.format("%s\t %s\t %s\t %s", tokens[0], src, sink, tokens[3]);
			  Element elink = new Element("link");
			  elink.setAttribute("id",tokens[0]);
			  elink.setAttribute("source",src);
			  elink.setAttribute("sink",sink);
			  elink.setAttribute("flow",tokens[3]);
			  root.addContent(elink);
		}

	    } catch (AMPLException e) {
		e.printStackTrace();
	    }
	    try {
		FileOutputStream out = new FileOutputStream(fn);
		XMLOutputter serializer = new XMLOutputter( Format.getPrettyFormat() );
		serializer.output(doc, out);
		out.flush();
		out.close();  
		sendToRepository(root);
		/*
		 * <service-request name="GetNextArchitecture" >
           <service-arguments>
           </service-arguments>
           </service-request>
		 * 
		 */ 
		
		
	    }
	    catch (Exception e) {
	    	e.printStackTrace();
	    }
   }
   private void sendToRepository(Element eArch) throws Exception {
	   
	   Element eReq = new Element("service-request");
	   Document doc = new Document(eReq);
	   eReq.setAttribute("name","StoreArchitectures");
	   Element eArgs = new Element("service-arguments");
	   Element eCompArgs = new Element("composite_argument");
	   eCompArgs.setAttribute("name","engine");
	   eCompArgs.setAttribute("type","architectures");
	   Element clone = (Element) eArch.clone();
	   eCompArgs.addContent(clone);
	   eArgs.addContent(eCompArgs);
	   eReq.addContent(eArgs);
				 
		XMLOutputter serializer = new XMLOutputter( Format.getPrettyFormat() );
		String request = serializer.outputString(doc);
		Service service = (Service) Naming.lookup("rmi://localhost/repository");
		String xml = service.invoke(request);
		System.out.println("Storing into the repository");
		System.out.println(xml);
   }
public void out() {
	   int dev = 1; // renumber devices sequentially 
	   List<String> out = new ArrayList<String>();
	   List<String> lines = arch.getNodeTable();
	   for (String line : lines) {
		   String outline;
		   String[] tokens = line.split("\\s+");
		   String ds = Integer.toString(dev);
		   String odev = new String(tokens[0]);
		   tokens[0] = ds;
		   devMap.put(odev, ds);
		   dev++;
		   String token = tokens[1];
		   if ( token.equals("Core") ) {
			outline =   doCore(odev,tokens);
		   }
		   else {
			 outline = doComponent(odev,tokens);  
		   }
		   out.add(outline); 
	   }
	   String a = arch.getName();
	   String name = a.replace("Arch", "AMPLOutput");
	   String[] tokens = name.split("_");
	   name = String.format("%s_NT%s", tokens[0],tokens[1]);
	   String tmp = System.getProperty("java.io.tmpdir");
	   tmp = "."; // write to working directory instead
	   String fn = String.format("%s\\%s.txt", tmp, name);
	   String t = String.format("AMPL Results for %s written to %s",a,fn);
	   System.out.println(t);
	   FileUtils.writeFile(fn,out); 
	   // Now write out updated link table with sequential device mappings.
	   List<String> outLT = new ArrayList<String>();
	   String nameOutLT = name.replace("NT", "LT");
	   String nameInLT = nameOutLT.replace("AMPLOutput", "AEEOutput");
	   nameInLT = String.format("data\\AEEOutput\\%s.txt", nameInLT);
	   nameOutLT = String.format("%s.txt",nameOutLT);
	   try {
		List<String>  inLT = FileUtils.read(nameInLT);
		String header = new String(inLT.get(0));
		outLT.add(header);
		inLT.remove(0);
		for ( String line : inLT) {
			  tokens = line.split("\\s+");
			  String src = devMap.get(tokens[1]);
			  String sink = devMap.get(tokens[2]);
			  String n = String.format("%s\t %s\t %s\t %s", tokens[0], src, sink, tokens[3]);
			  outLT.add(n);
		}
		 FileUtils.writeFile(nameOutLT,outLT); 
	    } catch (AMPLException e) {
		e.printStackTrace();
	    }
   }
}
