package net.xdevelop.jpclient;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

/**
 * The executor to execute the Python script and get the result with JSON format.
 * 
 * Usage:
 * <pre>
 *   PyServeContext.init(host, port);
 *   PyExecutor executor = PyServeContext.getExecutor();
 *   PyResult rs = executor.exec(script);
 *   if (rs.isSuccess()) {
 *   	System.out.println(rs.getResult());
 *   }
 *   else {
 *   	System.out.println(rs.getMsg());
 *   }
 * </pre>
 * 
 * The script should ends with
 * _result_ = "The value returns to client"
 * 
 * The _result_ can be got by Result.getResult(). 
 * If _result_ value is list, tuple, dict, ... it will be converted to JSON string. 
 * 
 * @author john.huang
 *
 */
public class PyExecutor {
	// Max script size 8M
	private final static int MAX_SCRIPT_SIZE = 1024 * 1024 * 8;
	
	PyServeContext context;
	
	PyExecutor(PyServeContext context) {
		this.context = context;
	}
	
	/**
	 * Executes a string format script, each line should split by "\n" or "\r" or "\r\n".
	 * 
	 * Sample:
	 * 		String script = "a = 3\nb = 2\n_result_ = a * b\n"; 
	 * 
	 * @param script
	 * @return execution result, success: if executes successfully, msg: error message if failed, result: the _result_ returns from PyServe
	 */
	public PyResult exec(String script) {
		if (context == null) {
			PyServeContext.getResultOfException("PySeveContext has not been initialized.");
		}
		
		if (script.length() > MAX_SCRIPT_SIZE) {
			PyServeContext.getResultOfException("Exceeds the max script size limit (8M).");
		}
		return context.executeScript(script);
	}
	
	/**
	 * Execute a Python script file
	 * 
	 * @param scriptFile
	 * @return
	 */
	public PyResult exec(File scriptFile) {
		try {
			return exec(new FileInputStream(scriptFile));
		}
		catch (FileNotFoundException e) {
			return PyServeContext.getResultOfException(e);
		}
	}
	
	/**
	 * Read script from the stream and execute it
	 * 
	 * @param scriptStream
	 * @return
	 */
	public PyResult exec(InputStream scriptStream) {
		try {
			String script = streamToString(scriptStream);
			return exec(script);
		} 
		catch (Exception e) {
			return PyServeContext.getResultOfException(e);
		}
	}
	
	private String streamToString(InputStream in) throws IOException, PyServeException {
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		OutputStreamWriter out = new OutputStreamWriter(bout);
		InputStreamReader input = new InputStreamReader(in);
		
		char[] buffer = new char[8192];
		
		long count = 0;
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            out.write(buffer, 0, n);
            count += n;
        }

        if (count > MAX_SCRIPT_SIZE) {
        	throw new PyServeException("Exceed the max script size limit (8M).");
        }
        out.flush();
        return bout.toString();		
	}
}