package eu.dnetlib.dlms.jdbc.serialization;

import java.sql.Date;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Helper class to deserialize a collection field of a structure object.
 * 
 * @author lexis
 * 
 */
public class CollectionDeserializer {

	/**
	 * Deserialize a collection field. Collection field serialization is the serialization of the corresponding list +
	 * "|" + ItemType (of the single elements in the collection).
	 * 
	 * @param serializedColl
	 *            string to deserialize
	 * @return Collection
	 */
	public Object deserialize(final String serializedColl) {
		//it depends on the content of collection:
		final String[] collSplitted = serializedColl.split("\\|");
		final String collContent = collSplitted[0];
		final ItemType contentType = ItemType.valueOf(collSplitted[1].trim());
		switch (contentType) {
		case BOOLEAN:
			return this.deserializeCollBoolean(collContent);
		case DATE:
			return this.deserializeCollDate(collContent);
		case DOUBLE:
			return this.deserializeCollDouble(collContent);
		case INT:
			return this.deserializeCollInteger(collContent);
		case LONG:
			return this.deserializeCollLong(collContent);
		case STRING:
		case URL:
			return this.deserializeCollString(collContent);
		case COLL: //collection of collection
			break;
		case D:
			return this.deserializeCollD(collContent);
		case INFORMATION_OBJECT:
			throw new RuntimeException("Unexpected type in collection field: INFORMATION_OBJECT");
		default:
			throw new RuntimeException("Unknown type in collection field: " + contentType);
		}
		return null;
		//I expect s is [el1, el2, etc]: remove the first and last char ([ and ]) and split it on ,
		//		final String valueNoBrackets = serializedColl.substring(1, serializedColl.length() - 1).trim();
		//		if (valueNoBrackets.startsWith("{")) {
		//			return this.deserializeCollD(serializedColl);
		//		} else {
		//			return this.deserializeColl(serializedColl);
		//		}
	}

	/**
	 * A field declared as coll(D) (eg. l:coll({l1:int;l2:string})) is serialized as [{l1=1,l2=a}, {l1=2, l2=b}]
	 * 
	 * @param serializedColl
	 * @return
	 */
	Collection<Map<String, Object>> deserializeCollD(final String serializedColl) {
		//tolgo le parantesi quadre
		final String valueNoBrackets = serializedColl.substring(1, serializedColl.length() - 1).trim();
		final List<Map<String, Object>> res = new ArrayList<Map<String, Object>>();
		//splitto su },
		final String[] collEls = valueNoBrackets.split("},");
		System.out.println("collEls is: " + Arrays.toString(collEls));
		//in collEls I have: {l1=v1,l2=v2 {l1=v11,l2=v12 {l1=v13,l2=v23}
		for (String el : collEls) {

			final Map<String, Object> elMap = new HashMap<String, Object>();
			//rimpiazzo le graffe rimanenti ed eventuali spazi con lo spazio e basta
			el = el.replaceFirst("\\s?\\{\\s?", " ");
			el = el.replaceFirst("\\s?}\\s?", " ");
			System.out.println("El in collEls: " + el);
			//el = l1=v1,l2=v2
			final String[] couples = el.split(",");
			for (final String c : couples) {
				final String[] coupleSplitted = c.split("\\s?=\\s?");
				//System.out.println("Couples should have length 2, is it? " + coupleSplitted.length);
				//TODO: sto buttando dentro stringhe a prescindere dal tipo del campo, per ora va bene ma in generale no!
				elMap.put(coupleSplitted[0].trim(), coupleSplitted[1].trim());
			}
			res.add(elMap);
		}
		return res;
	}

	Collection<String> deserializeCollString(final String serializedColl) {
		//I expect s is [el1, el2, etc]: remove the first and last char ([ and ]) and split it on ,
		final String valueNoBrackets = serializedColl.substring(1, serializedColl.length() - 1).trim();
		final List<String> res = new ArrayList<String>();
		final String[] els = valueNoBrackets.split(",");
		for (final String el : els)
			res.add(el.trim());
		return res;
	}

	Collection<Boolean> deserializeCollBoolean(final String serializedColl) {
		//I expect s is [el1, el2, etc]: remove the first and last char ([ and ]) and split it on ,
		final String valueNoBrackets = serializedColl.substring(1, serializedColl.length() - 1).trim();
		final List<Boolean> res = new ArrayList<Boolean>();
		final String[] els = valueNoBrackets.split(",");
		for (final String el : els)
			res.add(Boolean.parseBoolean(el));
		return res;
	}

	Collection<Double> deserializeCollDouble(final String serializedColl) {
		//I expect s is [el1, el2, etc]: remove the first and last char ([ and ]) and split it on ,
		final String valueNoBrackets = serializedColl.substring(1, serializedColl.length() - 1).trim();
		final List<Double> res = new ArrayList<Double>();
		final String[] els = valueNoBrackets.split(",");
		for (final String el : els)
			res.add(Double.parseDouble(el));
		return res;
	}

	Collection<Integer> deserializeCollInteger(final String serializedColl) {
		//I expect s is [el1, el2, etc]: remove the first and last char ([ and ]) and split it on ,
		final String valueNoBrackets = serializedColl.substring(1, serializedColl.length() - 1).trim();
		final List<Integer> res = new ArrayList<Integer>();
		final String[] els = valueNoBrackets.split(",");
		for (final String el : els)
			res.add(Integer.parseInt(el));
		return res;
	}

	Collection<Long> deserializeCollLong(final String serializedColl) {
		//I expect s is [el1, el2, etc]: remove the first and last char ([ and ]) and split it on ,
		final String valueNoBrackets = serializedColl.substring(1, serializedColl.length() - 1).trim();
		final List<Long> res = new ArrayList<Long>();
		final String[] els = valueNoBrackets.split(",");
		for (final String el : els)
			res.add(Long.parseLong(el));
		return res;
	}

	Collection<Date> deserializeCollDate(final String serializedColl) {
		//I expect s is [el1, el2, etc]: remove the first and last char ([ and ]) and split it on ,
		final String valueNoBrackets = serializedColl.substring(1, serializedColl.length() - 1).trim();
		final List<Date> res = new ArrayList<Date>();
		final String[] els = valueNoBrackets.split(",");
		for (final String el : els)
			res.add(Date.valueOf(el));
		return res;
	}

	/**
	 * [ [v1,v2,v3]|itemType, [v4,v5,v6]|itemType ]
	 * 
	 * @param serializedColl
	 * @return
	 */
	Collection<? extends Object> deserializeCollColl(final String serializedColl) {
		//I expect s is [el1, el2, etc]: remove the first and last char ([ and ]) and split it on ],
		//		final String valueNoBrackets = serializedColl.substring(1, serializedColl.length() - 1).trim();
		//		final List<Object> res = Lists.newArrayList();
		//		final String[] els = valueNoBrackets.split("],");
		//		//els[0]=[v1,v2,v3 	els[1] = [v4,v5,v6]
		//		for (int i = 0; i < els.length; i++) {
		//			String currColl = els[i];
		//			if (i < els.length - 1)
		//				currColl += "]";
		//			res.add(this.deserialize(currColl));
		//		}
		//		return res;
		throw new RuntimeException("Returning fields of tyoe coll(coll(type)) is not yet implemented");
	}
}
