/*
 * 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 static meta.util.FileUtils.path;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import meta.ampl.runner.AMPLException;
import meta.model.Architecture;
import meta.model.Device;
import meta.util.FileUtils;
/**
 * Level 0 AMPL data built via templates 
 */
public class AMPLdata0 {
	private HashMap<String, List<String>> deviceMap;
	private List<String> atmosphere;
	private List<String> core_diffuser;
	private List<String> fan_diffuser;
    private List<String> singlefan_dtc;
    private List<String> singlefan_ndtc;
    private List<String> multifan_dtc;
    private List<String> multifan_ndtc;
    private List<String> singleprop_dtc;
    private List<String> singleprop_ndtc;
    private List<String> multiprop_dtc;
    private List<String> multiprop_ndtc;
    private List<String> core;
    private List<String> fan_nozzle;
    private List<String> core_nozzle;
    private List<String> embedded;
    
    private String tdir;
	public AMPLdata0(Properties properties) throws Exception {
		tdir = properties.getProperty("template.dir");
		deviceMap = new HashMap<String, List<String> >();
		atmosphere = FileUtils.read(path(tdir,"Data_Atmosphere.txt"));
		core_diffuser = FileUtils.read(path(tdir,"Data_Core_Diffuser.txt"));
		fan_diffuser = FileUtils.read(path(tdir,"Data_Fan_Diffuser.txt"));		
		singlefan_dtc = FileUtils.read(path(tdir,"Data_Single_Fan_(DTC).txt"));
		singlefan_ndtc = FileUtils.read(path(tdir,"Data_Single_Fan_(nDTC).txt"));
		multifan_dtc = FileUtils.read(path(tdir,"Data_Multiple_Fans_(DTC).txt"));
		multifan_ndtc = FileUtils.read(path(tdir,"Data_Multiple_Fans_(nDTC).txt"));
		singleprop_dtc = FileUtils.read(path(tdir,"Data_Single_Front_Prop.txt"));
		singleprop_ndtc = FileUtils.read(path(tdir,"Data_Single_Rear_Prop.txt"));
		multiprop_dtc = FileUtils.read(path(tdir,"Data_Multiple_Front_Props.txt"));
		multiprop_ndtc = FileUtils.read(path(tdir,"Data_Multiple_Rear_Props.txt"));
		core = FileUtils.read(path(tdir,"Data_Core.txt"));
		fan_nozzle = FileUtils.read(path(tdir,"Data_Fan_Nozzle.txt"));
		core_nozzle = FileUtils.read(path(tdir,"Data_Core_Nozzle.txt"));
		embedded = FileUtils.read(path(tdir,"Data_Embedded.txt"));

		deviceMap.put("Atmosphere", atmosphere);
		deviceMap.put("Core_Diffuser", core_diffuser);
		deviceMap.put("Fan_Diffuser", fan_diffuser);
		deviceMap.put("Core", core);
		deviceMap.put("Single_Fan_(DTC)", singlefan_dtc);
		deviceMap.put("Single_Fan_(nDTC)", singlefan_ndtc);
		deviceMap.put("Multiple_Fans_(DTC)", multifan_dtc);
		deviceMap.put("Multiple_Fans_(nDTC)", multifan_ndtc);
		
		deviceMap.put("Single_Front_Prop", singleprop_dtc);
		deviceMap.put("Single_Rear_Prop", singleprop_ndtc);
		deviceMap.put("Multiple_Front_Props", multiprop_dtc);
		deviceMap.put("Multiple_Rear_Props", multiprop_ndtc);
		
		deviceMap.put("Core_Nozzle", core_nozzle);
		deviceMap.put("Fan_Nozzle", fan_nozzle);
		deviceMap.put("Embedded", embedded);
	}
	/**
	 * 
	 * @param source - source index
	 * @param sink   - sink index
	 * @param template - 
	 * @return
	 */
	private List<String> newSourceDevice(String source, String sink, List<String> template) {
		List<String> lines = new ArrayList<String>();
		for (String line : template) {
			String s = line.replaceAll("\\$", source);
			s = s.replaceAll("%", sink);
			lines.add(s);
		}
		return lines;
	}
	/**
	 * 
	 * @param source - source index
	 * @param sink   - sink index
	 * @param template - 
	 * @return
	 */
	private List<String> newDevice(String source, List<String> template) {
		List<String> lines = new ArrayList<String>();
		for (String line : template) {
			String s = line.replaceAll("\\$", source);
			lines.add(s);
		}
		return lines;
	}
	/**
	 * Build the AMPL data for the model
	 * An atmosphere 'device' is added for level 0 with device number 99
	 * @param arch
	 * @return ampl data for model
	 * @throws AMPLException
	 */
	 public List<String> build(Architecture arch) throws Exception {
	 // used to decide if device has already been seen	 	 
	 ArrayList<String> model = new ArrayList<String>();
	 List<String> at = deviceMap.get("Atmosphere");
	 List<String> amplatDevice = newSourceDevice("99","99",at );
	 model.addAll(amplatDevice);
	 int[] src = arch.getSourceIndexes();
	 int[] sink = arch.getSinkIndexes();
	 // go through the link table and find all the devices.
	 // use a hash so we only have one occurrance of each device.
	 Set<Integer> devIndexes = new HashSet<Integer>();
	 for ( int i=0; i< src.length;i++) {
		 int j = src[i];
		 devIndexes.add(j);
	 }
	 for ( int i=0; i< src.length;i++) {
		 int j = sink[i];
		 devIndexes.add(j);
	 }
	 List<Integer> list = new ArrayList<Integer>(devIndexes);
	  for (int i = 0; i < list.size(); i++) {  
		  Integer o = list.get(i);
		  int j = o.intValue();
		  Device device = arch.getDevice(j);
		  String name = device.getName(); 
		  List<String> template = deviceMap.get(name);
		  String devID = Integer.toString(j);
		  List<String> temp = newDevice(devID,template);
		  model.addAll(temp);
 	  }
	  List<String> objective = getObjective();
	  model.addAll(objective);
	 return  model;
	}
 
	/**
	 * Return the objective function template
	 */
	private List<String> getObjective() throws Exception {
		return FileUtils.read(path(tdir,"Data_Objective.txt"));
	}
}
