/**
 * Copyright (C) 2009-2013 FoundationDB, LLC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.foundationdb.sql.embedded;

import com.foundationdb.ais.model.Column;
import com.foundationdb.server.collation.AkCollator;
import com.foundationdb.server.types.TInstance;
import com.foundationdb.server.types.common.types.TypesTranslator;
import com.foundationdb.sql.optimizer.plan.PhysicalSelect.PhysicalResultColumn;
import com.foundationdb.sql.types.DataTypeDescriptor;

import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import java.util.List;

public class JDBCResultSetMetaData implements ResultSetMetaData
{
    protected static class ResultColumn extends PhysicalResultColumn {
        private int jdbcType;
        private DataTypeDescriptor sqlType;
        private Column aisColumn;
        private TInstance type;
        private JDBCResultSetMetaData nestedResultSet;

        protected ResultColumn(String name, 
                               int jdbcType, DataTypeDescriptor sqlType, 
                               Column aisColumn, TInstance type,
                               JDBCResultSetMetaData nestedResultSet) {
            super(name);
            this.jdbcType = jdbcType;
            this.sqlType = sqlType;
            this.aisColumn = aisColumn;
            this.type = type;
            this.nestedResultSet = nestedResultSet;
        }

        public int getJDBCType() {
            return jdbcType;
        }

        public DataTypeDescriptor getSQLType() {
            return sqlType;
        }

        public Column getAISColumn() {
            return aisColumn;
        }
        
        public TInstance getType() {
            return type;
        }

        public int getScale() {
            if (sqlType != null)
                return sqlType.getScale();
            if ((aisColumn != null) && (aisColumn.getTypeParameter1() != null))
                return aisColumn.getTypeParameter1().intValue();
            return 0;
        }

        public int getPrecision() {
            if (sqlType != null)
                return sqlType.getPrecision();
            if ((aisColumn != null) && (aisColumn.getTypeParameter2() != null))
                return aisColumn.getTypeParameter2().intValue();
            return 0;
        }

        public boolean isNullable() {
            if (sqlType != null)
                return sqlType.isNullable();
            if (aisColumn != null)
                return (aisColumn.getNullable() == Boolean.TRUE);
            return false;
        }

        public String getTypeName() {
            if (sqlType != null)
                return sqlType.getTypeName();
            if (aisColumn != null)
                return aisColumn.getTypeName();
            return "";
        }

        public int getMaximumWidth() {
            if (sqlType != null)
                return sqlType.getMaximumWidth();
            return 1024;
        }

        public JDBCResultSetMetaData getNestedResultSet() {
            return nestedResultSet;
        }
    }

    private final TypesTranslator typesTranslator;
    private final List<ResultColumn> columns;

    protected JDBCResultSetMetaData(TypesTranslator typesTranslator,
                                    List<ResultColumn> columns) {
        this.typesTranslator = typesTranslator;
        this.columns = columns;
    }

    protected List<ResultColumn> getColumns() {
        return columns;
    }

    protected ResultColumn getColumn(int column) {
        return columns.get(column - 1);
    }

    /* Wrapper */

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        throw new SQLException("Not supported");
    }
    
    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
    
    /* ResultSetMetaData */

    @Override
    public int getColumnCount() throws SQLException {
        return columns.size();
    }

    @Override
    public boolean isAutoIncrement(int column) throws SQLException {
        return getColumn(column).getAISColumn().getIdentityGenerator() != null;
    }

    @Override
    public boolean isCaseSensitive(int column) throws SQLException {
        Column aisColumn = getColumn(column).getAISColumn();
        if (aisColumn == null)
            return false;
        AkCollator collator = aisColumn.getCollator();
        if (collator == null)
            return false;
        else
            return collator.isCaseSensitive();
    }

    @Override
    public boolean isSearchable(int column) throws SQLException {
        return false;
    }

    @Override
    public boolean isCurrency(int column) throws SQLException {
        return false;
    }

    @Override
    public int isNullable(int column) throws SQLException {
        return getColumn(column).isNullable() ? columnNullable : columnNoNulls;
    }

    @Override
    public boolean isSigned(int column) throws SQLException {
        return typesTranslator.isTypeSigned(getColumn(column).getType());
    }

    @Override
    public int getColumnDisplaySize(int column) throws SQLException {
        return getColumn(column).getMaximumWidth();
    }

    @Override
    public String getColumnLabel(int column) throws SQLException {
        return getColumn(column).getName();
    }

    @Override
    public String getColumnName(int column) throws SQLException {
        ResultColumn jdbcColumn = getColumn(column);
        Column aisColumn = jdbcColumn.getAISColumn();
        if (aisColumn != null)
            return aisColumn.getName();
        return jdbcColumn.getName();
    }

    @Override
    public String getSchemaName(int column) throws SQLException {
        Column aisColumn = getColumn(column).getAISColumn();
        if (aisColumn != null)
            return aisColumn.getTable().getName().getSchemaName();
        return "";
    }

    @Override
    public int getPrecision(int column) throws SQLException {
        return getColumn(column).getPrecision();
    }

    @Override
    public int getScale(int column) throws SQLException {
        return getColumn(column).getScale();
    }

    @Override
    public String getTableName(int column) throws SQLException {
        Column aisColumn = getColumn(column).getAISColumn();
        if (aisColumn != null)
            return aisColumn.getTable().getName().getTableName();
        return "";
    }

    @Override
    public String getCatalogName(int column) throws SQLException {
        return "";
    }

    @Override
    public int getColumnType(int column) throws SQLException {
        return getColumn(column).getJDBCType();
    }

    @Override
    public String getColumnTypeName(int column) throws SQLException {
        return getColumn(column).getTypeName();
    }

    @Override
    public boolean isReadOnly(int column) throws SQLException {
        return true;
    }

    @Override
    public boolean isWritable(int column) throws SQLException {
        return false;
    }

    @Override
    public boolean isDefinitelyWritable(int column) throws SQLException {
        return false;
    }

    @Override
    public String getColumnClassName(int column) throws SQLException {
        return typesTranslator.jdbcClass(getColumn(column).getType()).getName();
    }


    public JDBCResultSetMetaData getNestedResultSet(int column) {
        return getColumn(column).getNestedResultSet();
    }
}

@@ -4663,38 +4663,50 @@
 ption %7B%0A        
-return
+Column aisColumn =
  getColumn(colum
@@ -4722,16 +4722,99 @@
 Column()
+;%0A        if (aisColumn == null)%0A            return false;%0A        return aisColumn
 .getIden

Fix JDBCResultSet#isAutoIncrement() where aisColumn may be null.