package liquibase.sqlgenerator.core;

import liquibase.database.Database;
import liquibase.datatype.DataTypeFactory;
import liquibase.exception.ValidationErrors;
import liquibase.sql.Sql;
import liquibase.sql.UnparsedSql;
import liquibase.sqlgenerator.SqlGeneratorChain;
import liquibase.statement.DatabaseFunction;
import liquibase.statement.core.InsertStatement;
import liquibase.structure.core.Relation;
import liquibase.structure.core.Table;

import java.util.Date;

public class InsertGenerator extends AbstractSqlGenerator<InsertStatement> {

    @Override
    public ValidationErrors validate(InsertStatement insertStatement, Database database, SqlGeneratorChain sqlGeneratorChain) {
        ValidationErrors validationErrors = new ValidationErrors();
        validationErrors.checkRequiredField("tableName", insertStatement.getTableName());
        validationErrors.checkRequiredField("columns", insertStatement.getColumnValues());

//        if (insertStatement.getSchemaName() != null && !database.supportsSchemas()) {
//           validationErrors.addError("Database does not support schemas");
//       }

        return validationErrors;
    }

    @Override
    public Sql[] generateSql(InsertStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) {
        StringBuffer sql = new StringBuffer("INSERT INTO " + database.escapeTableName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName()) + " (");
        for (String column : statement.getColumnValues().keySet()) {
            sql.append(database.escapeColumnName(statement.getCatalogName(), statement.getSchemaName(), statement.getTableName(), column)).append(", ");
        }
        sql.deleteCharAt(sql.lastIndexOf(" "));
        int lastComma = sql.lastIndexOf(",");
        if (lastComma >= 0) {
            sql.deleteCharAt(lastComma);
        }

        sql.append(") VALUES (");

        for (String column : statement.getColumnValues().keySet()) {
            Object newValue = statement.getColumnValues().get(column);
            if (newValue == null || newValue.toString().equalsIgnoreCase("NULL")) {
                sql.append("NULL");
            } else if (newValue instanceof String && !looksLikeFunctionCall(((String) newValue), database)) {
                sql.append(DataTypeFactory.getInstance().fromObject(newValue, database).objectToSql(newValue, database));
            } else if (newValue instanceof Date) {
                sql.append(database.getDateLiteral(((Date) newValue)));
            } else if (newValue instanceof Boolean) {
                if (((Boolean) newValue)) {
                    sql.append(DataTypeFactory.getInstance().getTrueBooleanValue(database));
                } else {
                    sql.append(DataTypeFactory.getInstance().getFalseBooleanValue(database));
                }
            } else if (newValue instanceof DatabaseFunction) {
                sql.append(database.generateDatabaseFunctionValue((DatabaseFunction) newValue));
            }
            else {
                sql.append(newValue);
            }
            sql.append(", ");
        }

        sql.deleteCharAt(sql.lastIndexOf(" "));
        lastComma = sql.lastIndexOf(",");
        if (lastComma >= 0) {
            sql.deleteCharAt(lastComma);
        }

        sql.append(")");

        return new Sql[] {
                new UnparsedSql(sql.toString(), getAffectedTable(statement))
        };
    }

    protected Relation getAffectedTable(InsertStatement statement) {
        return new Table().setName(statement.getTableName()).setSchema(statement.getCatalogName(), statement.getSchemaName());
    }
}

@@ -542,16 +542,66 @@
 ent%3E %7B%0A%0A
+%09private boolean previousInsertHasHeader = false;%0A
     @Ove
@@ -1321,32 +1321,40 @@
 neratorChain) %7B%0A
+       %0A
         StringBu
@@ -1381,16 +1381,621 @@
 gBuffer(
+);%0A        %0A        if(!previousInsertHasHeader) %7B%0A        %09generateHeader(sql,statement,database);%0A        %7D else %7B%0A            sql.append(%22,%22);        %09%0A        %7D%0A        generateValues(sql,statement,database);%0A%0A        return new Sql%5B%5D %7B%0A                new UnparsedSql(sql.toString(), getAffectedTable(statement))%0A        %7D;%0A    %7D%0A    %0A    public void setPreviousInsertStatement(boolean previousInsertHasHeader) %7B%0A    %09this.previousInsertHasHeader = previousInsertHasHeader;%0A    %7D%0A    %0A    public void generateHeader(StringBuffer sql,InsertStatement statement, Database database) %7B%0A        sql.append(
 %22INSERT 
@@ -2555,16 +2555,142 @@
  VALUES 
+%22);%0A    %7D%0A    public void generateValues(StringBuffer sql,InsertStatement statement, Database database) %7B%0A        sql.append(%22
 (%22);%0A%0A  
@@ -3972,16 +3972,20 @@
         
+int 
 lastComm
@@ -4117,25 +4117,24 @@
 d(%22)%22);%0A
-%0A
         
 return n
@@ -4129,120 +4129,24 @@
     
-return new Sql%5B%5D %7B%0A                new UnparsedSql(sql.toString(), getAffectedTable(statement))%0A        %7D;%0A    %7D
+%0A        %0A    %7D%0A
 %0A%0A  

refactor insertGenerator to allow for emitting only the values