package com.wecise.odb.jdbc;

import com.wecise.odb.Error;

import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.Socket;
import java.net.URL;
import java.sql.*;
import java.util.Calendar;

public class ODBPreparedStatement extends ODBStatement implements PreparedStatement {

    private Object[] parameters;
    private String sql;

    public ODBPreparedStatement(Connection conn, String sql) {
        super(conn);
        this.sql = sql;
        this.parseSql();
    }

    private void parseSql() {
        int num = 0;
        char[] a = this.sql.toCharArray();
        boolean ok = true;
        boolean escape = false;
        for (char c: a) {
            if (!escape) {
                if (c == '\\') {
                    escape = true;
                    continue;
                }
            } else {
                escape = false;
                continue;
            }
            if (c == '\'' || c == '"') {
                ok = !ok;
            }
            if (ok && c == '?') {
                num += 1;
            }
        }
        this.parameters = new Object[num];
    }

    private void setParam(int i, Object o) throws SQLException {
        if (i < 1 || i > parameters.length) {
            throw new SQLException(Error.parameterIndex + ": " + i);
        }
        int index = i - 1; // Sql start with 1, java start with 0
        this.parameters[index] = o;
    }

    @Override
    public ResultSet executeQuery() throws SQLException {
        exec(this.sql, this.parameters);
        return this.getResultSet();
    }

    @Override
    public int executeUpdate() throws SQLException {
        exec(this.sql, this.parameters);
        return 0;
    }

    @Override
    public void setNull(int i, int i1) throws SQLException {

    }

    @Override
    public void setBoolean(int i, boolean b) throws SQLException {
        setParam(i, b);
    }

    @Override
    public void setByte(int i, byte b) throws SQLException {
        setParam(i, b);
    }

    @Override
    public void setShort(int i, short i1) throws SQLException {
        setParam(i, i1);
    }

    @Override
    public void setInt(int i, int i1) throws SQLException {
        setParam(i, i1);
    }

    @Override
    public void setLong(int i, long l) throws SQLException {
        setParam(i, l);
    }

    @Override
    public void setFloat(int i, float v) throws SQLException {
        setParam(i, v);
    }

    @Override
    public void setDouble(int i, double v) throws SQLException {
        setParam(i, v);
    }

    @Override
    public void setBigDecimal(int i, BigDecimal bigDecimal) throws SQLException {
        setParam(i, bigDecimal);
    }

    @Override
    public void setString(int i, String s) throws SQLException {
        setParam(i, s);
    }

    @Override
    public void setBytes(int i, byte[] bytes) throws SQLException {
        setParam(i, bytes);
    }

    @Override
    public void setDate(int i, Date date) throws SQLException {
        setParam(i, date);
    }

    @Override
    public void setTime(int i, Time time) throws SQLException {
        setParam(i, time);
    }

    @Override
    public void setTimestamp(int i, Timestamp timestamp) throws SQLException {
        setParam(i, timestamp);
    }

    @Override
    public void setAsciiStream(int i, InputStream inputStream, int i1) throws SQLException {
        setParam(i, inputStream);
    }

    @Override
    public void setUnicodeStream(int i, InputStream inputStream, int i1) throws SQLException {
        setParam(i, inputStream);
    }

    @Override
    public void setBinaryStream(int i, InputStream inputStream, int i1) throws SQLException {
        setParam(i, inputStream);
    }

    @Override
    public void clearParameters() throws SQLException {
        this.parameters = new Object[0];
    }

    @Override
    public void setObject(int i, Object o, int i1) throws SQLException {
        setParam(i, o);
    }

    @Override
    public void setObject(int i, Object o) throws SQLException {
        setParam(i, o);
    }

    @Override
    public boolean execute() throws SQLException {
        exec(this.sql, this.parameters);
        return this.getResultSet() != null;
    }

    @Override
    public void addBatch() throws SQLException {
        throw new SQLFeatureNotSupportedException(Error.methodNotSupported + ": PreparedStatement.addBatch()");
    }

    @Override
    public void setCharacterStream(int i, Reader reader, int i1) throws SQLException {
        setParam(i, reader);
    }

    @Override
    public void setRef(int i, Ref ref) throws SQLException {
        setParam(i, ref);
    }

    @Override
    public void setBlob(int i, Blob blob) throws SQLException {
        setParam(i, blob);
    }

    @Override
    public void setClob(int i, Clob clob) throws SQLException {
        setParam(i, clob);
    }

    @Override
    public void setArray(int i, Array array) throws SQLException {
        setParam(i, array);
    }

    @Override
    public ResultSetMetaData getMetaData() throws SQLException {
        return this.getResultSet().getMetaData();
    }

    @Override
    public void setDate(int i, Date date, Calendar calendar) throws SQLException {
        setParam(i, date);
    }

    @Override
    public void setTime(int i, Time time, Calendar calendar) throws SQLException {
        setParam(i, time);
    }

    @Override
    public void setTimestamp(int i, Timestamp timestamp, Calendar calendar) throws SQLException {
        setParam(i, timestamp);
    }

    @Override
    public void setNull(int i, int i1, String s) throws SQLException {

    }

    @Override
    public void setURL(int i, URL url) throws SQLException {
        setParam(i, url);
    }

    @Override
    public ParameterMetaData getParameterMetaData() throws SQLException {
        return null;
    }

    @Override
    public void setRowId(int i, RowId rowId) throws SQLException {
        setParam(i, rowId);
    }

    @Override
    public void setNString(int i, String s) throws SQLException {
        setParam(i, s);
    }

    @Override
    public void setNCharacterStream(int i, Reader reader, long l) throws SQLException {
        setParam(i, reader);
    }

    @Override
    public void setNClob(int i, NClob nClob) throws SQLException {
        setParam(i, nClob);
    }

    @Override
    public void setClob(int i, Reader reader, long l) throws SQLException {
        setParam(i, reader);
    }

    @Override
    public void setBlob(int i, InputStream inputStream, long l) throws SQLException {
        setParam(i, inputStream);
    }

    @Override
    public void setNClob(int i, Reader reader, long l) throws SQLException {
        setParam(i, reader);
    }

    @Override
    public void setSQLXML(int i, SQLXML sqlxml) throws SQLException {
        setParam(i, sqlxml);
    }

    @Override
    public void setObject(int i, Object o, int i1, int i2) throws SQLException {
        setParam(i, o);
    }

    @Override
    public void setAsciiStream(int i, InputStream inputStream, long l) throws SQLException {
        setParam(i, inputStream);
    }

    @Override
    public void setBinaryStream(int i, InputStream inputStream, long l) throws SQLException {
        setParam(i, inputStream);
    }

    @Override
    public void setCharacterStream(int i, Reader reader, long l) throws SQLException {
        setParam(i, reader);
    }

    @Override
    public void setAsciiStream(int i, InputStream inputStream) throws SQLException {
        setParam(i, inputStream);
    }

    @Override
    public void setBinaryStream(int i, InputStream inputStream) throws SQLException {
        setParam(i, inputStream);
    }

    @Override
    public void setCharacterStream(int i, Reader reader) throws SQLException {
        setParam(i, reader);
    }

    @Override
    public void setNCharacterStream(int i, Reader reader) throws SQLException {
        setParam(i, reader);
    }

    @Override
    public void setClob(int i, Reader reader) throws SQLException {
        setParam(i, reader);
    }

    @Override
    public void setBlob(int i, InputStream inputStream) throws SQLException {
        setParam(i, inputStream);
    }

    @Override
    public void setNClob(int i, Reader reader) throws SQLException {
        setParam(i, reader);
    }
}
