/*
Storybook: Open Source software for novelists and authors.
Copyright (C) 2008 - 2012 Martin Mustun

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package storybook.model.hbn.entity;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Node;
import storybook.model.book.Book;
import static storybook.model.hbn.entity.AbstractEntity.fromXmlBeg;
import static storybook.model.hbn.entity.AbstractEntity.fromXmlEnd;
import storybook.tools.LOG;
import storybook.tools.xml.XmlKey;
import storybook.tools.xml.XmlUtil;

public class Internal extends AbstractEntity {

	private String key = "";
	private String stringValue = "";
	private Integer integerValue = 0;
	private Boolean booleanValue = false;
	private byte[] binValue;

	public Internal() {
		super(Book.TYPE.INTERNAL, "000");
	}

	public Internal(ResultSet rs) {
		this();
		try {
			key = rs.getString("key");
			stringValue = rs.getString("stringValue");
			integerValue = rs.getInt("integerValue");
			booleanValue = rs.getBoolean("booleanValue");
			binValue = rs.getBytes("binValue");
		} catch (SQLException ex) {
			//empty
		}
	}

	public Internal(String key) {
		this(key, "");
		this.key = key;
	}

	public Internal(String key, String stringValue) {
		this();
		this.key = key;
		this.stringValue = stringValue;
	}

	public Internal(String key, Integer integerValue) {
		this();
		this.key = key;
		this.integerValue = integerValue;
	}

	public Internal(String key, Boolean booleanValue) {
		this();
		this.key = key;
		this.booleanValue = booleanValue;
	}

	public Internal(String key, byte[] binValue) {
		this();
		this.key = key;
		this.binValue = binValue;
	}

	public Internal(String key, Object value) {
		this();
		this.key = key;
		if (value instanceof String) {
			this.stringValue = (String) value;
		} else if (value instanceof Integer) {
			this.integerValue = (Integer) value;
		} else if (value instanceof Boolean) {
			this.booleanValue = (Boolean) value;
		} else if (value instanceof byte[]) {
			// ignore
		} else {
			LOG.err("Internal.Internal(): Unknown Type");
		}
	}

	@Override
	public Long getId() {
		return this.id;
	}

	@Override
	public void setId(Long id) {
		this.id = id;
	}

	public String getKey() {
		return this.key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public String getStringValue() {
		return this.stringValue;
	}

	public void setStringValue(String stringValue) {
		this.stringValue = stringValue;
	}

	public boolean hasStringValue() {
		return stringValue != null && stringValue.length() > 0;
	}

	public Integer getIntegerValue() {
		return this.integerValue;
	}

	public void setIntegerValue(Integer integerValue) {
		this.integerValue = integerValue;
	}

	public boolean hasIntegerValue() {
		return integerValue != null;
	}

	public Boolean getBooleanValue() {
		return this.booleanValue;
	}

	public void setBooleanValue(Boolean booleanValue) {
		this.booleanValue = booleanValue;
	}

	public boolean hasBooleanValue() {
		return booleanValue != null;
	}

	public byte[] getBinValue() {
		return binValue;
	}

	public void setBinValue(byte[] binValue) {
		this.binValue = binValue;
	}

	public boolean hasBinValue() {
		return binValue != null;
	}

	@Override
	public String toString() {
		StringBuilder buf = new StringBuilder();
		buf.append(key);
		buf.append(": ");
		if (hasStringValue()) {
			buf.append("string: '").append(stringValue).append("' ");
		} else {
			if (hasIntegerValue()) {
				buf.append("int: ").append(integerValue).append(" ");
			}
			if (hasBooleanValue()) {
				buf.append("boolean: ").append(booleanValue).append(" ");
			}
			if (hasBinValue()) {
				buf.append("'bin: [binary]");
			}
		}
		return buf.toString() + (hasNotes() ? "*" : "");
	}

	@Override
	public String toCsv(String quoteStart, String quoteEnd, String separator) {
		String b = "";
		b += quoteStart + key + quoteStart + separator + quoteEnd + quoteStart;
		if (hasStringValue()) {
			b = stringValue;
		} else if (hasIntegerValue()) {
			b = integerValue.toString();
		} else if (hasBooleanValue()) {
			b = booleanValue.toString();
		} else {
			b += "";
		}
		b += quoteEnd + "\n";
		return (b);
	}

	@Override
	public String toHtml() {
		return (toCsv("<td>", "</td>", "\n"));
	}

	@Override
	public String toText() {
		return (toCsv("", "", "\t"));
	}

	@Override
	public String toXml() {
		StringBuilder b = new StringBuilder(toXmlBeg());
		if (hasStringValue()) {
			b.append(XmlUtil.setAttribute(2, "string", stringValue));
		} else if (hasIntegerValue()) {
			b.append(XmlUtil.setAttribute(2, "integer", integerValue.toString()));
		} else if (hasBooleanValue()) {
			b.append(XmlUtil.setAttribute(2, "boolean", booleanValue.toString()));
		}
		b.append(">\n");
		b.append(toXmlEnd());
		return XmlUtil.format(b.toString());
	}

	public Internal fromXml(Node node) {
		Internal p = new Internal();
		fromXmlBeg(node, p);
		p.setKey(XmlUtil.getString(node, XmlKey.XK.KEY));
		p.setStringValue(XmlUtil.getString(node, "string"));
		p.setIntegerValue(XmlUtil.getInteger(node, "integer"));
		p.setBooleanValue(XmlUtil.getBoolean(node, "boolean"));
		fromXmlEnd(node, p);
		return p;
	}

	@Override
	@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
	public boolean equals(Object obj) {
		if (!super.equals(obj)) {
			return false;
		}
		Internal test = (Internal) obj;
		boolean ret = true;
		ret = ret && equalsStringNullValue(stringValue, test.getStringValue());
		ret = ret
		   && equalsIntegerNullValue(integerValue, test.getIntegerValue());
		ret = ret
		   && equalsBooleanNullValue(booleanValue, test.getBooleanValue());
		if (binValue != null) {
			ret = ret && binValue.equals(test.binValue);
		}
		return ret;
	}

	@Override
	public int hashCode() {
		int hash = super.hashCode();
		hash = hash * 31 + (key != null ? key.hashCode() : 0);
		hash = hash * 31 + (stringValue != null ? stringValue.hashCode() : 0);
		hash = hash * 31 + (integerValue != null ? integerValue.hashCode() : 0);
		hash = hash * 31 + (booleanValue != null ? booleanValue.hashCode() : 0);
		hash = hash * 31 + (binValue != null ? binValue.hashCode() : 0);
		return hash;
	}

	public static List<String> getDefColumns() {
		List<String> list = AbstractEntity.getDefColumns(Book.TYPE.INTERNAL);
		list.add("key, 512");
		list.add("string_value, 4096");
		return (list);
	}

	public static List<String> getTable() {
		List<String> ls = new ArrayList<>();
		String tableName = "internal";
		AbstractEntity.getTable(tableName, ls);
		ls.add(tableName + ",key,String,512");
		ls.add(tableName + ",string_value,String,4096");
		ls.add(tableName + ",integer_value,Integer,0");
		ls.add(tableName + ",boolean_value,Boolean,0");
		ls.add(tableName + ",binValue,Binary,16384");
		return (ls);
	}

}
