package com.jscape.inet.ssh.protocol.v2.marshaling.keys;

import com.jscape.inet.ssh.protocol.v2.marshaling.primitive.StringCodec;
import com.jscape.inet.ssh.protocol.v2.messages.Signature;
import com.jscape.util.io.ByteArrayOutputStream;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @author Alex Usun
 */
public class DsaSignatureCodec
        implements SignatureCodec.EntryCodec {

    private static final int R_LENGTH = 20;
    private static final int S_LENGTH = 20;

    @Override
    public Signature read(String identifier, InputStream in)
            throws IOException {
        byte[] blob = StringCodec.readValue(in);
        byte[] rData = createSignValue(blob, 0, R_LENGTH);
        byte[] sData = createSignValue(blob, R_LENGTH, S_LENGTH);

        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        buffer.write(0x30);
        buffer.write(rData.length + sData.length + 4);
        buffer.write(0x02);
        buffer.write(rData.length);
        buffer.write(rData);
        buffer.write(0x02);
        buffer.write(sData.length);
        buffer.write(sData);

        return new Signature(identifier, buffer.toByteArray());
    }

    @Override
    public void write(Signature value, OutputStream out)
            throws IOException {
        int rLength = value.blob[3];
        byte[] rData = createSignDataValue(value.blob, 4, rLength, R_LENGTH);
        int sLength = value.blob[rLength + 5];
        byte[] sData = createSignDataValue(value.blob, rLength + 6, sLength, S_LENGTH);

        byte[] blob = new byte[rData.length + sData.length];
        System.arraycopy(rData, 0, blob, 0, rData.length);
        System.arraycopy(sData, 0, blob, rData.length, sData.length);

        StringCodec.writeValue(blob, out);
    }

    private byte[] createSignValue(byte[] data, int offset, int length) {
        for (; length > 0 && data[offset] == 0; ++offset, --length) {
            // ok
        }

        int size = data[offset] > 0 ? length : length + 1;
        int resultOff = data[offset] > 0 ? 0 : 1;
        byte[] result = new byte[size];
        System.arraycopy(data, offset, result, resultOff, length);

        return result;
    }

    private byte[] createSignDataValue(byte[] sign, int offset, int length, int resultLength) {
        for (; length > resultLength; ++offset, --length) {
            // ok
        }

        byte[] result = new byte[resultLength];
        int resultOff = resultLength - length;
        System.arraycopy(sign, offset, result, resultOff, length);

        return result;
    }
}
