package com.moex.asts.export;

import com.micex.client.Filler;
import com.micex.client.Meta;
import com.micex.client.Meta.Field;
import com.micex.client.Meta.Message;
import com.micex.client.Meta.Ticker;
import com.moex.memory.Column;
import com.moex.memory.Record;
import com.moex.memory.Table;
import com.moex.memory.Type;
import com.moex.util.Fixed;

public class ClientTable extends Table implements Filler {

    public static Type mapMetaType(Meta.FieldType type) {
        switch (type) {
        case Char:
            return Type.STRING;
        case Integer:
            return Type.INTEGER;
        case Float:
        case Fixed:
        case FloatPoint:
            return Type.FIXED;
        case Date:
            return Type.DATE;
        case Time:
            return Type.TIME;
        }
        return null;
    }

    static String toStringValue(Object value) {
        if (value == null)
            return null;
        return value.toString();
    }

    static long toLongValue(Object value) {
        if (value instanceof Number)
            return ((Number) value).longValue();
        return 0;
    }

    static double toDoubleValue(Object value) {
        if (value instanceof Number)
            return ((Number) value).doubleValue();
        return 0;
    }

    static Fixed toFixedValue(Object value) {
        if (value instanceof Fixed)
            return (Fixed) value;
        return Fixed.ZERO;
    }

    static int toDateValue(Object value) {
        if (value instanceof Number)
            return ((Number) value).intValue();
        return 0;
    }

    static int toTimeValue(Object value) {
        if (value instanceof Number)
            return ((Number) value).intValue();
        return 0;
    }

    void setRecordValue(Record target, Meta.Field source, Object value) {
        final int column = source.index;
        if (value == null) {
            if (source.isKey())
                // Set some reasonable default
                switch (source.type()) {
                    case Char:
                        target.setString(column, "");
                        break;
                    case Integer:
                        target.setLong(column, 0);
                        break;
                    case Float:
                    case Fixed:
                    case FloatPoint:
                        target.setFixed(column, Fixed.ZERO);
                        break;
                    case Date:
                        target.setDate(column, 0);
                        break;
                    case Time:
                        target.setDate(column, 0);
                        break;
                }
            else
                target.setNull(column);
        } else {
            switch (source.type()) {
                case Char:
                    target.setString(column, toStringValue(value));
                    break;
                case Integer:
                    target.setLong(column, toLongValue(value));
                    break;
                case Float:
                case Fixed:
                case FloatPoint:
                    target.setFixed(column, toFixedValue(value));
                    break;
                case Date:
                    final int date = toDateValue(value);
                    if (date > 0)
                        target.setDate(column, date);
                    else
                        target.setNull(column);
                    break;
                case Time:
                    final int time = toTimeValue(value);
                    if (time > 0)
                        target.setTime(column, time);
                    else
                        target.setNull(column);
                    break;
            }
        }
    }

    public final String name;

    public ClientTable(String name, Column[] columns) {
        super(columns);
        this.name = name;
    }

    private Record locator;

    @Override
    public boolean initTableUpdate(Message source) {
        locator = getLocator();
        return getPrimaryKeyCount() > 0;
    }

    @Override
    public void doneTableUpdate(Message source) {
        locator = null;
    }

    private int position;
    
    private Record current;

    @Override
    public boolean initRecordUpdate(Message source) {
        position = source.isOrderbook() ? -1 : search(locator);
        if (position < 0)
            current = newRow();
        else
            current = getPrimaryIndex().getRow(position);
        return position < 0;
    }

    @Override
    public void doneRecordUpdate(Message source) {
        if (position < 0)
            addRow(-position - 1, current);
        locator.clear();
        current = null;
    }

    @Override
    public int getRecordDecimals() {
        return current == null ? 0 : current.getScale();
    }

    @Override
    public void setRecordDecimals(int decimals) {
        if (current == null) return;
        current.setScale(decimals);
    }

    @Override
    public void setKeyValue(Field field, Object value) {
        if (locator != null)
            setRecordValue(locator, field, value);
    }

    @Override
    public void setFieldValue(Field field, Object value) {
        if (current != null)
            setRecordValue(current, field, value);
    }

    @Override
    public void switchOrderbook(Message source, Ticker ticker) {
        // nothing
    }

}
