package hiro.yoshioka.sql.resource;

import hiro.yoshioka.util.StringUtil;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySource;
import org.eclipse.ui.views.properties.TextPropertyDescriptor;

public abstract class DBResource implements IDBResource, Serializable,
		IPropertySource {
	private static final long serialVersionUID = 9999521409956L;
	protected transient Log fLogger = LogFactory.getLog(this.getClass());

	protected IDBResource _parent;

	protected String name;

	protected String comment;

	protected Map<String, IDBResource> _children = new LinkedHashMap<String, IDBResource>();

	protected int fResouceKind;

	protected Properties fProperties;

	protected boolean valid = true;

	public static transient Object image;

	protected String alias = StringUtil.EMPTY_STRING;

	public DBResource(IDBResource parent) {
		_parent = parent;
	}

	@Override
	public void setAlias(String alias) {
		this.alias = alias;
	}

	@Override
	public boolean hasAlias() {
		return !StringUtil.isEmpty(this.alias);
	}

	@Override
	public void clearAlias() {
		this.alias = StringUtil.EMPTY_STRING;
	}

	@Override
	public String getAlias() {
		return alias;
	}

	@Override
	public Properties getProperties() {
		return fProperties;
	}

	@Override
	public void setProperties(Properties p) {
		fProperties = p;
	}

	@Override
	public String getPropertyValue(String key) {
		if (fProperties == null) {
			return StringUtil.EMPTY_STRING;
		}
		return StringUtil.nvl(fProperties.getProperty(key));
	}

	@Override
	public void setPropertyValue(String key, String value) {
		if (fProperties == null) {
			fProperties = new Properties();
		}
		fProperties.setProperty(key, value);
	}

	public void slimUp() {
		System.out.println(getName() + "// slim up");
		_children.clear();
		if (fProperties != null) {
			fProperties.clear();
		}
	}

	public IDBResource getChildAt(int index) {
		return new ArrayList<IDBResource>(_children.values()).get(index);
	}

	public int childrenNum() {
		return _children.size();
	}

	public boolean hasChildren() {
		return _children.size() > 0;
	}

	public String getName() {
		return name == null ? StringUtil.EMPTY_STRING : name;
	}

	public String getNameWithParentName() {
		if (getParent() == null) {
			return getName();
		}
		String str = getParent().getName();
		if (str.length() > 0) {
			return String.format("%s.%s", str, getName());
		}
		return getName();
	}

	public String getNameWithComment() {
		return getNameWithComment(null, 0);
	}

	@Override
	public String getNameWithComment(Charset charset, int maxColumnNameLen) {
		if (getComment().length() > 0) {
			if (maxColumnNameLen <= 0) {
				return String.format("%s \"%s\"", getName(), getComment());
			}
			return String.format("%s \"%s\"", getName(), StringUtil.cutByBytes(
					getComment(), maxColumnNameLen, charset));
		}
		return getName();
	}

	@Override
	public String getNameWithAsComment() {
		return getNameWithAsComment(null, 0);
	}

	@Override
	public String getNameWithAsComment(Charset charset, int maxColumnNameLen) {
		if (getComment().length() > 0) {
			if (maxColumnNameLen <= 0) {
				return String.format("%s As \"%s\"", getName(), getComment());
			}
			return String.format("%s As \"%s\"", getName(), StringUtil
					.cutByBytes(getComment(), maxColumnNameLen, charset));
		}
		return getName();
	}

	public String getUName() {
		return getName().toUpperCase();
	}

	public boolean startsNameWith(String string) {
		return getUName().startsWith(string.toUpperCase());
	}

	public boolean startsCommentWith(String string) {
		return getUComment().startsWith(string.toUpperCase());
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getComment() {
		return comment == null ? StringUtil.EMPTY_STRING : comment;
	}

	public String getUComment() {
		return getComment().toUpperCase();
	}

	public void setComment(String str) {
		this.comment = str;
	}

	public DBRoot getRoot() {
		IDBResource parent = getParent();
		if (parent == null) {
			return null;
		}
		return parent.getRoot();
	}

	public IDBResource getParent() {
		return _parent;
	}

	public String getImageString() {
		return "\u211b";
	}

	public IDBResource[] listArrayResources() {
		List<IDBResource> list = listResources();

		return (IDBResource[]) list.toArray(new IDBResource[list.size()]);
	}

	public List<IDBResource> listResources() {
		ArrayList<IDBResource> list = new ArrayList<IDBResource>();
		list.addAll(_children.values());
		return list;
	}

	protected List<DBResource> listResources(String pattern) {
		List<DBResource> list = new ArrayList<DBResource>();
		IDBResource[] target = listArrayResources();
		String up = pattern.toUpperCase();
		for (int i = 0; i < target.length; i++) {
			DBResource resource = (DBResource) target[i];
			if (resource.containKeyInNameOrComment(up)) {
				list.add(resource);
			}
		}
		return list;
	}

	@Override
	public List<IDBResource> startsWithResourceLists(String pattern) {
		ArrayList<IDBResource> list = new ArrayList<IDBResource>();
		IDBResource[] target = listArrayResources();
		for (int i = 0; i < target.length; i++) {
			IDBResource resource = (IDBResource) target[i];
			if (resource.getUName().startsWith(pattern.toUpperCase())) {
				list.add(resource);
			}
		}
		return list;
	}

	protected boolean containKeyInNameOrComment(String upperString) {
		try {
			if (getUName().indexOf(upperString) >= 0
					|| getUComment().indexOf(upperString) >= 0) {
				return true;
			}
		} catch (Exception e) {
		}
		return false;
	}

	@Override
	public void setResources(Map<String, IDBResource> map) {
		_children = map;
	}

	@Override
	public IDBResource getResource(String key) {
		return getResource(key, false);
	}

	@Override
	public IDBResource getResource(String key, boolean considerAlias) {
		if (key == null) {
			return null;
		}
		IDBResource ret = _children.get(key.toUpperCase());
		if (ret != null) {
			return ret;
		}
		if (considerAlias) {
			for (IDBResource child : _children.values()) {
				if (child.hasAlias()) {
					if (child.getAlias().equalsIgnoreCase(key)) {
						return child;
					}
				}
			}
		}
		return null;
	}

	@Override
	public void putResource(String key, IDBResource child) {
		_children.put(key.toUpperCase(), child);
	}

	public String toString() {
		StringBuffer buf = new StringBuffer();
		buf.append(getClass().getName());
		buf.append(" UNAME[").append(getUName());
		buf.append("] ChildNum:");
		buf.append(_children.size());
		return buf.toString();
	}

	private void readObject(ObjectInputStream in) throws IOException,
			ClassNotFoundException {
		in.defaultReadObject();
		fLogger = LogFactory.getLog(this.getClass());
	}

	@Override
	public boolean isValid() {
		return valid;
	}

	@Override
	public void setValid(boolean valid) {
		this.valid = valid;
	}

	@Override
	public Object getImage() {
		return image;
	}

	@Override
	public int hashCode() {
		return (getClass().getName() + getName()).hashCode();
	}

	@Override
	public void setValueFromOld(IDBResource tbl) {
	}

	// ==============================================================
	// org.eclipse.ui.views.properties.IPropertySource
	// ==============================================================
	@Override
	public Object getEditableValue() {
		return null;
	}

	@Override
	public IPropertyDescriptor[] getPropertyDescriptors() {
		IPropertyDescriptor[] descriptor = new IPropertyDescriptor[0];
		if (fProperties == null) {
			return descriptor;
		}
		try {
			descriptor = new IPropertyDescriptor[fProperties.size()];
			int i = 0;
			for (Iterator ite = fProperties.keySet().iterator(); ite.hasNext(); i++) {
				String key = (String) ite.next();
				descriptor[i] = new TextPropertyDescriptor(key, key);
			}
			return descriptor;
		} catch (RuntimeException e) {
			e.printStackTrace();
		}
		return new IPropertyDescriptor[0];
	}

	@Override
	public Object getPropertyValue(Object id) {
		if (fProperties == null) {
			return StringUtil.EMPTY_STRING;
		}
		return fProperties.getProperty((String) id);
	}

	@Override
	public void setPropertyValue(Object key, Object value) {
		if (fProperties == null) {
			fProperties = new Properties();
		}
		fProperties.setProperty(StringUtil.nvl(key), StringUtil.nvl(value));
	}

	@Override
	public boolean isPropertySet(Object arg0) {
		return false;
	}

	@Override
	public void resetPropertyValue(Object arg0) {

	}

	@Override
	public void setParent(INameFamily parent) {
		// TODO Auto-generated method stub

	}
}