package dowser.model;

import java.util.Collection;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Vector;

/**
 *
 * @author Chetan Pawgi
 */
public class Class extends DomainEntity {

	private Map<String, Attribute> m_vAttributes;
	private List<String> m_ListAttributes;
	private Map<String, Operation> m_vOperations;
	private List<String> m_ListOperations;
	private List<Class> m_vSuperClasses;
	private List<Class> m_vSubClasses;
	private List<Relation> m_vRelations;

	{
		m_vAttributes = new Hashtable<String, Attribute>();
		m_ListAttributes = new Vector<String>();
		m_vOperations = new Hashtable<String, Operation>();
		m_vSubClasses = new Vector<Class>();
		m_vSuperClasses = new Vector<Class>();
		m_vRelations = new Vector<Relation>();
		m_ListOperations = new Vector<String>();
	}

	public Collection<Relation> getRelations() {
		return Collections.unmodifiableCollection(m_vRelations);
	}

	public Collection<Attribute> getAttributes() {
		return Collections.unmodifiableCollection(m_vAttributes.values());
	}

	public Attribute getAttribute(int index) {
		return getAttribute(m_ListAttributes.get(index));
	}

	public int getIndexOfAttribute(Attribute attrib) {
		return m_ListAttributes.indexOf(attrib);
	}

	public boolean containsAttribute(String attribName) {
		return m_vAttributes.containsKey(attribName);
	}

	public Attribute getAttribute(String attribName) {
		return m_vAttributes.get(attribName);
	}

	public int getAttributeCount() {
		return m_vAttributes.size();
	}

	public int getIndexOfOperation(Operation operation) {
		return m_ListOperations.indexOf(operation);
	}

	public boolean containsOperation(String operationName) {
		return m_vOperations.containsKey(operationName);
	}

	public Operation getOperation(String operationName) {
		return m_vOperations.get(operationName);
	}

	public int getOperationCount() {
		return m_vOperations.size();
	}

	public Operation getOperation(int index) {
		return getOperation(m_ListOperations.get(index));
	}

	public Collection<Operation> getOperations() {
		return Collections.unmodifiableCollection(m_vOperations.values());
	}

	public List<Class> getSuperClasses() {
		return Collections.unmodifiableList(m_vSuperClasses);
	}

	public List<Class> getSubClasses() {
		return Collections.unmodifiableList(m_vSubClasses);
	}

	public Class(String name) {
		super(name);
	}

	public void addRelation(Relation relation) {
		if (!m_vRelations.contains(relation)) {
			m_vRelations.add(relation);
		}
	}

	public void removeRelation(Relation relation) {
		if (m_vRelations.contains(relation)) {
			m_vRelations.remove(relation);
		}
	}

	public void addAttribute(String attribName) {
		addAttribute(new Attribute(this, attribName), m_ListAttributes.size());
	}

	public void addAttribute(Attribute attrib, int index) {
		if (attrib.getParentClass() != this) {
			throw new IllegalStateException("Invalid attribute being added to " + this.getName() + " with parent = " + attrib.getParentClass().getName());
		}
		if (index > m_ListAttributes.size()) {
			throw new IllegalArgumentException("can't add attribute at index " + index + " > " + m_ListAttributes.size());
		}
		if (!m_vAttributes.containsKey(attrib.getName())) {
			m_vAttributes.put(attrib.getName(), attrib);
			m_ListAttributes.add(attrib.getName());
		}
	}

	public void addOperation(String operationName) {
		addOperation(new Operation(this, operationName), m_ListOperations.size());
	}

	public void addOperation(Operation operation, int index) {
		if (operation.getParentClass() != this) {
			throw new IllegalStateException("Invalid operation being added to " + this.getName() + " with parent = " + operation.getParentClass().getName());
		}
		if (index > m_ListOperations.size()) {
			throw new IllegalArgumentException("can't add operation at index " + index + " > " + m_ListAttributes.size());
		}
		if (!m_vOperations.containsKey(operation.getName())) {
			m_vOperations.put(operation.getName(), operation);
			m_ListOperations.add(operation.getName());
		}
	}

	public void addSuperClass(Class superClass) {
		if (superClass == this) {
			return;
		}
		if (!m_vSuperClasses.contains(superClass)) {
			m_vSuperClasses.add(superClass);
			superClass.addSubClass(this);
		}
	}

	public void removeSuperClass(Class superClass) {
		if (m_vSuperClasses.contains(superClass)) {
			m_vSuperClasses.remove(superClass);
			superClass.removeSubClass(this);
		}
	}

	public void addSubClass(Class subClass) {
		if (subClass == this) {
			return;
		}
		if (!m_vSubClasses.contains(subClass)) {
			m_vSubClasses.add(subClass);
			subClass.addSuperClass(this);
		}
	}

	public void removeSubClass(Class subClass) {
		if (m_vSubClasses.contains(subClass)) {
			m_vSubClasses.remove(subClass);
			subClass.removeSuperClass(this);
		}
	}

	public Operation findSimilarOperation(String operationName) {
		throw new UnsupportedOperationException("findSimilarOperation not supported yet");
	}

	public Attribute findSimilarAttribute(String attributeName) {
		throw new UnsupportedOperationException("findSimilarAttribute not supported yet");
	}

	public int getRelationCount() {
		return m_vRelations.size();
	}

	public Relation getRelation(int index) {
		return m_vRelations.get(index);
	}

	@Override
	public String toString() {
		StringBuilder bld = new StringBuilder();
		bld.append("Class : " + getName());
		if (m_vAttributes.size() > 0) {
			bld.append("\n\tAttributes : \n");
			for (Attribute attrib : m_vAttributes.values()) {
				bld.append("\t\t" + attrib.toString());
			}
		}
		if (m_vOperations.size() > 0) {
			bld.append("\n\tOperations : \n");
			for (Operation oprn : m_vOperations.values()) {
				bld.append("\t\t" + oprn.toString());
			}
		}
		if (m_vSuperClasses.size() > 0) {
			bld.append("\n\tSuperClasses : \n");
			for (Class superClass : m_vSuperClasses) {
				bld.append("\t\t" + superClass.getName() + "\n");
			}
		}
		if (m_vSubClasses.size() > 0) {
			bld.append("\n\tSuperClasses : \n");
			for (Class superClass : m_vSuperClasses) {
				bld.append("\t\t" + superClass.getName() + "\n");
			}
		}
		if (m_vRelations.size() > 0) {
			bld.append("\n\tRelations : \n");
			for (Relation relation : m_vRelations) {
				bld.append("\t\t" + relation.getName() + "\n");
			}
		}
		return bld.toString();
	}

	public void renameAttribute(Attribute attrib, String newName) {
		String oldName = attrib.getName();
		int prevInd = m_ListAttributes.indexOf(oldName);
		m_ListAttributes.remove(oldName);
		m_vAttributes.remove(oldName);
		attrib.setName(newName);
		addAttribute(attrib, prevInd);
	}

	public void renameOperation(Operation oprn, String newName) {
		String oldName = oprn.getName();
		int prevInd = m_ListOperations.indexOf(oldName);
		m_ListOperations.remove(oldName);
		m_vOperations.remove(oldName);
		oprn.setName(newName);
		addOperation(oprn, prevInd);
	}
}
