package org.kne.cloud.network.tcp;

import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

import org.kne.cloud.network.NetworkPacket;
import org.kne.cloud.network.ipv6.TLV;

/**
 * TCP选项TLV基类
 * 遵循RFC 793和后续扩展的TCP选项格式
 */
public class TCPOptionTLV extends TLV {
    
    /**
     * 构造函数 - 从ByteBuffer创建
     */
    public TCPOptionTLV(ByteBuffer header, boolean isDefault) {
        super(header, isDefault);
    }
    
    /**
     * 构造函数 - 指定类型创建
     */
    public TCPOptionTLV(int type, boolean isDefault) {
        super(type, isDefault);
    }
    
    /**
     * 从通道读取TCP选项TLV
     */
    public static TCPOptionTLV readTCPOptionTLVFromChannel(ReadableByteChannel din) throws IOException {
        ByteBuffer typeBuffer = NetworkPacket.bufferAllocator.allocate(1);
        typeBuffer.limit(1);
        while (typeBuffer.hasRemaining()) {
            if (din.read(typeBuffer) == -1) {
                return null;
            }
        }
        typeBuffer.flip();
        int type = typeBuffer.get(0) & 0xff;
        
        TCPOptionTLV tcpOption;
        switch(type) {
            case TCPEndOption.END_OF_OPTION_LIST:
                tcpOption = new TCPEndOption(typeBuffer);
                tcpOption.readFromChannel(din, 0);
                return tcpOption;
            case TCPNopOption.NO_OPERATION:
                tcpOption = new TCPNopOption(typeBuffer);
                tcpOption.readFromChannel(din, 0);
                return tcpOption;
            case TCPMssOption.MAXIMUM_SEGMENT_SIZE:
                tcpOption = new TCPMssOption(typeBuffer);
                tcpOption.readFromChannel(din, 0);
                return tcpOption;
            case TCPWindowScaleOption.WINDOW_SCALE:
                tcpOption = new TCPWindowScaleOption(typeBuffer);
                tcpOption.readFromChannel(din, 0);
                return tcpOption;
            case TCPSackPermittedOption.SACK_PERMITTED:
                tcpOption = new TCPSackPermittedOption(typeBuffer);
                tcpOption.readFromChannel(din, 0);
                return tcpOption;
            case TCPTimestampOption.TIMESTAMP:
                tcpOption = new TCPTimestampOption(typeBuffer);
                tcpOption.readFromChannel(din, 0);
                return tcpOption;
            default:
                // 未知选项类型，按通用选项处理
                tcpOption = new TCPOptionTLV(typeBuffer, true);
                tcpOption.readFromChannel(din, 0);
                return tcpOption;
        }
    }
    
    /**
     * 写入TCP选项TLV到通道
     */
    public static void writeTCPOptionTLVToChannel(WritableByteChannel dto, TCPOptionTLV tlv) throws IOException {
        tlv.writeToChannel(dto);
    }
    
   
}

/**
 * End of Option List TCP选项
 */
class TCPEndOption extends TCPOptionTLV {
    public static final int END_OF_OPTION_LIST = 0;
    
    public TCPEndOption(ByteBuffer header) {
        super(header, false);
        setHeaderLength(1); // 单字节选项
    }
    
    @Override
    public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
        // 单字节选项，不需要读取额外数据
    }
    
    @Override
    public void writeToChannel(WritableByteChannel dto) throws IOException {
        // 只写入类型字节
        header.limit(1);
        dto.write(header.slice(0, 1));
    }
    
    @Override
    public long getTotalLength() {
        return 1;
    }
}

/**
 * No-Operation TCP选项
 */
class TCPNopOption extends TCPOptionTLV {
    public static final int NO_OPERATION = 1;
    
    public TCPNopOption(ByteBuffer header) {
        super(header, false);
        setHeaderLength(1); // 单字节选项
    }
    
    @Override
    public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
        // 单字节选项，不需要读取额外数据
    }
    
    @Override
    public void writeToChannel(WritableByteChannel dto) throws IOException {
        // 只写入类型字节
        header.limit(1);
        dto.write(header.slice(0, 1));
    }
    
    @Override
    public long getTotalLength() {
        return 1;
    }
}

/**
 * Maximum Segment Size TCP选项
 */
class TCPMssOption extends TCPOptionTLV {
    public static final int MAXIMUM_SEGMENT_SIZE = 2;
    
    public TCPMssOption(ByteBuffer header) {
        super(header, true);
    }
    
    public TCPMssOption(int mss) {
        super(MAXIMUM_SEGMENT_SIZE, true);
        setDataLength(2);
        ByteBuffer dataBuffer = NetworkPacket.bufferAllocator.allocate(2);
        dataBuffer.putShort((short) mss);
        dataBuffer.flip();
        getData().put(dataBuffer);
    }
    
    public int getMssValue() {
        if (getData() != null && getData().remaining() >= 2) {
            ByteBuffer duplicate = getData().duplicate();
            return duplicate.getShort() & 0xFFFF;
        }
        return 0;
    }
}

/**
 * Window Scale TCP选项
 */
class TCPWindowScaleOption extends TCPOptionTLV {
    public static final int WINDOW_SCALE = 3;
    
    public TCPWindowScaleOption(ByteBuffer header) {
        super(header, true);
    }
    
    public TCPWindowScaleOption(int scaleFactor) {
        super(WINDOW_SCALE, true);
        setDataLength(1);
        ByteBuffer dataBuffer = NetworkPacket.bufferAllocator.allocate(1);
        dataBuffer.put((byte) scaleFactor);
        dataBuffer.flip();
        getData().put(dataBuffer);
    }
    
    public int getScaleFactor() {
        if (getData() != null && getData().remaining() >= 1) {
            ByteBuffer duplicate = getData().duplicate();
            return duplicate.get() & 0xFF;
        }
        return 0;
    }
}

/**
 * SACK Permitted TCP选项
 */
class TCPSackPermittedOption extends TCPOptionTLV {
    public static final int SACK_PERMITTED = 4;
    
    public TCPSackPermittedOption(ByteBuffer header) {
        super(header, true);
        setDataLength(0); // 无数据部分
    }
    
    public TCPSackPermittedOption() {
        super(SACK_PERMITTED, true);
        setDataLength(0); // 无数据部分
    }
}

/**
 * Timestamp TCP选项
 */
class TCPTimestampOption extends TCPOptionTLV {
    public static final int TIMESTAMP = 8;
    
    public TCPTimestampOption(ByteBuffer header) {
        super(header, true);
    }
    
    public TCPTimestampOption(int tsValue, int tsEchoReply) {
        super(TIMESTAMP, true);
        setDataLength(8);
        ByteBuffer dataBuffer = NetworkPacket.bufferAllocator.allocate(8);
        dataBuffer.putInt(tsValue);
        dataBuffer.putInt(tsEchoReply);
        dataBuffer.flip();
        getData().put(dataBuffer);
    }
    
    public long getTimestampValue() {
        if (getData() != null && getData().remaining() >= 8) {
            ByteBuffer duplicate = getData().duplicate();
            return duplicate.getInt() & 0xFFFFFFFFL;
        }
        return 0;
    }
    
    public long getTimestampEchoReply() {
        if (getData() != null && getData().remaining() >= 8) {
            ByteBuffer duplicate = getData().duplicate();
            duplicate.position(4);
            return duplicate.getInt() & 0xFFFFFFFFL;
        }
        return 0;
    }
}