package org.kne.cloud.network.ipv6;

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;

public class IPv6HopByHopTLV extends TLV {
    public static final int PAD1 = 0;
    public static final int PADN = 1;
    public static final int JUMBO_PAYLOAD = 0xC2;
    public static final int ROUTER_ALERT = 0x05;
	public static final int KLALB_OAM = 0x3E;
	public static final int KLALB_PASSPORT = 0x1E;
    
    public IPv6HopByHopTLV(ByteBuffer header) {
        this(header, true);
    }
    
    public IPv6HopByHopTLV(ByteBuffer header, boolean isDefault) {
        super(header, isDefault);
    }
    
    public IPv6HopByHopTLV(int type) {
        this(type, true);
    }
    
    public IPv6HopByHopTLV(int type, boolean isDefault) {
        super(type, isDefault);
    }
    
    public static IPv6HopByHopTLV readIPv6HopByHopTLVFromChannel(ReadableByteChannel din) throws IOException {
        ByteBuffer bbf = NetworkPacket.bufferAllocator.allocate(2);
        bbf.limit(1);
        while (bbf.hasRemaining()) {
            if (din.read(bbf) == -1) {
                return null;
            }
        }
        int type = bbf.get(0) & 0xff;
        IPv6HopByHopTLV htlv;
        
        switch(type) {
            case PAD1:
                // Pad1: 只有类型字段，没有数据部分
                htlv = new Pad1HopByHopTLV(bbf);
                htlv.readFromChannel(din, 0);
                return htlv;
            case PADN:
                // PadN: 有数据部分
                htlv = new PadNHopByHopTLV(bbf);
                htlv.readFromChannel(din, 0);
                return htlv;
            case ROUTER_ALERT:
                // 路由器告警: 有数据部分
                htlv = new RouterAlertHopByHopTLV(bbf, true);
                htlv.readFromChannel(din, 0);
                return htlv;
            case JUMBO_PAYLOAD:
                // 巨型载荷: 有数据部分
                htlv = new JumboPayloadHopByHopTLV(bbf, true);
                htlv.readFromChannel(din, 0);
                return htlv;
            case KLALB_OAM:    
            	// KLALB OAM
                htlv = new KLALBOAMHopByHopTLV(bbf);
                htlv.readFromChannel(din, 0);
                return htlv;
            case KLALB_PASSPORT:
            	// KLALB Passport
                htlv = new KLALBPassportHopByHopTLV(bbf);
                htlv.readFromChannel(din, 0);
                return htlv;
            default:
                // 未知类型: 假设有数据部分
                htlv = new IPv6HopByHopTLV(bbf, true);
                htlv.readFromChannel(din, 0);
                return htlv;
        }
    }
    
    public static void writeIPv6HopByHopTLVToChannel(WritableByteChannel dto, IPv6HopByHopTLV tlv) throws IOException {
        tlv.writeToChannel(dto);
    }

	@Override
	public String toString() {
		return "IPv6HopByHopTLV [getType()=" + getType() + ", getDataLength()=" + getDataLength() + "]";
	}
    
}





/**
 * 路由器告警 TLV - 有数据部分
 */
class RouterAlertHopByHopTLV extends IPv6HopByHopTLV {
    public RouterAlertHopByHopTLV(ByteBuffer header, boolean isDefault) {
        super(header, isDefault); // isDefault = true: 有数据部分
    }
    
    public short getAlertValue() {
        if (getData() != null && getData().remaining() >= 2) {
            ByteBuffer duplicate = getData().duplicate();
            return duplicate.getShort();
        }
        return 0;
    }
    
    public void setAlertValue(short value) {
        if (getData() == null) {
            // 根据isDefault逻辑，可能需要分配数据缓冲区
            // 这里简化处理
            return;
        }
        ByteBuffer duplicate = getData().duplicate();
        duplicate.putShort(value);
    }
}

/**
 * 巨型载荷 TLV - 有数据部分
 */
class JumboPayloadHopByHopTLV extends IPv6HopByHopTLV {
    public JumboPayloadHopByHopTLV(ByteBuffer header, boolean isDefault) {
        super(header, isDefault); // isDefault = true: 有数据部分
    }
    
    public int getJumboLength() {
        if (getData() != null && getData().remaining() >= 4) {
            ByteBuffer duplicate = getData().duplicate();
            return duplicate.getInt();
        }
        return 0;
    }
    
    public void setJumboLength(int length) {
        if (getData() == null) return;
        ByteBuffer duplicate = getData().duplicate();
        duplicate.putInt(length);
    }
}