package hiro.yoshioka.sql;

import hiro.yoshioka.classmanager.ClassManager;
import hiro.yoshioka.sdh.ResultSetDataHolder;
import hiro.yoshioka.sdh.ResultSetMetaCopy;
import hiro.yoshioka.sdh2.ReflectionPreparedStatement;
import hiro.yoshioka.sdh2.ResultSetDataHolder2;
import hiro.yoshioka.sql.engine.MirroringRequest;
import hiro.yoshioka.sql.engine.Request;
import hiro.yoshioka.sql.engine.SQLOperationType;
import hiro.yoshioka.sql.params.ConnectionProperties;
import hiro.yoshioka.sql.resource.DBCrossRefference;
import hiro.yoshioka.sql.resource.DBResourceType;
import hiro.yoshioka.sql.resource.DBRoot;
import hiro.yoshioka.sql.resource.IDBColumn;
import hiro.yoshioka.sql.resource.IDBSequence;
import hiro.yoshioka.sql.resource.IDBTable;
import hiro.yoshioka.sql.resource.INameFamily;
import hiro.yoshioka.util.StringUtil;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import jp.sf.orangesignal.csv.CsvWriter;
import jp.sf.orangesignal.csv.handlers.ResultSetHandler;

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

public abstract class AbsNoSQL implements ITransactionSQL {
	protected Log fLogger = LogFactory.getLog(getClass());
	protected boolean capturing;
	protected ConnectionProperties _info;
	protected ClassManager classManager;
	protected Set<SqlTransactionListener> fTransactionListenerList;
	protected Set<SqlBasicListener> fConnectionListenerList;
	protected ResultSetUtil rsUtil = new ResultSetUtil();
	private Date latestOperationTime;

	public AbsNoSQL() {
	}

	public AbsNoSQL(ClassManager classManager) {
		this.classManager = classManager;
	}

	@Override
	public Boolean isAlive(ConnectionProperties properties) throws SQLException {
		this.latestOperationTime = new java.util.Date();
		return null;
	}

	@Override
	public boolean load(File f) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean save(File f) throws IOException {
		// TODO Auto-generated method stub
		return false;
	}

	public void setMakeBlobData(boolean makeblob) {
		this.rsUtil.setMakeBlobData(makeblob);
	}

	public boolean isMakeBlobData() {
		return rsUtil.isMakeBlobData();
	}

	@Override
	public boolean connect(ConnectionProperties properties) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean close() throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	final public void addConnectionListner(SqlBasicListener listner) {
		if (listner == null) {
			return;
		}
		if (fConnectionListenerList == null) {
			fConnectionListenerList = new HashSet<SqlBasicListener>();
		}
		fConnectionListenerList.add(listner);
	}

	@Override
	final public void addTracsactionListner(SqlTransactionListener listener) {
		if (listener == null) {
			return;
		}
		if (fTransactionListenerList == null) {
			fTransactionListenerList = new HashSet<SqlTransactionListener>();
		}
		fTransactionListenerList.add(listener);
	}

	@Override
	public void removeConnetionListener(SqlBasicListener listner) {
		if (fConnectionListenerList == null) {
			return;
		}
		fConnectionListenerList.remove(listner);
	}

	@Override
	public void removeTracsactionListner(SqlTransactionListener listener) {
		if (fTransactionListenerList == null) {
			return;
		}
		fTransactionListenerList.remove(listener);
	}

