package hiro.yoshioka.sql;

import hiro.yoshioka.ast.sql.oracle.WolfSQLParserConstants;
import hiro.yoshioka.sdh.ResultSetDataHolder;
import hiro.yoshioka.sdh2.ResultSetDataHolder2;
import hiro.yoshioka.sql.engine.Request;
import hiro.yoshioka.sql.engine.GettingResourceRequest;
import hiro.yoshioka.sql.engine.SQLOperationType;
import hiro.yoshioka.sql.engine.TransactionRequest;
import hiro.yoshioka.sql.params.ConnectionProperties;
import hiro.yoshioka.sql.resource.DBColumn;
import hiro.yoshioka.sql.resource.DBRoot;
import hiro.yoshioka.sql.resource.DBSchema;
import hiro.yoshioka.sql.resource.DBTable;
import hiro.yoshioka.sql.resource.IDBSchema;
import hiro.yoshioka.util.SQLDataType;

import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ODBCSQL extends AbsTransactionSQL {

	public static String getSuggestURL() {
		return "jdbc:odbc:";
	}

	protected ODBCSQL(Driver ds) {
		super(ds);
	}

	public boolean close() throws SQLException {
		boolean status = true;
		if (_con != null) {
			try {
				if (!_con.isClosed()) {
					_con.rollback();
					_con.close();
				}
				// fTrunsactionTime = false;
			} finally {
				_con = null;
			}
		}
		if (_extra_con != null) {
			try {
				if (!_extra_con.isClosed()) {
					_extra_con.close();
				}
				// fTrunsactionTime = false;
			} finally {
				_extra_con = null;
			}
		}
		for (int i = 0; i < fConnectionListenerList.size(); i++) {
			fConnectionListenerList.get(i).disconnected();
		}
		return status;
	}

	protected String getSupportToken() {
		StringBuffer buf = new StringBuffer();
		Pattern p = Pattern.compile("\"(\\w+)\"");
		String[] str = WolfSQLParserConstants.tokenImage;
		for (int i = 0; i < str.length; i++) {
			Matcher m = p.matcher(str[i]);
			if (m.matches()) {
				buf.append(m.group(1)).append(",");
			}
		}
		if (buf.length() > 0) {
			buf.setLength(buf.length() - 1);
		}
		return buf.toString();
	}

	protected void createDBProcedureDef(GettingResourceRequest request)
			throws SQLException {
	}

	protected void createDBTableDef(GettingResourceRequest request)
			throws SQLException {
		ResultSetDataHolder rdh = null;

		DatabaseMetaData meta = _extra_con.getMetaData();

		rdh = RS2RDH(meta.getTables(null, null, null, null), true, null, null);
		DBRoot root = getRoot();
		for (int i = 0; i < rdh.getRowCount(); i++) {
			String tableSchem = rdh.getStringData(i, "TABLE_SCHEM");
			String tableName = rdh.getStringData(i, "TABLE_NAME").toUpperCase();
			String type = rdh.getStringData(i, "TABLE_TYPE").toUpperCase();

			if (tableName.indexOf("/") > -1) {
				rdh.deleteRow(i);
				i--;
				fLogger.warn("Ignore Schema/Table/TYPE [" + tableSchem + "/"
						+ tableName + "/" + type + "] ");
				continue;
			}
			if (tableSchem != null) {
				tableSchem = tableSchem.toUpperCase();
			}
			IDBSchema mschema = (IDBSchema) root.getResource(tableSchem);
			if (mschema == null) {
				mschema = new DBSchema(root);
				mschema.setName(tableSchem);
				root.putResource(mschema.getName(), mschema);
			}
			DBTable dbTable = new DBTable(mschema);
			dbTable.setName(tableName);
			dbTable.setTableType(type);
			if (dbTable.isTable()) {
				setTableColumns(mschema.getName(), dbTable);
			}
			mschema.putTable(dbTable);

			setResourceProperties(dbTable, i, rdh);

		}

	}

	public boolean doOperation(SQLOperationType operation, Request request)
			throws SQLException {
		boolean retCode = true;
		switch (operation) {
		case SELECT_SESSION:
			request.setRDH(getSessionInfo());
			break;
		case PREPARED_EXECUTE_QUERY:
			TransactionRequest treq = (TransactionRequest) request;
			treq.setRDH(executeQuery(treq.getSQLStatement()));
			break;
		default:
			retCode = super.doOperation(operation, request);
			break;
		}
		return retCode;
	}

	public ResultSetDataHolder2 executeQuery(String sql_statement)
			throws SQLException {
		Statement statement = null;
		ResultSet rs = null;
		if (_con == null) {
			return null;
		}
		try {

			statement = _con.createStatement();
			fLogger.trace(sql_statement);
			long time = System.currentTimeMillis();
			rs = statement.executeQuery(sql_statement);
			time = System.currentTimeMillis() - time;
			ResultSetDataHolder2 rdh = RS2RDH(rs, true, sql_statement, null);
			rdh.setWrapTime(time);
			return rdh;
		} finally {
			if (statement != null) {
				statement.close();
			}
		}
	}

	/**
	 * @param operationCode
	 * @return
	 */
	public boolean canDoOperation(SQLOperationType operation) {
		switch (operation) {
		case SELECT_SESSION:
			return false;
		case SELECT_LOCK:
			return false;
		default:
			return super.canDoOperation(operation);
		}
	}

	@Override
	public boolean connect(ConnectionProperties properties) throws SQLException {
		try {
			try {
				_info = properties;
				_url = properties.getProperty("url");
				Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

				connectiong = true;
				_con = DriverManager.getConnection(properties
						.getProperty("url"));
				_con.setAutoCommit(properties.isAutoCommit());
				_extra_con = DriverManager.getConnection(properties
						.getProperty("url"));

				for (int i = 0; i < fConnectionListenerList.size(); i++) {
					fConnectionListenerList.get(i).connected();
				}
				return true;
			} catch (Exception e) {
				e.printStackTrace();
				return false;
			}
		} finally {
			connectiong = false;
		}
	}

	protected void setTableColumns(String schema, DBTable table)
			throws SQLException {
		ResultSetDataHolder rdh = null;

		ResultSet rs = null;
		Statement st = null;
		try {
			StringBuffer sql = new StringBuffer();
			sql.append("SELECT * FROM ");
			if (schema.trim().length() > 0) {
				sql.append(schema + ".");
			}
			sql.append(table);
			st = _con.createStatement();
			st.setMaxRows(1);

			rs = st.executeQuery(sql.toString());
			ResultSetMetaData md = rs.getMetaData();
			for (int i = 1; i <= md.getColumnCount(); i++) {
				DBColumn col = new DBColumn(table);
				col.setName(md.getColumnName(i));
				col.setDataType(SQLDataType.parse(md.getColumnType(i)));
				col.setSize(md.getPrecision(i));
				col.setDecimalDigits(md.getScale(i));
				col.setNullable((short) md.isNullable(i));

				table.putResource(col.getUName(), col);
			}
		} catch (Exception e) {
			return;
		} finally {
			if (rs != null) {
				rs.close();
			}
			if (st != null) {
				st.close();
			}
		}

	}

	@Override
	protected boolean setTableText(GettingResourceRequest request)
			throws SQLException {
		fLogger.fatal("Not support yet...");
		return false;
	}

	@Override
	protected void getTrigger(GettingResourceRequest request)
			throws SQLException {
		fLogger.fatal("Not support yet...");
	}

	@Override
	public ResultSetDataHolder2 getSessionInfo() throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	public ResultSetDataHolder2 getLockInfo() throws SQLException {
		return null;
	}

	@Override
	protected void setComments(GettingResourceRequest request)
			throws SQLException {
		// TODO Auto-generated method stub

	}

	@Override
	protected void getSequence(GettingResourceRequest request)
			throws SQLException {
		fLogger.fatal("Not support yet...");

	}

}