/*
 * 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.aee.service.excel;

import java.io.File;
import java.util.Properties;
import java.util.concurrent.BlockingQueue;

import aee.excel.ExcelApplication;
import aee.excel.Workbook;
import aee.excel.Workbooks;
import aee.excel.Worksheets;
import aee.exception.AeeException;

/**
 * This class manages all Excel interaction for the service. This is done in a
 * dedicated thread since RMI dispatches calls on multiple threads. RMI calls
 * other than the first call fail when performing an OLE operation, most probably because
 * SWT can only run on the display thread. Two blocking queues are used: an input
 * queue that contains excel operations to perform and an output queue that contains
 * excel results, errors
 */
public class ExcelProxy extends Thread {
	private BlockingQueue<Command>        inq;
	private BlockingQueue<CommandResult>  outq;
	private Properties                    properties;
	
	private ExcelApplication excel;
	private Workbooks        workbooks;
	private Workbook         workbook;
	private Worksheets       worksheets;

	/**
	 * Constructor
	 *
	 * @param inq        The input queue of Excel commands to execute 
	 * @param outq       The output queue of command results
	 * @param properties The service properties
	 */
	public ExcelProxy(BlockingQueue<Command> inq, BlockingQueue<CommandResult> outq, 
			         Properties properties) {
		super("ExcelProxyThread");
		this.inq        = inq;
		this.outq       = outq;
		this.properties = properties;
		
		initExcel();
	}

	/* (non-Javadoc)
	 * @see java.lang.Thread#run()
	 */
	@Override
	public void run() {
		while (true) {
			try {
				Command       cmd    = inq.take();
				CommandResult result = cmd.execute(this);
				outq.add(result);

			} catch (InterruptedException e) {
				outq.add(new CommandResult(e));
			}
		}
	}

	/**
	 * Initialize Excel -- no excel instance is running
	 */
	private void initExcel() {
		excel      = null;
		workbooks  = null;
		workbook   = null;
		worksheets = null;
	}
	
	/**
	 * Start excel and create basic objects
	 * @param level  Current execution level
	 * @throws AeeException if any SWT/COM error
	 */
	public void startExcel(int level) throws AeeException {
		if (! hasExcel()) {
			excel      = new ExcelApplication();
			workbooks  = excel.getWorkbooks();
			workbook   = workbooks.open(getExcelFn(level));
			worksheets = workbook.getWorksheets();
			excel.setVisible(Boolean.parseBoolean(properties.getProperty("excel.visible")));
			excel.setInteractive(true);
		}
	}
	
	/**
	 * Report the Excel filename. If it starts with "%s" then replace
	 * the %s with the data directory
	 * @param level  Current execution level
	 * @return The full pathname to the excel file;
	 */
	private String getExcelFn(int level) {
		String fn = properties.getProperty(String.format("excel.file.%d", level));
		if (fn.startsWith("%s")) {
			String datadir = properties.getProperty("datadir");
			if (datadir == null)
				datadir = "";
			else
				datadir = String.format("%s%c", datadir, File.separatorChar);
			fn = String.format(fn, datadir);
		}
		return fn;
	}

	/**
	 * Shut excel down
	 */
	public void stopExcel() {
		if (hasExcel())
			try {
				excel.quit(true);
			} catch (AeeException aex) {
			}
		if (excel      != null) excel.dispose();
		if (workbooks  != null) workbooks.dispose();
		if (workbook   != null) workbook.dispose();
		if (worksheets != null) worksheets.dispose();
		
		initExcel();
	}

	/**
	 * Report if Excel was started
	 * @return true if started
	 */
	public boolean hasExcel() {
		return (excel != null);
	}
	
	/**
	 * Report the application COM object
	 * @return The application
	 */
	public ExcelApplication getApplication() {
		return excel;
	}
	
	/**
	 * Report the worksheets COM object
	 * @return The Worksheets
	 */
	public Worksheets getWorksheets() {
		return worksheets;
	}
}
