package com.tandbergtv.watchpoint.pmm.title.conf;

import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;

/**
 * Represents the &lt;title&gt; tag in the specification.
 * 
 * @author Raj Prakash
 */
public class TitleConf {
	private Specification specification;
	private String name;
	private String alias;
	private TitleConf parent;
	private List<TitleConf> children = new ArrayList<TitleConf>();
	private boolean hasAsset;
	private List<Variable> metadata = new ArrayList<Variable>();
	private int min;
	private int max;
	
	/**
	 * @param specification
	 */
	public TitleConf(Specification specification) {
		super();
		this.specification = specification;
	}

	/**
	 * @return the alias
	 */
	public String getAlias() {
		/* Falls back to the name */
		if (alias == null || alias.length() == 0)
			return this.name;
		
		ResourceBundle bundle = specification.getBundle();
		
		if (bundle != null && bundle.containsKey(this.alias))
			return bundle.getString(alias);
		
		return this.alias;
	}

	/**
	 * @param alias the alias to set
	 */
	public void setAlias(String alias) {
		this.alias = alias;
	}

	/**
	 * @return the specification
	 */
	public Specification getSpecification() {
		return specification;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name the name to set
	 */
	void setName(String name) {
		this.name = name;
	}

	/**
	 * Get the parent title conf
	 * @return The parent title conf
	 */
	public TitleConf getParent() {
		return this.parent;
	}

	/**
	 * @param parent the parent to set
	 */
	void setParent(TitleConf parent) {
		this.parent = parent;
	}

	/**
	 * @return the parentName
	 */
	public String getParentName() {
		return (parent != null) ? parent.getName() : null;
	}

	/**
	 * @return the children
	 */
	public List<TitleConf> getChildren() {
		return children;
	}

	/**
	 * @param children the children to set
	 */
	void setChildren(List<TitleConf> children) {
		if (children != null) {
			for (TitleConf child : children)
				child.setParent(this);
		}
		
		this.children = (children != null) ? children : new ArrayList<TitleConf>();
	}

	/**
	 * @return the hasAsset
	 */
	public boolean isHasAsset() {
		return hasAsset;
	}

	/**
	 * @param hasAsset the hasAsset to set
	 */
	void setHasAsset(boolean hasAsset) {
		this.hasAsset = hasAsset;
	}

	/**
	 * Returns the multiplicity
	 * 
	 * @return
	 */
	public Multiplicity getTitleMultiplicity() {
		return Multiplicity.getMultiplicity(this.min, this.max);
	}

	/**
	 * @return the min
	 */
	public int getMin() {
		return min;
	}

	/**
	 * @param min the min to set
	 */
	public void setMin(int min) {
		this.min = min;
	}

	/**
	 * @return the max
	 */
	public int getMax() {
		return max;
	}

	/**
	 * @param max the max to set
	 */
	public void setMax(int max) {
		this.max = max;
	}

	/**
	 * @return the metadata
	 */
	public List<Variable> getMetadata() {
		return metadata;
	}

	/**
	 * @param metadata the metadata to set
	 */
	void setMetadata(List<Variable> metadata) {
		this.metadata = (metadata != null) ? metadata : new ArrayList<Variable>();
	}

	/**
	 * Gets the metadata variable with the given name.
	 * 
	 * @param name	name of the variable to find
	 * @return		the variable with the given name; null, if not found
	 */
	public Variable getMetadataVariable(String name) {
		if(metadata != null) {
			for(Variable variable : metadata) {
				if(variable.getName().equals(name)) {
					return variable;
				}
			}
		}
		return null;
	}

	/**
	 * Gets the child titleConf that has the given name.
	 * 
	 * @param name	name of the child titleConf to find
	 * @return		the child with the given name; null, if not found
	 */
	public TitleConf getChild(String name) {
		if(children != null) {
			for(TitleConf child : children) {
				if(child.getName().equals(name)) {
					return child;
				}
			}
		}
		return null;
	}

	/**
	 * Adds the given titleConf as a child.
	 * 
	 * @param titleConf	the child
	 */
	void addChild(TitleConf titleConf) {
		titleConf.setParent(this);
		children.add(titleConf);
	}

	/**
	 * Adds a metadata variable.
	 * 
	 * @param v	the metadata variable
	 */
	void addMetadata(Variable v) {
		metadata.add(v);
	}
	
	/**
	 * Gets all the descendants of this titleConf.
	 * 
	 * @return	the list of descendants
	 */
	public List<TitleConf> getAllDescendants() {
		List<TitleConf> allDecendants = new ArrayList<TitleConf>();
		for(TitleConf child : getChildren()) {
			allDecendants.add(child);
			allDecendants.addAll(child.getAllDescendants());
		}
		return allDecendants;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return (name != null) ? name.hashCode() : super.hashCode();
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object o) {
		if(name != null) {
			return o instanceof TitleConf && name.equals(((TitleConf) o).name);
		} else {
			return super.equals(o);
		}
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		String newLineString = System.getProperty("line.separator");
		StringBuffer sb = new StringBuffer();
		
		sb.append("TitleConf:\n");
		sb.append("Name: " + name).append(" (").append(getAlias()).append(")").append(newLineString);
		sb.append("Parent Name: " + this.getParentName()).append(newLineString);
		sb.append("Min-max " + min + "," + max).append(newLineString);
		sb.append("Metadata: \n");
		for(Variable v : metadata) {
			sb.append(v).append(newLineString);
		}
		sb.append("Children: \n");
		for(TitleConf child : children) {
			sb.append(child).append(newLineString);
		}
		
		return sb.toString();
	}
}
