/**
 * @license Highcharts JS v2.3.3 (2012-11-02)
 *
 * (c) 20012-2014
 *
 * Author: Gert Vaartjes
 *
 * License: www.highcharts.com/license
 */
package com.highcharts.export.converter;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeoutException;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.gson.Gson;
import com.highcharts.export.pool.PoolException;
import com.highcharts.export.pool.BlockingQueuePool;
import com.highcharts.export.server.Server;
import com.highcharts.export.util.MimeType;

@Service("svgConverter")
public class SVGConverter {

	@Autowired
	private BlockingQueuePool serverPool;
	protected static Logger logger = Logger.getLogger("converter");

	public ByteArrayOutputStream convert(String input, MimeType mime,
			String constructor, String callback, Float width, Float scale) throws SVGConverterException, IOException, PoolException, NoSuchElementException, TimeoutException {

			ByteArrayOutputStream stream = null;

			// get filename
			String extension = mime.name().toLowerCase();
			String outFilename = createUniqueFileName("." + extension);

			Map<String, String> params = new HashMap<String, String>();
			Gson gson = new Gson();

			params.put("infile", input);
			params.put("outfile", outFilename);

			if (constructor != null && !constructor.isEmpty()) {
				params.put("constr", constructor);
			}

			if (callback != null && !callback.isEmpty()) {
				params.put("callback", callback);
			}

			if (width != null) {
				params.put("width", String.valueOf(width));
			}

			if (scale != null) {
				params.put("scale", String.valueOf(scale));
			}

			String json = gson.toJson(params);
			String output = requestServer(json);

			// check for errors
			if (output.substring(0,5).equalsIgnoreCase("error")) {
				logger.debug("recveived error from phantomjs: " + output);
				throw new SVGConverterException("recveived error from phantomjs:" + output);
			}

			stream = new ByteArrayOutputStream();
			if (output.equalsIgnoreCase(outFilename)) {
				// in case of pdf, phantom cannot base64 on pdf files
				stream.write(FileUtils.readFileToByteArray(new File(outFilename)));
			} else {
				// assume phantom is returning SVG or a base64 string for images
				if (extension.equals("svg")) {
					stream.write(output.getBytes());
				} else {
					stream.write(Base64.decodeBase64(output));
				}
			}
			return stream;
	}

	public String requestServer(String params) throws SVGConverterException, TimeoutException, NoSuchElementException, PoolException {
		Server server = null;

		try {
			server = (Server) serverPool.borrowObject();
			String response = server.request(params);

			return response;
		} catch (SocketTimeoutException ste) {
			throw new TimeoutException(ste.getMessage());
		} catch (TimeoutException te) {
			throw new TimeoutException(te.getMessage());
		} catch (PoolException nse) {
				logger.error("POOL EXHAUSTED!!");
				throw new PoolException(nse.getMessage());
		}catch (Exception e) {
			logger.debug(e.getMessage());
			throw new SVGConverterException("Error converting SVG" + e.getMessage());
		} finally {
			try {
				serverPool.returnObject(server, true);
			} catch (Exception e) {
				logger.error("Exception while returning server to pool: " + e.getMessage());
			}
		}
	}

	public String createUniqueFileName(String extension) throws IOException {
		return System.getProperty("java.io.tmpdir") + "/" + RandomStringUtils.randomAlphanumeric(8) + extension;
	}
}