package ru.yandex.webmaster3.core.util.yson;

import com.fasterxml.jackson.core.Base64Variant;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.core.base.GeneratorBase;
import com.fasterxml.jackson.core.json.JsonWriteContext;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;

/**
 * @author avhaliullin
 */
public class ToBinaryYsonGenerator extends GeneratorBase {
    private final YsonBinaryStreamWriter writer;

    public ToBinaryYsonGenerator(int features, ObjectCodec codec, YsonBinaryStreamWriter writer) {
        super(features, codec);
        this.writer = writer;
    }

    @Override
    public void flush() throws IOException {
        writer.flush();
    }

    @Override
    protected void _releaseBuffers() {
    }

    @Override
    protected void _verifyValueWrite(String typeMsg) throws IOException {
        int status = _writeContext.writeValue();
        if (status == JsonWriteContext.STATUS_EXPECT_NAME) {
            _reportError("Can not " + typeMsg + ", expecting field name");
        }
    }

    @Override
    public void writeStartArray() throws IOException {
        _verifyValueWrite("write number");
        writer.writeListStart();
    }

    @Override
    public void writeEndArray() throws IOException {
        writer.writeListEnd();
    }

    @Override
    public void writeStartObject() throws IOException {
        _verifyValueWrite("write number");
        writer.writeMapStart();
    }

    @Override
    public void writeEndObject() throws IOException {
        writer.writeMapEnd();
    }

    @Override
    public void writeFieldName(String name) throws IOException {
        writer.writeMapKey(name);
    }

    @Override
    public void writeString(String text) throws IOException {
        _verifyValueWrite("write number");
        writer.writeStringValue(text);
    }

    @Override
    public void writeString(char[] text, int offset, int len) throws IOException {
        _verifyValueWrite("write number");
        writeString(new String(text, offset, len));//TODO
    }

    @Override
    public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException {
        writeBinary(text, offset, length);
    }

    @Override
    public void writeUTF8String(byte[] text, int offset, int length) throws IOException {
        writeBinary(text, offset, length);
    }

    @Override
    public void writeRaw(String text) throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public void writeRaw(String text, int offset, int len) throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public void writeRaw(char[] text, int offset, int len) throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public void writeRaw(char c) throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public void writeBinary(Base64Variant bv, byte[] data, int offset, int len) throws IOException {
        _verifyValueWrite("write number");
        writer.writeBinaryStringValue(data, offset, len);
    }

    @Override
    public void writeNumber(int v) throws IOException {
        _verifyValueWrite("write number");
        writer.writeSInt64Value(v);
    }

    @Override
    public void writeNumber(long v) throws IOException {
        _verifyValueWrite("write number");
        writer.writeSInt64Value(v);
    }

    @Override
    public void writeNumber(BigInteger v) throws IOException {
        _verifyValueWrite("write number");
        writer.writeSInt64Value(v.longValue());
    }

    @Override
    public void writeNumber(double v) throws IOException {
        _verifyValueWrite("write number");
        writer.writeDoubleValue(v);
    }

    @Override
    public void writeNumber(float v) throws IOException {
        _verifyValueWrite("write number");
        writer.writeDoubleValue(v);
    }

    @Override
    public void writeNumber(BigDecimal v) throws IOException {
        _verifyValueWrite("write number");
        writer.writeDoubleValue(v.doubleValue());
    }

    @Override
    public void writeNumber(String encodedValue) throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public void writeBoolean(boolean state) throws IOException {
        _verifyValueWrite("write number");
        writer.writeBooleanValue(state);
    }

    @Override
    public void writeNull() throws IOException {
        _verifyValueWrite("write number");
        writer.writeEntity();
    }

    @Override
    public void close() throws IOException {
        flush();
        super.close();
    }
}
