package hiro.yoshioka.ast.sql.util;

import hiro.yoshioka.sql.resource.DBRoot;
import hiro.yoshioka.sql.resource.IDBColumn;
import hiro.yoshioka.sql.resource.IDBSchema;
import hiro.yoshioka.sql.resource.IDBTable;
import hiro.yoshioka.util.StringUtil;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class DBResourceUtil {
	static Log fLogger = LogFactory.getLog(DBResourceUtil.class);

	public static DBRoot onlyPureTable(DBRoot root) {
		DBRoot clone = null;
		try {
			clone = clone(root);
			clone.slimUp();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return clone;
	}

	public static String generateJavaCodeForTest(DBRoot root) {
		if (root == null) {
			return StringUtil.EMPTY_STRING;
		}

		StringBuilder buf = new StringBuilder();
		StringUtil.appendln(buf, "DBRoot root = new DBRoot();");
		IDBSchema[] schemas = root.getSchemas();
		StringUtil.appendln(buf, "IDBSchema mschema = null;");
		StringUtil.appendln(buf, "DBTable table = null;");
		StringUtil.appendln(buf, "IDBColumn column = null;");
		StringUtil.appendln(buf, "String[] columns = null;");

		int depth = 0;
		for (IDBSchema schema : schemas) {
			StringUtil.appendln(buf, "mschema = new DBSchema(root);");
			StringUtil.appendln(buf, "mschema.setName(\"" + schema.getName()
					+ "\");");
			StringUtil.appendln(buf,
					"root.putResource(mschema.getName(), mschema);");
			if (root.getDefaultSchema().equals(schema)) {
				StringUtil.appendln(buf, "root.setDefaultSchema(mschema);");
			}
			IDBTable[] tables = schema.getTableOrViews();
			for (IDBTable table : tables) {
				StringUtil.appendln(buf, "table = new DBTable(mschema);");
				StringUtil.appendln(buf, "table.setName(\"" + table.getName()
						+ "\");");
				if (table.isTable()) {
					StringUtil.appendln(buf, "table.setTableType(\"TABLE\");");
				}
				StringUtil.appendln(buf, "mschema.putTable(table);");

				IDBColumn[] columns = table.getColumns();
				StringUtil.append(buf, "columns = new String[]{");
				for (IDBColumn column : columns) {
					StringUtil.append(buf, "\"" + column.getName() + "\",");
				}
				if (columns.length > 1) {
					buf.setLength(buf.length() - 1);
				}
				StringUtil.appendln(buf, "};");
				depth = 1;
				StringUtil.appendln(buf, depth,
						"for (int i = 0; i < columns.length; i++) {");
				StringUtil.appendln(buf, depth,
						"DBColumn col = new DBColumn(table);");
				StringUtil.appendln(buf, depth, "col.setName(columns[i]);");
				StringUtil.appendln(buf, depth,
						"col.setComment(\"comment_\" + i);");
				StringUtil.appendln(buf, depth,
						"col.setDataType(Types.VARCHAR);");
				StringUtil.appendln(buf, depth,
						"col.setDataTypeString(\"VARCHAR2\");");
				StringUtil.appendln(buf, depth, "col.setSize(10);");
				StringUtil.appendln(buf, depth, "col.setDecimalDigits(0);");
				StringUtil.appendln(buf, depth,
						"col.setNullable(DatabaseMetaData.attributeNullable);");
				StringUtil.appendln(buf, depth, "col.setPKey(true);");
				StringUtil.appendln(buf, depth,
						"table.putResource(col.getUName(), col);");

				StringUtil.appendln(buf, "}");

				depth = 0;

			}
		}

		return buf.toString();
	}

	public static DBRoot loadDBRoot(File f) {
		if (fLogger.isInfoEnabled()) {
			fLogger.info("load[" + f + "]");
		}
		ObjectInputStream in = null;
		DBRoot ret = null;
		try {
			in = new ObjectInputStream(new FileInputStream(f));
			ret = (DBRoot) in.readObject();
			if (fLogger.isInfoEnabled()) {
				fLogger.info("ret[" + ret + "]");
			}
			return ret;
		} catch (InvalidClassException e) {
			fLogger.fatal(StringUtil.EMPTY_STRING, e);
			return null;
		} catch (Exception e) {
			fLogger.fatal(StringUtil.EMPTY_STRING, e);
			return null;
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e1) {
					fLogger.fatal(StringUtil.EMPTY_STRING, e1);
					return null;
				}
			}
		}
	}

	private static DBRoot clone(DBRoot root) throws IOException,
			ClassNotFoundException {
		ObjectOutputStream out = null;
		ObjectInputStream in = null;
		try {
			ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
			out = new ObjectOutputStream(bos);
			out.writeObject(root);
			out.flush();
			in = new ObjectInputStream(new ByteArrayInputStream(bos
					.toByteArray()));

			return (DBRoot) in.readObject();

		} finally {
			if (in != null) {
				in.close();
			}
			if (out != null) {
				out.close();
			}
		}
	}
}
