package org.wushujames.connect.mysql;

import java.math.BigInteger;

import org.apache.kafka.connect.data.Schema;
import org.apache.kafka.connect.data.SchemaBuilder;
import org.apache.kafka.connect.data.Struct;

import com.google.code.or.common.glossary.Column;
import com.google.code.or.common.glossary.Row;
import com.zendesk.maxwell.schema.Table;
import com.zendesk.maxwell.schema.columndef.BigIntColumnDef;
import com.zendesk.maxwell.schema.columndef.ColumnDef;
import com.zendesk.maxwell.schema.columndef.ColumnType;
import com.zendesk.maxwell.schema.columndef.IntColumnDef;
import com.zendesk.maxwell.schema.columndef.StringColumnDef;

/**
 * 
 * DataConverter handles translating Maxwell schemas to Kafka Connect schemas and row data to Kafka
 * Connect records.
 * 
 * @author jylcheng
 *
 */
public class DataConverter {

    public static Schema convertPrimaryKeySchema(Table table) {
        String tableName = table.getName();
        String databaseName = table.getDatabase().getName();
        SchemaBuilder pkBuilder = SchemaBuilder.struct().name(databaseName + "." + tableName + ".pk");

        for (String pk : table.getPKList()) {
            int columnNumber = table.findColumnIndex(pk);
            addFieldSchema(table, columnNumber, pkBuilder);
        }
        return pkBuilder.build();
    }

    public static Schema convertRowSchema(Table table) {
        String tableName = table.getName();
        String databaseName = table.getDatabase().getName();
        SchemaBuilder builder = SchemaBuilder.struct().name(databaseName + "." + tableName);

        for (int columnNumber = 0; columnNumber < table.getColumnList().size(); columnNumber++) {
            addFieldSchema(table, columnNumber, builder);
        }
        return builder.build();
    }

    private static void addFieldSchema(Table table, int columnNumber,
            SchemaBuilder builder) {
        // TODO Auto-generated method stub
        ColumnDef def = table.getColumnList().get(columnNumber);
        String columnName = def.getName();
        ColumnType type = def.getType();
        switch (type) {
        case TINYINT:
            builder.field(columnName, Schema.INT16_SCHEMA);
            break;
        case INT:
            builder.field(columnName, Schema.INT32_SCHEMA);
            break;
        case CHAR:
            builder.field(columnName, Schema.STRING_SCHEMA);
            break;
        case BIGINT:
            builder.field(columnName, Schema.INT64_SCHEMA);
            break;
        default:
            throw new RuntimeException("unsupported type");
        }

    }

    static Struct convertPrimaryKeyData(Schema pkSchema, Table table, Row row) {
        Struct pkStruct = new Struct(pkSchema);

        for (String pk : table.getPKList()) {
            int idx = table.findColumnIndex(pk);

            Column column = row.getColumns().get(idx);
            ColumnDef def = table.getColumnList().get(idx);

            addFieldData(pkStruct, def, column);
        }
        return pkStruct;
    }

    private static void addFieldData(Struct struct, ColumnDef columnDef,
            Column column) {
        ColumnType type = columnDef.getType();
        String columnName = columnDef.getName();
        Object columnValue = column.getValue();
        switch (type) {
        case TINYINT:
            IntColumnDef shortIntDef = (IntColumnDef) columnDef;
            Long l1 = shortIntDef.toLong(columnValue);
            struct.put(columnName, l1.shortValue());
            break;
        case INT:
            IntColumnDef intDef = (IntColumnDef) columnDef;
            Long l2 = intDef.toLong(columnValue);
            struct.put(columnName, l2.intValue());
            break;
        case CHAR:
            StringColumnDef strDef = (StringColumnDef) columnDef;
            String s = strDef.toString(columnValue);
            struct.put(columnName, s);
            break;
        case BIGINT:
            BigIntColumnDef bigIntDef = (BigIntColumnDef) columnDef;
            BigInteger bigInt = bigIntDef.toNumeric(columnValue);
            struct.put(columnName, bigInt.longValue());
            break;

        default:
            throw new RuntimeException("unsupported type");
        }
    }

    static Struct convertRowData(Schema rowSchema, Table table, Row row) {
        Struct rowStruct = new Struct(rowSchema);

        for (int columnNumber = 0; columnNumber < table.getColumnList().size(); columnNumber++) {
            Column column = row.getColumns().get(columnNumber);
            ColumnDef def = table.getColumnList().get(columnNumber);

            addFieldData(rowStruct, def, column);
        }
        return rowStruct;
    }

}