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

import java.util.List;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.libreecm.commonAPI.auxiliars.exceptions.NotDefinedIdPropertyDataException;
import com.libreecm.commonAPI.model.enums.Cardinality;
import com.libreecm.commonAPI.model.enums.PropertyType;
import com.libreecm.commonAPI.model.enums.Updatability;
import com.libreecm.commonAPI.model.objects.Choice;
import com.libreecm.commonAPI.model.objects.ExtensionsData;

/**
 * Base property definition.
 * Defines a customized definition derived from a java type:
 * string, integer, boolean, etc
 * 
 * @cmis 1.0
 */
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
public abstract class PropertyDefinition<T> extends ExtensionsData {

	private String id;
	private String localName;
	private String localNamespace;
	private String displayName;
	private String queryName;
	private String description;
	private PropertyType propertyType;
	private Updatability updatibility;
	private Boolean inherited;
	private Boolean required;
	private Boolean queryable;
	private Boolean orderable;
	private Boolean openChoice;
	private List<T> defaultValue;
	private List<Choice<T>> choices;
	private Cardinality cardinality;
	    
	public PropertyDefinition(){
		
	}
	
	public PropertyDefinition(String name, String id,String description,
			String local_namespace, String local_name, String query_name,
			PropertyType type, Cardinality cardinality, Updatability updatability, 
			boolean queryable, boolean orderable, 
			boolean required, boolean inherited, List<T> default_value,
			boolean open_choice, List<Choice<T>> choices){
		
		this.localName=local_name;
		this.localNamespace=local_namespace;
		this.displayName=name;
		this.queryName=query_name;
		this.description=description;
		this.propertyType=type;
		this.updatibility=updatability;
		this.inherited=inherited;
		this.required=required;
		this.queryable=queryable;
		this.orderable=orderable;
		this.openChoice=open_choice;
		this.defaultValue=default_value;
		this.choices=choices;
		this.cardinality=cardinality;
		this.setId(id);
		
	}
	
	/**
     * Returns the property definition ID.
     * 
     * @return the property definition ID
     * 
     * @cmis 1.0
     */
	public String getId() {
		if (id==null || id.isEmpty())
				throw new NotDefinedIdPropertyDataException(this.toString());
		return id;
	}

    /**
     * Returns the local name.
     * 
     * @return the local name
     * 
     * @cmis 1.0
     */
    public String getLocalName(){
    	return this.localName;
    }

    /**
     * Returns the local namespace.
     * 
     * @return the local namespace
     * 
     * @cmis 1.0
     */
    public String getLocalNamespace(){
    	return this.localNamespace;
    }

    /**
     * Returns the display name.
     * 
     * @return the display name
     * 
     * @cmis 1.0
     */
    public String getDisplayName(){
    	return this.displayName;
    }

    /**
     * Returns the query name
     * 
     * @return the query name
     * 
     * @cmis 1.0
     */
    public String getQueryName(){
    	return this.queryName;
    }
    /**
     * Returns the property description.
     * 
     * @return returns the description
     * 
     * @cmis 1.0
     */
    public String getDescription(){
    	return this.description;
    }

    /**
     * Returns the property type.
     * x
     * @return the property type
     * 
     * @cmis 1.0
     */
    public PropertyType getPropertyType(){
    	return this.propertyType;
    }

    /**
     * Returns the cardinality.
     * 
     * @return the cardinality
     * 
     * @cmis 1.0
     */
    public Cardinality getCardinality(){
    	return this.cardinality;
    }

	/**
	 * @param cardinality the cardinality to set
	 */
	public void setCardinality(Cardinality cardinality) {
		this.cardinality = cardinality;
	}

	/**x
     * Returns the updatability.
     * 
     * @return the updatability
     * 
     * @cmis 1.0
     */
    public Updatability getUpdatibility(){
    	return this.updatibility;
    }

    /**
     * Returns if the property is inherited by a parent type.
     * 
     * @return {@code true} - is inherited; {@code false} - is not inherited;
     *         {@code null} - unknown (noncompliant repository)
     * 
     * @cmis 1.0
     */
    public Boolean isInherited(){
    	return this.inherited;
    }

    /**
     * Returns if the property is required.
     * 
     * @return {@code true} - is required; {@code false} - is not required;
     *         {@code null} - unknown (noncompliant repository)
     * 
     * @cmis 1.0
     */
    public Boolean isRequired(){
    	return this.required;
    }

