/*
 * 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.ampl.runner;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
 *  Create an AMPL process and communicate with it by sending
 *  commands through stdin/stdout. Use a BlockingQueue to 
 *  keep the stdin thread alive waiting for the next request.
 */
public class AMPLprocessImpl implements AMPLprocess {
    private BlockingQueue<List<String>> reqQ = null;
    public void runner() throws IOException,AMPLException  {

    
    	String working = getAMPLhome();
    	reqQ = new ArrayBlockingQueue<List<String>>(200);
    	File dir = new File(working);
     	ProcessBuilder pb = new ProcessBuilder("cmd","/C","ampl","-i-");
    	pb.directory(dir);
        final Process process = pb.start();
        InputStream output = process.getInputStream();
        Console console = new Console(output);
        console.start();
        OutputStream input = process.getOutputStream();
        Terminal terminal = new Terminal(input,reqQ);
        terminal.start();
         InputStream errOutput = process.getErrorStream();
         ErrorConsole errorConsole = new ErrorConsole(errOutput);
         errorConsole.start();
         new Thread("WaitForAMPL") {
				@Override
				public void run() {
					int rc;
					try {
						rc = process.waitFor();
						System.out.println("AMPL Process exited with rc:"+rc);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}	 
				}
			}.start(); 
         
    }
	
	public Map<String, Variable> getVariables() throws AMPLException {
		AMPLvariables amplVars = new AMPLvariables(); 
		List<String> cmds = amplVars.getCmds();
		reqQ.add(cmds); 
		return amplVars.getVariables();
	}
	
	public void setData(List<String> text) throws AMPLException {
		List<String> list = new ArrayList<String>();
		list.add("data;");
		list.addAll(text);
		list.add("model;");
		reqQ.add(list);
		
	}

	public void setModel(List<String> text) throws AMPLException {
		reqQ.add(text);
	}
	
	public void setSolver(Solver solver) throws AMPLException {
	  post("option solver ipopt;");	
	}
	
	public void solve() throws AMPLException {
	   post("solve;");
	}
	
	public void reset() throws AMPLException {
		post("reset;");
	}
	/**
	 * Post a command to the AMPL process
	 * @param text
	 */
	private void post(String text) {
		List<String> list = new ArrayList<String>();	
		list.add(text);
		reqQ.add(list);
	}
	
	public void shutdown() throws AMPLException {
		post("quit;");
		
	}
	
	public SolutionStatus getSolutionStatus() throws AMPLException {
		AMPLsolution solution = new AMPLsolution();
		List<String> cmds = solution.getCmds();
		reqQ.add(cmds); 
		return solution.getSolutionStatus();
	}
	
	public String getAMPLhome() throws AMPLException {
		String amplHome = System.getProperty("AMPL_HOME");
		if ( amplHome == null) {
			throw new AMPLException("VM Argument -DAMPL_HOME not defined");
		}
		File file = new File(amplHome);
		if (! file.isDirectory() ) {
			String msg = String.format("-DAMPL_HOME=%s is not a directory", amplHome);
			throw new AMPLException(msg);
		}
		return amplHome;
	}
}