	protected void notifyExecute(SQLExecutionStatus status, String... params) {
		if (fTransactionListenerList == null) {
			return;
		}
		switch (status) {
		case AFTER_EXECUTE:
			if (params.length != 2) {
				System.err.println("Argments count is must be 2!");
			}
			break;

		default:
			break;
		}
		for (SqlTransactionListener listener : fTransactionListenerList) {
			try {
				listener.executionStatus(status, false, params);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public ResultSetDataHolder renameField(IDBColumn before, String afterName)
			throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	final public DBRoot getRoot() {
		return _info.getDBRootResource();
	}

	@Override
	public String getDefaultSchemaName() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean createDatabase(String name, Properties properties)
			throws SQLException {
		fLogger.fatal("=========================================");
		fLogger.fatal("Not support yet");
		fLogger.fatal("=========================================");
		return false;
	}

	@Override
	public boolean dropDatabase(String name) throws SQLException {
		fLogger.fatal("=========================================");
		fLogger.fatal("Not support yet");
		fLogger.fatal("=========================================");
		return false;
	}

	@Override
	public boolean createUser(String name, Properties properties)
			throws SQLException {
		fLogger.fatal("=========================================");
		fLogger.fatal("Not support yet");
		fLogger.fatal("=========================================");
		return false;
	}

	@Override
	public boolean dropUser(String name) throws SQLException {
		fLogger.fatal("=========================================");
		fLogger.fatal("Not support yet");
		fLogger.fatal("=========================================");
		return false;
	}

	@Override
	public void setRoot(DBRoot root) {
		this._info.setDBRoot(root);
	}

	@Override
	public DBRoot getCopyRoot() {
		ObjectOutputStream out = null;
		ObjectInputStream in = null;
		DBRoot newObject = null;
		try {
			ByteArrayOutputStream bout = new ByteArrayOutputStream();
			out = new ObjectOutputStream(bout);
			out.writeObject(getRoot());
			out.close();
			byte[] bytes = bout.toByteArray();
			in = new ObjectInputStream(new ByteArrayInputStream(bytes));
			newObject = (DBRoot) in.readObject();
			in.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (in != null) {
					in.close();
				}
				if (out != null) {
					out.close();
				}
			} catch (Exception ee) {
				ee.printStackTrace();
			}
		}
		return newObject;
	}

	@Override
	public Set<String> getSchemas() {
		fLogger.error("getSchemas always return EMPTY_SET");
		return Collections.EMPTY_SET;
	}

	@Override
	public Set<String> getTables(String text) {
		fLogger.error("getTables always return EMPTY_SET");
		return Collections.EMPTY_SET;
	}

	@Override
	public ResultSetDataHolder getProcedures(String name) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isCapturing() {
		return capturing;
	}

	@Override
	public boolean canDoOperation(SQLOperationType operation) {
		switch (operation) {
		case CREATE_DATABASE:
		case DROP_DATABASE:
			return false;
		default:
			break;
		}
		return false;
	}

	@Override
	public void setBuildTimeStamp(String format) {
		rsUtil.setBuildTimeStamp(format);
	}

	@Override
	public void setBuildDate(String format) {
		rsUtil.setBuildDate(format);
	}

	@Override
	public boolean supportResultSet() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean existsSchema(String name) throws SQLException {
		boolean ret = false;
		Set<String> nameSet = getSchemas();
		if (nameSet.contains(name)) {
			ret = true;
		} else {
			for (String s : nameSet) {
				if (s.equalsIgnoreCase(name)) {
					ret = true;
					break;
				}
			}
		}

		fLogger.info(String.format(" schema exists [%b] ", ret));
		return ret;
	}

	@Override
	public void updateLatestRequestTime() {
		this.latestOperationTime = new java.util.Date();
	}

	@Override
	public Date getLatestRequestTime() {
		return this.latestOperationTime;
	}

	@Override
	public boolean doOperation(SQLOperationType operation, Request request)
			throws SQLException {
		fLogger.fatal("what's this operation ? " + operation);
		return false;
	}

	@Override
	public List<String> getTablePrimaryKeys(String catalog, String schema,
			String table) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ResultSet getAllData(IDBTable table) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ResultSetDataHolder2 getAllData2(String schema, String table,
			Request request) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ResultSetDataHolder2 getAllData2(IDBTable table, Request request)
			throws SQLException {
		INameFamily schema = table.getParent();
		ResultSetDataHolder2 ret = this.getAllData2(schema.getName(),
				table.getName(), request);
		if (ret != null) {
			ret.setTableName(table.getComment());
		}
		return ret;
	}

	@Override
	public int count(String sql_statement) throws SQLException {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public ResultSetDataHolder2 counts(String[] sql_statements)
			throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean execute(ReflectionPreparedStatement ref) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean execute(String sql_statement) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void executePrepareQueryByLine(String sql_statement,
			LineListener listner) throws SQLException {
		// TODO Auto-generated method stub

	}

	@Override
	public boolean execute(String sql_statement, String[] args)
			throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public ResultSetDataHolder2 executePrepare(String sql_statement,
			Object[] arg1) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ResultSetDataHolder2 executePrepareQuery(String sql_statement,
			String[] binds) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setMaxRowNum(int max) {
		// TODO Auto-generated method stub

	}

	@Override
	public boolean saveCsv(String sql_statement, ResultSetHandler handler,
			CsvWriter writer) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean cansel() throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean commit() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean rollback() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean trunsactionTime() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public ResultSetMetaCopy getTableMetaCopy(String name) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ResultSetMetaCopy getTableMetaCopy(String name, String[] strings) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ResultSetDataHolder2 getDiffInfoOf(DBResourceType resourceType,
			String schemaName, boolean withValue) {
		throw new UnsupportedOperationException();
	}

	@Override
	public boolean createMirroredTableTo(MirroringRequest mirroring_request)
			throws SQLException {
		mirroring_request.setMirroringFromSql(this);
		ITransactionSQL mirroring_to_sql = mirroring_request
				.getMirroringToSql();
		boolean retCode = true;
		try {
			ConnectionProperties targetConnectionProperties = mirroring_request
					.getTargetConnectionProperties();
			String text = String.format("DB Migraion Connecting[%s]",
					targetConnectionProperties.getDisplayString());
			mirroring_request.beginTask(text, 2);

			mirroring_request.worked(1);

			mirroring_to_sql.connect(targetConnectionProperties);
			mirroring_request.worked(1);
			text = String.format("DB Migraion Connect Success[%s]",
					targetConnectionProperties.getDisplayString());
			mirroring_request.subTask(text);

			DBRoot targetRoot = targetConnectionProperties.getDBRootResource();
			if (targetRoot == null) {
				fLogger.fatal("☆☆☆");
				String message = String.format(
						"☆☆☆ Missing DBRoot Resourceon [%s]",
						targetConnectionProperties.getDisplayString());
				fLogger.fatal(message);
				mirroring_request.setThrowable(new IllegalStateException(
						message));
				mirroring_request.addResultRecord(new String[] { "CHECK", "-",
						targetConnectionProperties.getDisplayString(),
						StringUtil.EMPTY_STRING, "×", "-",
						"Missing DBRoot Resourceon" });
				return false;
			}
			if (!mirroring_to_sql
					.createMirroredTableTo_FaseOnSchema(mirroring_request)) {
				retCode = false;
			}
			if (!mirroring_to_sql
					.createMirroredTableTo_FaseOnTable(mirroring_request)) {
				retCode = false;
			}

		} catch (Throwable e) {
			fLogger.error(StringUtil.EMPTY_STRING, e);
			retCode = false;
		} finally {
		}

		return retCode;
	}

	@Override
	public boolean createMirroredTableTo_FaseOnSchema(
			MirroringRequest mirroring_request) throws SQLException {
		fLogger.fatal("=========================================");
		fLogger.fatal("Not support yet");
		fLogger.fatal("=========================================");
		return false;
	}

	@Override
	public boolean createMirroredTableTo_FaseOnTable(
			MirroringRequest mirroring_request) throws SQLException {
		fLogger.fatal("=========================================");
		fLogger.fatal("Not support yet");
		fLogger.fatal("=========================================");
		return false;
	}

	@Override
	public boolean migration(ITransactionSQL osql, DBCrossRefference original,
			boolean drop, boolean cascade) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean migration(ITransactionSQL osql, IDBSequence original,
			boolean drop, boolean cascade, boolean noSchema)
			throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

}
