package eu.dnetlib.broker.common.utils;

import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MapValue {

	private MapValueType type = MapValueType.STRING;
	private Object value = "";

	private static final Log log = LogFactory.getLog(MapValue.class);

	public MapValue() {}

	public MapValue(final MapValueType type, final Object value) {
		this.type = type;
		this.value = value;
	}

	public MapValueType getType() {
		return this.type;
	}

	public void setType(final MapValueType type) {
		this.type = type;
	}

	public Object getValue() {
		return this.value;
	}

	public void setValue(final Object value) {
		this.value = value;
	}

	public Object asObject() {
		if (this.value == null) {
			log.warn("Object is NULL");
			return null;
		}
		try {
			switch (this.type) {
			case STRING:
			case INTEGER:
			case FLOAT:
			case BOOLEAN:
			case DATE:
				return asSimpleObject(getType(), getValue().toString());
			case LIST_STRING:
				return ((List<?>) getValue()).stream().map(o -> asSimpleObject(MapValueType.STRING, o.toString())).collect(Collectors.toList());
			case LIST_INTEGER:
				return ((List<?>) getValue()).stream().map(o -> asSimpleObject(MapValueType.INTEGER, o.toString())).collect(Collectors.toList());
			case LIST_FLOAT:
				return ((List<?>) getValue()).stream().map(o -> asSimpleObject(MapValueType.FLOAT, o.toString())).collect(Collectors.toList());
			case LIST_BOOLEAN:
				return ((List<?>) getValue()).stream().map(o -> asSimpleObject(MapValueType.BOOLEAN, o.toString())).collect(Collectors.toList());
			case LIST_DATE:
				return ((List<?>) getValue()).stream().map(o -> asSimpleObject(MapValueType.DATE, o.toString())).collect(Collectors.toList());
			default:
				log.warn("Invalid type: " + this.type);
				return null;
			}
		} catch (final Exception e) {
			log.warn("Error parsing value: " + this);
			return null;
		}
	}

	private Object asSimpleObject(final MapValueType type, final String s) {
		try {
			switch (type) {
			case STRING:
				return s.toString();
			case INTEGER:
				return s.contains(".") ? NumberUtils.toLong(StringUtils.substringBefore(s, "."), 0) : NumberUtils.toLong(s, 0);
			case FLOAT:
				return NumberUtils.toDouble(s, 0);
			case BOOLEAN:
				return BooleanUtils.toBoolean(s);
			case DATE:
				return DateParser.parse(s);
			default:
				log.warn("Unmamaged type: " + type);
				return null;
			}
		} catch (final Exception e) {
			log.warn("Error parsing value: " + s + " - type: " + type);
			return null;
		}
	}

	@Override
	public String toString() {
		return String.format("[ type; %s, value: %s ]", getType(), getValue());
	}
}
