/**
 * Copyright 2010-2014 Axel Fontaine
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.flywaydb.core.internal.dbsupport.vertica;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.flywaydb.core.internal.dbsupport.DbSupport;
import org.flywaydb.core.internal.dbsupport.JdbcTemplate;
import org.flywaydb.core.internal.dbsupport.Schema;
import org.flywaydb.core.internal.dbsupport.Table;
import org.flywaydb.core.internal.dbsupport.Type;
import org.flywaydb.core.internal.dbsupport.postgresql.PostgreSQLTable;

public class VerticaSchema extends Schema {

    public VerticaSchema(JdbcTemplate jdbcTemplate, DbSupport dbSupport, String name) {
        super(jdbcTemplate, dbSupport, name);
    }
    
    @Override
    protected boolean doExists() throws SQLException {
        return jdbcTemplate.queryForInt("SELECT COUNT(*) FROM v_catalog.schemata WHERE schema_name=?", name) > 0;
    }

    @Override
    protected boolean doEmpty() throws SQLException {
        int objectCount = jdbcTemplate.queryForInt(
                "SELECT count(*) FROM v_catalog.all_tables WHERE schema_name=? and table_type = 'TABLE'",
                name);
        return objectCount == 0;
    }

    @Override
    protected void doCreate() throws SQLException {
        jdbcTemplate.execute("CREATE SCHEMA " + dbSupport.quote(name));
    }

    @Override
    protected void doDrop() throws SQLException {
        jdbcTemplate.execute("DROP SCHEMA " + dbSupport.quote(name) + " CASCADE");
    }

    @Override
    protected void doClean() throws SQLException {
        for (String statement : generateDropStatementsForViews()) {
            jdbcTemplate.execute(statement);
        }

        for (Table table : allTables()) {
            table.drop();
        }

        for (String statement : generateDropStatementsForSequences()) {
            jdbcTemplate.execute(statement);
        }

        // Vertica does not support base types, enums or domains 

        // Includes scalar functions and aggregate functions:
        for (String statement : generateDropStatementsForFunctions()) {
            jdbcTemplate.execute(statement);
        }

        for (Type type : allTypes()) {
            type.drop();
        }
    }

    /**
     * Generates the statements for dropping the sequences in this schema.
     *
     * @return The drop statements.
     * @throws SQLException when the clean statements could not be generated.
     */
    private List<String> generateDropStatementsForSequences() throws SQLException {
        List<String> sequenceNames =
                jdbcTemplate.queryForStringList(
                        "SELECT sequence_name FROM v_catalog.sequences WHERE sequence_schema=?", name);

        List<String> statements = new ArrayList<String>();
        for (String sequenceName : sequenceNames) {
            statements.add("DROP SEQUENCE IF EXISTS " + dbSupport.quote(name, sequenceName));
        }

        return statements;
    }

    /**
     * Generates the statements for dropping the routines in this schema.
     *
     * @return The drop statements.
     * @throws SQLException when the clean statements could not be generated.
     */
    private List<String> generateDropStatementsForFunctions() throws SQLException {
        List<Map<String, String>> rows =
                jdbcTemplate.queryForList(
                        "select * from user_functions where schema_name = ? and procedure_type = 'User Defined Function'",
                        name);

        List<String> statements = new ArrayList<String>();
        for (Map<String, String> row : rows) {
            statements.add("DROP FUNCTION IF EXISTS " + dbSupport.quote(name, row.get("function_name")) + "(" + row.get("function_argument_type") + ")");
        }
        return statements;
    } 
    
    /**
     * Generates the statements for dropping the views in this schema.
     *
     * @return The drop statements.
     * @throws SQLException when the clean statements could not be generated.
     */
    private List<String> generateDropStatementsForViews() throws SQLException {
        List<String> viewNames =
                jdbcTemplate.queryForStringList(
                        //Search for all the table names 
                        "SELECT t.table_name FROM v_catalog.all_tables t" +
                                //in this schema
                                " WHERE schema_name=?" +
                                //Querying for 'VIEW' in Vertica will exclude user-defined tables, system tables and temporary tables 
                                " and table_type = 'VIEW'",
                        name);

        List<String> statements = new ArrayList<String>();
        for (String viewName : viewNames) {
            statements.add("DROP VIEW IF EXISTS " + dbSupport.quote(name, viewName));
        }
        return statements;
    }     
    
    @Override
    protected Table[] doAllTables() throws SQLException {
        List<String> tableNames =
                jdbcTemplate.queryForStringList(
                        //Search for all the table names 
                        "SELECT t.table_name FROM v_catalog.all_tables t" +
                                //in this schema
                                " WHERE schema_name=?" +
                                //Querying for 'TABLE' in Vertica will exclude views, system tables and temporary tables 
                                " and table_type =  'TABLE'",
                        name);
        //Vertica will drop projections, when using cascade, but it will not drop views.

        Table[] tables = new Table[tableNames.size()];
        for (int i = 0; i < tableNames.size(); i++) {
            tables[i] = new PostgreSQLTable(jdbcTemplate, dbSupport, this, tableNames.get(i));
        }
        return tables;
    }

    @Override
    public Table getTable(String tableName) {
        return new PostgreSQLTable(jdbcTemplate, dbSupport, this, tableName);
    }

}

@@ -763,63 +763,8 @@
 p;%0A%0A
-import org.flywaydb.core.internal.dbsupport.DbSupport;%0A
 impo
@@ -1084,16 +1084,34 @@
 s Schema
+%3CVerticaDbSupport%3E
  %7B%0A%0A    
@@ -1158,16 +1158,23 @@
 mplate, 
+Vertica
 DbSuppor

Fix to VerticaSchema to support an upstream change that involves type parameterization. The super class Schema ...changed to... Schema<S extends DbSupport>