package omq.common.util;

import java.io.IOException;
import java.util.Properties;

import omq.common.event.Event;
import omq.common.message.Request;
import omq.common.message.Response;
import omq.common.util.Serializers.GsonImp;
import omq.common.util.Serializers.ISerializer;
import omq.common.util.Serializers.JavaImp;
import omq.common.util.Serializers.KryoImp;
import omq.exception.EnvironmentException;
import omq.exception.SerializerException;
import omq.server.RemoteObject;

/**
 * 
 * @author Sergi Toda <sergi.toda@estudiants.urv.cat>
 * 
 */
public class Serializer {
	public static String kryo = KryoImp.class.getCanonicalName();
	public static String java = JavaImp.class.getCanonicalName();
	public static String gson = GsonImp.class.getCanonicalName();

	public static ISerializer serializer;

	private static Boolean getEnableCompression() {
		Boolean enableCompression = false;
		try {
			Properties env = Environment.getEnvironment();
			enableCompression = Boolean.valueOf(env.getProperty(ParameterQueue.ENABLECOMPRESSION, "false"));
		} catch (EnvironmentException e) {
			e.printStackTrace();
		}

		return enableCompression;
	}

	public static ISerializer getInstance() throws SerializerException {
		if (serializer == null) {
			try {
				Properties env = Environment.getEnvironment();
				String className = env.getProperty(ParameterQueue.SERIALIZER_NAME, Serializer.java);

				if (className == null || className.isEmpty()) {
					throw new ClassNotFoundException("Class name is null or empty.");
				}

				serializer = (ISerializer) Class.forName(className).newInstance();
			} catch (Exception ex) {
				throw new SerializerException(ex.getMessage(), ex);
			}
		}

		return serializer;
	}

	public static byte[] serialize(Object obj) throws SerializerException {
		ISerializer instance = getInstance();

		Boolean enableCompression = getEnableCompression();
		if (enableCompression) {
			byte[] objSerialized = instance.serialize(obj);
			try {
				return Zipper.zip(objSerialized);
			} catch (IOException e) {
				throw new SerializerException(e.getMessage(), e);
			}
		} else {
			return instance.serialize(obj);
		}
	}

	public static Request deserializeRequest(byte[] bytes, RemoteObject obj) throws SerializerException {
		ISerializer instance = getInstance();

		Boolean enableCompression = getEnableCompression();
		if (enableCompression) {
			try {
				byte[] unZippedBytes = Zipper.unzip(bytes);
				return instance.deserializeRequest(unZippedBytes, obj);
			} catch (IOException e) {
				throw new SerializerException(e.getMessage(), e);
			}
		} else {
			return instance.deserializeRequest(bytes, obj);
		}
	}

	public static Response deserializeResponse(byte[] bytes, Class<?> type) throws SerializerException {
		ISerializer instance = getInstance();

		Boolean enableCompression = getEnableCompression();
		if (enableCompression) {
			try {
				byte[] unZippedBytes = Zipper.unzip(bytes);
				return instance.deserializeResponse(unZippedBytes, type);
			} catch (IOException e) {
				throw new SerializerException(e.getMessage(), e);
			}
		} else {
			return instance.deserializeResponse(bytes, type);
		}
	}

	public static Event deserializeEvent(byte[] bytes) throws SerializerException {
		ISerializer instance = getInstance();

		Boolean enableCompression = getEnableCompression();
		if (enableCompression) {
			try {
				byte[] unZippedBytes = Zipper.unzip(bytes);
				return instance.deserializeEvent(unZippedBytes);
			} catch (IOException e) {
				throw new SerializerException(e.getMessage(), e);
			}
		} else {
			return instance.deserializeEvent(bytes);
		}
	}
}