package hiro.yoshioka.sql.resource;

import hiro.yoshioka.util.StringUtil;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class DBSchema extends DBResource implements IDBSchema {
	private static final long serialVersionUID = 9999204848887L;
	protected Map<String, IDBTrigger> fTriggerMap;
	protected Map<String, IDBSequence> fSequenceMap;
	protected boolean fTmpSelection;

	public DBSchema(DBRoot root) {
		super(root);
	}

	public int childrenNum() {
		int sum = _children.size();
		if (fTriggerMap != null) {
			sum += fTriggerMap.size();
		}
		if (fSequenceMap != null) {
			sum += fSequenceMap.size();
		}
		return sum;
	}

	public void putProcedure(IDBTable table) {
		super.putResource(table.getName(), table);
	}

	public boolean isTmpSelection() {
		return fTmpSelection;
	}

	public void removeAll() {
		_children.clear();
		if (fTriggerMap != null) {
			fTriggerMap.clear();
		}
		if (fSequenceMap != null) {
			fSequenceMap.clear();
		}
	}

	public String[] getTableNames() {
		List<String> retList = new ArrayList<String>();
		for (IDBTable table : getTableOrViews()) {
			retList.add(table.getName());
		}
		return retList.toArray(new String[retList.size()]);
	}

	public IDBTrigger getTrigger(String name) {
		return fTriggerMap.get(name);
	}

	public IDBTrigger[] getTriggers() {
		return fTriggerMap.values().toArray(new IDBTrigger[0]);
	}

	public void putTrigger(IDBTrigger trigger) {
		if (fTriggerMap == null) {
			fTriggerMap = new LinkedHashMap<String, IDBTrigger>();
		}
		fTriggerMap.put(trigger.getUName(), trigger);
	}

	public IDBSequence getSequence(String name) {
		if (fSequenceMap == null || name == null) {
			return null;
		}
		return fSequenceMap.get(name.toUpperCase());
	}

	public IDBSequence[] getSequences() {
		if (fSequenceMap == null) {
			return IDBSequence.EMPTY_ARRAY;
		}
		return fSequenceMap.values().toArray(new IDBSequence[0]);
	}

	public void putSequence(IDBSequence sequence) {
		if (fSequenceMap == null) {
			fSequenceMap = new LinkedHashMap<String, IDBSequence>();
		}
		fSequenceMap.put(sequence.getUName(), sequence);
	}

	@Override
	public IDBTable[] getTableOrSystemTables() {
		List<IDBTable> list = getTablesList(TableType.TABLE_SET);
		return list.toArray(new IDBTable[list.size()]);
	}

	@Override
	public IDBTable[] getTableOrViews() {
		List<IDBTable> list = getTablesList(TableType.TABLE_OR_VIEW_SET);
		return list.toArray(new IDBTable[list.size()]);
	}

	@Override
	public IDBTable[] getProcedures() {
		List<IDBTable> list = getTablesList(TableType.PROCEDURE_SET);
		return list.toArray(new IDBTable[list.size()]);
	}

	public IDBTable[] getFunctions() {
		List<IDBTable> list = getTablesList(TableType.FUNCTION_SET);
		return list.toArray(new IDBTable[list.size()]);
	}

	@Override
	public IDBTable[] getSynonyms() {
		List<IDBTable> list = getTablesList(TableType.SYNONYM_SET);
		return list.toArray(new IDBTable[list.size()]);
	}

	public boolean contain(String pattern) {
		if (containKeyInNameOrComment(pattern.toUpperCase())) {
			return true;
		}
		for (Iterator ite = _children.values().iterator(); ite.hasNext();) {
			if (((IDBTable) ite.next()).contain(pattern)) {
				return true;
			}
		}

		return false;
	}

	@Override
	public void putTable(IDBTable table) {
		super.putResource(table.getName(), table);
	}

	public IDBTable getTableResource(String name) {
		return getTableOf(null, name, false);
	}

	public IDBTable getTableResource(String name, boolean considerAlias) {
		return getTableOf(null, name, considerAlias);
	}

	public IDBTable getTableResource(String name, boolean considerAlias,
			Set<TableType> typeSet) {
		return getTableOf(typeSet, name, considerAlias);
	}

	public IDBTable getProcedure(String name) {
		return getTableOf(TableType.PROCEDURE_SET, name, false);
	}

	@Override
	public void slimUp() {
		for (Iterator ite = _children.values().iterator(); ite.hasNext();) {
			IDBTable t = (IDBTable) ite.next();
			if (t.isProcudeure() || t.isFunction()) {
				_children.remove(t);
			} else {
				t.slimUp();
			}
		}
	}

	public List listResources() {
		List list = super.listResources();
		if (fTriggerMap != null && fTriggerMap.size() > 0) {
			list.addAll(fTriggerMap.values());
		}
		if (fSequenceMap != null && fSequenceMap.size() > 0) {
			list.addAll(fSequenceMap.values());
		}
		return list;
	}

	public List getResourceListStartsWith(String tableNameString) {
		List<IDBResource> list = new ArrayList<IDBResource>();
		for (Iterator<Entry<String, IDBResource>> ite = _children.entrySet()
				.iterator(); ite.hasNext();) {
			Map.Entry<String, IDBResource> entry = ite.next();
			IDBResource t = entry.getValue();
			if (t.startsNameWith(tableNameString)) {
				list.add(t);
			}
		}
		return list;
	}

	public String getCurrentDefaultString() {
		if (isDefault()) {
			if (isCurrent()) {
				return "\u24b9\u24b8";
			} else {
				return "\u24b9";
			}
		} else {
			if (isCurrent()) {
				return "\u24b8";
			} else {
				return StringUtil.EMPTY_STRING;
			}
		}
	}

	public boolean isDefault() {
		DBRoot root = getRoot();
		if (root == null) {
			return false;
		}
		return this.equals(root.getDefaultSchema());
	}

	public boolean isCurrent() {
		DBRoot root = getRoot();
		if (root == null) {
			return false;
		}
		return this.equals(root.getCurrentSchema());
	}

	public String toString() {
		return getNameWithComment();
	}

	@Override
	public List<IDBTable> getTablesList(Set<TableType> typeSet) {
		List<IDBTable> list = new ArrayList<IDBTable>();
		for (IDBResource child : _children.values()) {
			if (child instanceof IDBTable) {
				IDBTable tbl = (IDBTable) child;
				if (typeSet == null || typeSet.contains(tbl.getTableType())) {
					list.add(tbl);
				}
			}
		}
		return list;
	}

	private IDBTable getTableOf(Set<TableType> typeSet, String name,
			boolean considerAlias) {
		for (IDBTable table : getTablesList(typeSet)) {
			if (table.getName().equalsIgnoreCase(name)) {
				return table;
			}
			if (considerAlias && table.hasAlias()) {
				if (table.getAlias().equalsIgnoreCase(name)) {
					return table;
				}
			}
		}
		return null;
	}

}