    /**
     * Returns if the property is queryable.
     * 
     * @return {@code true} - is queryable; {@code false} - is not queryable;
     *         {@code null} - unknown (noncompliant repository)
     * 
     * @cmis 1.0
     */
    public Boolean isQueryable(){
    	return this.queryable;
    }

    /**
     * Returns if the property is Orderable.
     * 
     * @return {@code true} - is Orderable; {@code false} - is not Orderable;
     *         {@code null} - unknown (noncompliant repository)
     * 
     * @cmis 1.0
     */
    public Boolean isOrderable(){
    	return this.orderable;
    }

    /**
     * Returns if the property supports open choice.
     * 
     * @return {@code true} - supports open choice; {@code false} - does not
     *         support open choice; {@code null} - unknown or not applicable
     * 
     * @cmis 1.0
     */
    public Boolean isOpenChoice(){
    	return this.openChoice;
    }

    /**
     * Returns the default value.
     * 
     * @return the default value (list) or an empty list if no default value is
     *         defined
     * x
     * @cmis 1.0
     */
    public List<T> getDefaultValue(){
    	return this.defaultValue;
    }

    /**
     * Returns the choices for this property.
     * 
     * @return the choices or an empty list if no choices are defined
     * 
     * @cmis 1.0
     */
    public List<Choice<T>> getChoices(){
    	return this.choices;
    }

	/**
	 * @param updatibility the updatibility to set
	 */
	public void setUpdatibility(Updatability updatibility) {
		this.updatibility = updatibility;
	}

	/**
	 * @return the inherited
	 */
	public Boolean getInherited() {
		return inherited;
	}

	/**
	 * @param inherited the inherited to set
	 */
	public void setInherited(Boolean inherited) {
		this.inherited = inherited;
	}

	/**
	 * @return the required
	 */
	public Boolean getRequired() {
		return required;
	}

	/**
	 * @param required the required to set
	 */
	public void setRequired(Boolean required) {
		this.required = required;
	}

	/**
	 * @return the queryable
	 */
	public Boolean getQueryable() {
		return queryable;
	}

	/**x
	 * @param queryable the queryable to set
	 */
	public void setQueryable(Boolean queryable) {
		this.queryable = queryable;
	}

	/**
	 * @return the orderable
	 */
	public Boolean getOrderable() {
		return orderable;
	}

	/**
	 * @param orderable the orderable to set
	 */
	public void setOrderable(Boolean orderable) {
		this.orderable = orderable;
	}

	/**
	 * @return the openChoice
	 */
	public Boolean getOpenChoice() {
		return openChoice;
	}

	/**
	 * @param openChoice the openChoice to set
	 */
	public void setOpenChoice(Boolean openChoice) {
		this.openChoice = openChoice;
	}

	/**
	 * @param id the id to set
	 */
	public void setId(String id) {
		if (id==null || id.isEmpty())
				throw new NotDefinedIdPropertyDataException(this.toString());
		this.id = (id);
	}

	/**
	 * @param localName the localName to set
	 */
	public void setLocalName(String localName) {
		this.localName = localName;
	}

	/**
	 * @param localNamespace the localNamespace to set
	 */
	public void setLocalNamespace(String localNamespace) {
		this.localNamespace = localNamespace;
	}

	/**
	 * @param displayName the displayName to set
	 */
	public void setDisplayName(String displayName) {
		this.displayName = displayName;
	}

	/**
	 * @param queryName the queryName to set
	 */
	public void setQueryName(String queryName) {
		this.queryName = queryName;
	}

	/**
	 * @param description the description to set
	 */
	public void setDescription(String description) {
		this.description = description;
	}

	/**
	 * @param propertyType the propertyType to set
	 */
	public void setPropertyType(PropertyType propertyType) {
		this.propertyType = propertyType;
	}

	/**
	 * @param defaultValue the defaultValue to set
	 */
	public void setDefaultValue(List<T> defaultValue) {
		this.defaultValue = defaultValue;
	}

	/**
	 * @param choices the choices to set
	 */
	public void setChoices(List<Choice<T>> choices) {
		this.choices = choices;
	}
	
	public String toString(){
		return "PropertyDefinition of type: "+this.getClass().toGenericString()+
				" with id "+this.getId()+" type "+this.getPropertyType()+" "+this.getDescription();
	}

}
