package cl.altiuz.reports.zmq;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.rmi.RemoteException;

public class ObjetoRemoto {

	private static boolean isWindows = System.getProperty("os.name").contains(
			"Windows");;

	/**
	 * 
	 */
	private static final long serialVersionUID = -6160527847042641482L;

	private static final String OD_LINK_HEADER = ">>>OnDemand Link File Header -- Do Not Modify<<<";

	public byte[] getDoc(String path, int doc_off, int doc_len, int comp_off,
			int comp_len, char compressionType) throws RemoteException {
		byte[] data;

		try {
			if (isWindows) {
				path = getWindowsPath(path);
			}
			data = decompress(path, doc_off, doc_len, comp_off, comp_len,
					compressionType);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RemoteException(e.getMessage(), e);
		} catch (InterruptedException e) {
			e.printStackTrace();
			throw new RemoteException(e.getMessage(), e);
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RemoteException(e.getMessage(), e);
		}
		return data;
	}

	private String getWindowsPath(String path) throws FileNotFoundException,
			IOException {
		File link = new File(path);
		FileReader fReader = null;
		BufferedReader bReader = null;
		String line = null;
		try {
			fReader = new FileReader(link);
			bReader = new BufferedReader(fReader);

			char[] cbuf = new char[(int) link.length()];
			bReader.read(cbuf);
			line = new String(cbuf).trim();
		} finally {
			if (bReader != null) {
				bReader.close();
			}
			if (fReader != null) {
				fReader.close();
			}
		}

		if (line.startsWith(OD_LINK_HEADER)) {
			path = line.substring(OD_LINK_HEADER.length());
		} else {
			throw new IllegalArgumentException("Invalid OD Link file");
		}
		return path;
	}

	private byte[] decompress(String path, int doc_off, int doc_len,
			int comp_off, int comp_len, char compressionType)
			throws IOException, InterruptedException {
		File outFile = null;
		byte[] result = null;
		try {
			// TODO Cache decompressed files
			outFile = File.createTempFile("bin", null);
			// outFile = new File("/tmp/a");
			Runtime rt = Runtime.getRuntime();
			String arsadmin = Config.getString("ObjetoRemoto.arsadmin_path");
			String[] cmd = {
					isWindows ? '"' + arsadmin + ".exe" + '"' : arsadmin,
					"decompress", "-c", String.valueOf(compressionType), "-s",
					path, "-o", outFile.getAbsolutePath(), "-b",
					Integer.toString(comp_off, 10), "-l",
					Integer.toString(comp_len, 10) };
			Process proc = rt.exec(cmd);

			StreamGobbler errorGobbler = new StreamGobbler(
					proc.getErrorStream(), "ERROR");

			// any output?
			StreamGobbler outputGobbler = new StreamGobbler(
					proc.getInputStream(), "OUTPUT");

			// kick them off
			errorGobbler.start();
			outputGobbler.start();
			proc.waitFor();

			errorGobbler.terminate();
			outputGobbler.terminate();
			proc.getErrorStream().close();
			proc.getInputStream().close();
			proc.getOutputStream().close();

			if (outFile.length() == 0) {
				throw new IllegalArgumentException("No data decompressed");
			}

			FileInputStream fis = null;
			ByteArrayOutputStream baos = null;
			byte[] buffer = new byte[doc_len];

			try {
				fis = new FileInputStream(outFile);
				fis.skip(doc_off);
				int bytesRead = fis.read(buffer);
				if (bytesRead != -1) {
					baos = new ByteArrayOutputStream();
					do {
						baos.write(buffer, 0,
								bytesRead < doc_len - baos.size() ? bytesRead
										: doc_len - baos.size());
						bytesRead = fis.read(buffer);
					} while (bytesRead != -1 && baos.size() < doc_len);
					if (bytesRead < doc_len - baos.size()) {
						baos.write(buffer, 0, doc_len - baos.size());
					}
					result = baos.toByteArray();
					if (result.length != doc_len) {
						throw new IllegalArgumentException("pifia");
					}
				}
			} finally {
				if (fis != null) {
					fis.close();
				}
				if (baos != null) {
					baos.close();
				}
			}

		} finally {
			if (outFile != null && outFile.exists()) {
				outFile.delete();
			}
		}
		return result;
	}

	class StreamGobbler extends Thread {
		InputStream is;
		String type;
		private boolean running = true;

		StreamGobbler(InputStream is, String type) {
			this.is = is;
			this.type = type;
		}

		public void run() {
			InputStreamReader isr = null;
			BufferedReader br = null;
			try {
				isr = new InputStreamReader(is);
				br = new BufferedReader(isr);
				String line = null;
				while (running && (line = br.readLine()) != null) {
					System.out.println(type + ">" + line);
				}
			} catch (IOException ioe) {
				if (!"Bad file descriptor".equals(ioe.getMessage())
						&& !"Stream closed".equals(ioe.getMessage())) {
					ioe.printStackTrace();
				}
			} finally {
				try {
					if (br != null) {
						br.close();
					}
					if (isr != null) {
						isr.close();
					}
					if (is != null) {
						is.close();
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		public void terminate() {
			running = false;

		}

	}

}
