package com.libreecm.commonAPI.model.objects.properties;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.libreecm.commonAPI.auxiliars.exceptions.NotDefinedIdPropertyDataException;
import com.libreecm.commonAPI.auxiliars.exceptions.NotDefinedPropertyDataValueException;
import com.libreecm.commonAPI.model.objects.ExtensionsData;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class Properties extends ExtensionsData {

	private String id;
	private final Map<String, PropertyData<?>> properties = new LinkedHashMap<String, PropertyData<?>>();
	private final List<PropertyData<?>> propertyList = new ArrayList<PropertyData<?>>();

	/**
	 * Constructor.
	 */
	public Properties() {
	}

	/**
	 * Constructor.
	 * 
	 * @param properties
	 *            initial collection of properties
	 */
	public Properties(Collection<PropertyData<?>> properties) {
		addProperties(properties);
	}

	/**
	 * Shallow copy constructor.
	 * 
	 * Creates a new collection of properties but references the original
	 * property and extension objects.
	 */
	public Properties(Properties properties) {
		if (properties == null) {
			throw new IllegalArgumentException("Properties not set!");
		}

		this.addProperties(properties.getPropertyList());
		this.setExtensions(properties.getExtensions());
	}

	protected void addProperties(Collection<PropertyData<?>> properties) {
		if (properties != null) {
			for (PropertyData<?> prop : properties) {
				addProperty(prop);
			}
		}
	}

	public void addProperty(PropertyData<?> property) {
		if (property.getId()==null)
			throw new NotDefinedIdPropertyDataException(property.toString());
		if (property.getValues()==null || property.getValues().size()==0)
			throw new NotDefinedPropertyDataValueException(property.toString());
		propertyList.add(property);
		properties.put(property.getId(), property);
		
	}

	public String getId() {
		if (this.id == null)
			return null;
		return this.id;
	}

	public Map<String, PropertyData<?>> getProperties() {
		return Collections.unmodifiableMap(properties);
	}

	public List<PropertyData<?>> getPropertyList() {
		return Collections.unmodifiableList(propertyList);
	}

	public void removeProperty(String id) {
		if (id == null) {
			return;
		}

		Iterator<PropertyData<?>> iterator = propertyList.iterator();
		while (iterator.hasNext()) {
			PropertyData<?> property = iterator.next();
			if (id.equals(property.getId())) {
				iterator.remove();
				break;
			}
		}

		properties.remove(id);
	}

	public void replaceProperty(PropertyData<?> property) {
		if (property == null || property.getId() == null) {
			return;
		}

		removeProperty(property.getId());

		propertyList.add(property);
		properties.put(property.getId(), property);
	}

	public void setId(String id) {
		this.id = (id);
	}

	@Override
	public String toString() {
		return "Properties Data [properties=" + propertyList + "]" + super.toString();
	}

}
