/**
 * Copyright (C) <2019>  <chen junwen>
 * <p>
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * <p>
 * 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
 * General Public License for more details.
 * <p>
 * You should have received a copy of the GNU General Public License along with this program.  If
 * not, see <http://www.gnu.org/licenses/>.
 */
package io.mycat.resultset;

import io.mycat.MySQLPacketUtil;
import io.mycat.api.collector.RowBaseIterator;
import io.mycat.beans.mycat.MycatRowMetaData;

import java.math.BigDecimal;
import java.sql.Types;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Iterator;

/**
 * @author Junwen Chen
 * @todo convertor对于某些分支未完善
 **/
public class TextResultSetResponse extends AbstractMycatResultSetResponse {

    public TextResultSetResponse(RowBaseIterator iterator) {
        super(iterator);
    }

    @Override
    public Iterator<byte[]> rowIterator() {
        final RowBaseIterator rowBaseIterator = iterator;
        final MycatRowMetaData mycatRowMetaData = rowBaseIterator.getMetaData();
        final TextConvertor convertor = TextConvertorImpl.INSTANCE;
        final int columnCount = mycatRowMetaData.getColumnCount();

        return new Iterator<byte[]>() {
            @Override
            public boolean hasNext() {
                return rowBaseIterator.next();
            }

            @Override
            public byte[] next() {
                byte[][] row = new byte[columnCount][];
                for (int columnIndex = 0, rowIndex = 0; rowIndex < columnCount; columnIndex++, rowIndex++) {
                    int columnType = mycatRowMetaData.getColumnType(columnIndex);
                    row[rowIndex] = getValue(rowBaseIterator, convertor, columnIndex, columnType);
                }
                return MySQLPacketUtil.generateTextRow(row);
            }
        };
    }

    private byte[] getValue(RowBaseIterator rowBaseIterator, TextConvertor convertor, int columnIndex,
                            int columnType) {
        byte[] res;
        switch (columnType) {
            case Types.NUMERIC: {

            }
            case Types.DECIMAL: {
                BigDecimal value = rowBaseIterator.getBigDecimal(columnIndex);
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                res = convertor.convertBigDecimal(value);
                break;
            }
            case Types.BIT: {
                boolean value = rowBaseIterator.getBoolean(columnIndex);
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                res = convertor.convertBoolean(value);
                break;
            }
            case Types.TINYINT: {
                byte value = rowBaseIterator.getByte(columnIndex);
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                res = convertor.convertByte(value);
                break;
            }
            case Types.SMALLINT: {
                short value = rowBaseIterator.getShort(columnIndex);
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                res = convertor.convertShort(value);
                break;
            }
            case Types.BIGINT:
            case Types.INTEGER: {
                long value = rowBaseIterator.getLong(columnIndex);
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                res = convertor.convertLong(value);
                break;
            }
            case Types.REAL: {
                float value = rowBaseIterator.getFloat(columnIndex);
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                res = convertor.convertFloat(value);
                break;
            }
            case Types.FLOAT:
            case Types.DOUBLE: {
                double value = rowBaseIterator.getDouble(columnIndex);
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                res = convertor.convertDouble(value);
                break;
            }
            case Types.BINARY:
            case Types.VARBINARY:
            case Types.LONGVARBINARY: {
                byte[] value = rowBaseIterator.getBytes(columnIndex);
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                res = convertor.convertBytes(value);
                break;
            }
            case Types.DATE: {
                LocalDate value = rowBaseIterator.getDate(columnIndex);
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                res = convertor.convertDate(value);
                break;
            }
            case Types.TIME: {
                Duration value = rowBaseIterator.getTime(columnIndex);
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                res = convertor.convertDuration(value);
                break;
            }
            case Types.TIMESTAMP: {
                LocalDateTime value = rowBaseIterator.getTimestamp(columnIndex);
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                res = convertor.convertTimeStamp(value);
                break;
            }
            case Types.CHAR: {

            }
            case Types.VARCHAR: {

            }
            case Types.LONGVARCHAR: {
                String string = rowBaseIterator.getString(columnIndex);
                if (string == null) {
                    return null;
                }
                res = string.getBytes();
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                break;
            }
            case Types.BLOB: {

            }
            case Types.CLOB: {
                res = rowBaseIterator.getBytes(columnIndex);
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                break;
            }
            case Types.NULL: {
                res = null;
                return null;
            }
            case Types.OTHER: {
                String string = rowBaseIterator.getString(columnIndex);
                if (string == null) {
                    return null;
                }
                res = string.getBytes();
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                break;
            }
            case Types.BOOLEAN: {
                Boolean object = rowBaseIterator.getBoolean(columnIndex);
                if (rowBaseIterator.wasNull()) {
                    return null;
                }
                res = convertor.convertBoolean(object);
                break;

//                if (object instanceof Boolean) {
//                    return (Boolean) object ? "1".getBytes() : "0".getBytes();
//                }
//                if (object instanceof String) {
//                    return Boolean.parseBoolean((String) object) ? "1".getBytes() : "0".getBytes();
//                }
//                if (object instanceof Number) {
//                    return ((Number) object).intValue() > 0 ? "1".getBytes() : "0".getBytes();
//                }
//                if (object instanceof Character) {
//                    return (Character) object > 0 ? "1".getBytes() : "0".getBytes();
//                }
//                if (rowBaseIterator.wasNull()) {
//                    return null;
//                }
//                return object.toString().getBytes();
            }
            default:
                throw new RuntimeException("unsupport!");
        }
        return res;
    }

    @Override
    public void close() {
        this.iterator.close();
    }
}