package org.kne.cloud.network.tun;

import java.io.IOException;
import java.lang.foreign.MemorySegment;
import java.net.SocketException;
import java.nio.ByteBuffer;

import org.kne.cloud.network.tun.WintunDriver.Packet;
import org.kne.cloud.network.tun.WintunDriver.SendPacket;
import org.kne.cloud.network.tun.WintunDriver.WintunSessionHandle;

public class WindowsTUNChannel implements TUNChannel {
	
	private WintunSessionHandle session;
	private MemorySegment waitevent;

	protected WindowsTUNChannel(WintunSessionHandle session) {
		this.session=session;
		this.waitevent =WintunDriver.getReadWaitEvent(session);
	}
	
	@Override
	public int write(ByteBuffer src) throws IOException {
		if(session==null) {
			throw new SocketException("TUN session closed!");
		}
		int rem=src.remaining();
		 SendPacket sendPacket = WintunDriver.allocateSendPacket(session, rem);
        if (sendPacket != null) {
            sendPacket.data().asByteBuffer().put(src);
            sendPacket.send();
        }
		return rem;
	}

	@Override
	public int read(ByteBuffer dst) throws IOException {
		while (true) {
			if(session==null) {
				throw new SocketException("TUN session closed!");
			}
			WindowsWaitHandle.waitForSingleObject(waitevent, 10);
            Packet packet = WintunDriver.receivePacket(session);
            if (packet != null) {
            	ByteBuffer bytebuf=packet.data().asByteBuffer();
            	int rem=Math.min(bytebuf.remaining(),dst.remaining());
            	dst.put(bytebuf);
                packet.release();
        		return rem;
            	
            }
		}
	}

	@Override
	public boolean isOpen() {
		return session!=null;
	}

	@Override
	public void close() throws IOException {
		WintunSessionHandle wsh=session;
		session=null;
		WintunDriver.endSession(wsh);
	}

}
