package com.jscape.inet.proxy.socks.protocol.v5.marshaling;

import com.jscape.util.IOTools;
import com.jscape.util.io.primitive.ByteCodec;
import com.jscape.util.io.primitive.ByteStringCodec;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;

/**
 * @author Alex Usun
 */
public class InetAddressCodec {

    private static final int IP_V4 = 0x01;
    private static final int DOMAIN_NAME = 0x03;
    private static final int IP_V6 = 0x04;

    public static void writeValue(InetAddress value, OutputStream out)
            throws IOException {
        if (value instanceof Inet4Address) {
            Inet4Address address = (Inet4Address) value;
            ByteCodec.writeValue((byte) IP_V4, out);
            out.write(address.getAddress());
        } else if (value instanceof Inet6Address) {
            Inet6Address address = (Inet6Address) value;
            ByteCodec.writeValue((byte) IP_V6, out);
            out.write(address.getAddress());
        }
    }

    public static InetAddress readValue(InputStream in)
            throws IOException {
        int code = ByteCodec.readValue(in) & 0xFF;
        switch (code) {
            case IP_V4:
                byte[] address4 = IOTools.read(new byte[4], in);
                return Inet4Address.getByAddress(address4);
            case IP_V6:
                byte[] address6 = IOTools.read(new byte[16], in);
                return Inet6Address.getByAddress(address6);
            case DOMAIN_NAME:
                String address = ByteStringCodec.readValue(StandardCharsets.UTF_8, in);
                return InetAddress.getByName(address);
            default:
                throw new IOException("Unsupported address code: " + code);
        }

    }

    private InetAddressCodec() {
    }
}
