/*package org.kne.cloud.network.klalb;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

import org.kne.cloud.network.MultipurposeSocketAddress;
import org.kne.cloud.network.SpeedLimiter;

public class DatagramKLALBPacketLink implements KLALBPacketLink {

	private static final int MTU=1500;
	
	private static final int HEAD=32;
	
	private int packSign=0;
	
	@Override
	public String toString() {
		return new MultipurposeSocketAddress("UDP",(InetSocketAddress)ds.getLocalSocketAddress())+"←"+new MultipurposeSocketAddress("UDP",(InetSocketAddress)ds.getRemoteSocketAddress());
	}

	private DatagramSocket ds;

	public DatagramKLALBPacketLink(DatagramSocket connectDatagramSocket) throws IOException {
		this.ds=connectDatagramSocket;
	}

		private ByteArrayOutputStream bos=new ByteArrayOutputStream(65535);
		private DataOutputStream dos=new DataOutputStream(bos);
	@Override
	public void writePacket(KLALBPacket kp) throws IOException {
		//System.out.println("               TX:"+kp);
		KLALBOutputStream.writeKLALBPacketToStream(dos, kp);
		
	}

	private byte[]bc=new byte[65535];
	DataInputStream dis;
	@Override
	public KLALBPacket readPacket() throws IOException {
		KLALBPacket kp=null;
		do {
		if(dis==null) {
			
			byte[]data=new byte[65535];
		DatagramPacket dp=new DatagramPacket(data, data.length);
		ds.receive(dp);
		
		
		dis=new DataInputStream(new ByteArrayInputStream(bc, 0, dp.getLength()));
		}
		kp=KLALBInputStream.readKLALBPacketFromStream(dis);
		if(kp!=null) {
			break;
		}
		dis=null;
		//System.out.println("               RX:"+kp);
		}while(true);
		return kp;
	}

	@Override
	public void close() throws IOException {
		ds.close();
	}

	@Override
	public boolean isClosed() {
		return ds.isClosed();
	}

	@Override
	public void setSoTimeout(int val) throws SocketException  {
		ds.setSoTimeout(val);
	}

	@Override
	public int getSoTimeout() throws SocketException {
		return	ds.getSoTimeout();
	}

	@Override
	public void flush() throws IOException {
		byte[]bt=bos.toByteArray();
		bos.reset();
		int seq=0;
		int maxseq=(bt.length+MTU-HEAD-1)/(MTU-HEAD);
		int startptr=0;
		while(startptr<bt.length) {
			int copysize=Math.min(bt.length-startptr,MTU-HEAD);
			byte[]data=new byte[copysize+4];
			data[2]=(byte) (packSign>>8);
			data[3]=(byte) packSign;
			data[4]=(byte)seq;
			data[5]=(byte)maxseq;
			System.arraycopy(bt, startptr, data, 6, copysize);
			startptr+=copysize;
		DatagramPacket dp=new DatagramPacket(data,data.length);
		ds.send(dp);
		}
		packSign++;
		packSign=packSign&0xffff;
	}

	@Override
	public boolean isStream() {
		return false;
	}
}*/
package org.kne.cloud.network.klalb;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

import org.kne.cloud.network.DatagramServerSocket.SubDatagramSocket;
import org.kne.cloud.network.MultiProtocolSocketAddress;
import org.kne.cloud.network.NetworkPacket;
import org.kne.cloud.network.PacketRebuilder;
import org.kne.cloud.network.PacketSpliter;

public class SplitedDatagramKLALBPacketLink extends AbstractKLALBPacketLink implements KLALBPacketLink {
	private PacketSpliter pslr;
	private PacketRebuilder pbdr;
	
	@Override
	public String toString() {
		return new MultiProtocolSocketAddress("UDP",(InetSocketAddress)ds.getLocalSocketAddress())+"←"+new MultiProtocolSocketAddress("UDP",(InetSocketAddress)ds.getRemoteSocketAddress());
	}

	private DatagramSocket ds;

	public SplitedDatagramKLALBPacketLink(DatagramSocket connectDatagramSocket) throws IOException {
		this.ds=connectDatagramSocket;
		pslr=new PacketSpliter(new WritableByteChannel() {
			
			@Override
			public boolean isOpen() {
				return !ds.isClosed();
			}
			
			@Override
			public void close() throws IOException {
			}
			
			@Override
			public int write(ByteBuffer src) throws IOException {
				int rem=src.remaining();
				byte[]bt=src.array();
				DatagramPacket dp=new DatagramPacket(bt,src.position(),src.limit());
				//System.out.println("SendDatagram:"+src.remaining());
				ds.send(dp);
				return rem;
			}
		},1350);
		pbdr=new PacketRebuilder(new ReadableByteChannel() {
			
			@Override
			public boolean isOpen() {
				return !ds.isClosed();
			}
			
			@Override
			public void close() throws IOException {
			}
			
			@Override
			public int read(ByteBuffer dst) throws IOException {DatagramPacket dp;
				if(ds instanceof SubDatagramSocket) {
					dp=((SubDatagramSocket) ds).receive();
					dst.put(dp.getData(), 0, dp.getLength());
					
				}else {
				dp=new DatagramPacket(bc, bc.length);
				ds.receive(dp);
				dst.put(dp.getData(), 0, dp.getLength());
				}
				//System.out.println("RecvDatagram:"+dp.getLength());
				return dp.getLength();
			}
		},1000000000);
		
	}

		//private ByteBuffer bbf=ByteBuffer.allocate(65535);
		
	/*@Override
	public void writeKLALBPacket(KLALBPacket kp) throws IOException {
		//System.out.println("               TX:"+kp);
		//KLALBPacket.writeKLALBPacketToStream(dos, kp);
		KLALBPacket.writeKLALBPacketToChannel(new WritableByteChannel() {

			@Override
			public boolean isOpen() {
				return true;
			}

			@Override
			public void close() throws IOException {
				
			}

			@Override
			public int write(ByteBuffer src) throws IOException {
				int sr=src.remaining();
				//try {
				bbf.put(src);
				//}catch (Exception e) {e.printStackTrace();
				//System.out.println(src+" "+bbf);
				//}
				return sr;
			}
			
		}, kp);
	}*/

	private byte[]bc=new byte[65535];

	//private ByteBuffer bibf=ByteBuffer.allocate(65535);
	
	/*@Override
	public KLALBPacket readKLALBPacket() throws IOException {
		KLALBPacket kp=null;
		do {
		if(bibf.remaining()<=0) {
			bibf.clear();
			
		
			pbdr.read(bibf );
			
			bibf.flip();
		}
		kp=KLALBPacket.readKLALBPacketFromChannel(new ReadableByteChannel() {
			
			@Override
			public boolean isOpen() {
				return true;
			}
			
			@Override
			public void close() throws IOException {
				
			}
			
			@Override
			public int read(ByteBuffer dst) throws IOException {
				int olmt=bibf.limit();

				int rst=Math.min(bibf.remaining(),dst.remaining());
					bibf.limit(rst+bibf.position());
					dst.put(bibf);
					bibf.limit(olmt);
				return rst;
			}
		});
		if(kp!=null) {
			break;
		}
		//dis=null;
		//System.out.println("               RX:"+kp);
		}while(true);
		return kp;
	}
*/
	@Override
	public void close() throws IOException {
		ds.close();
	}

	@Override
	public boolean isClosed() {
		return ds.isClosed();
	}

	@Override
	public void setSoTimeout(int val) throws SocketException  {
		ds.setSoTimeout(val);
	}

	@Override
	public int getSoTimeout() throws SocketException {
		return	ds.getSoTimeout();
	}

	/*@Override
	public void flush() throws IOException {
		bbf.flip();
		//TimeDebugger tdb=new TimeDebugger();
		//tdb.putTime("flushStart");
		pslr.write(bbf, new WritableByteChannel() {
			
			@Override
			public boolean isOpen() {
				return true;
			}
			
			@Override
			public void close() throws IOException {
			}
			
			@Override
			public int write(ByteBuffer src) throws IOException {
				int rem=src.remaining();
				byte[]bt=src.array();
				DatagramPacket dp=new DatagramPacket(bt,src.position(),src.limit());
				ds.send(dp);
				return rem;
			}
		});
		//tdb.putTime("flushEnd");
		//tdb.print();
		
		bbf.clear();
	
	}*/

	@Override
	public boolean isStream() {
		return false;
	}

	@Override
	public void writePacket(ByteBuffer kp) throws IOException {
		pslr.write(kp);
	}

	@Override
	public ByteBuffer readPacket() throws IOException {
			ByteBuffer bbf=NetworkPacket.bufferAllocator.allocate(65535);
				pbdr.read(bbf );
				bbf.flip();
			return bbf;
	}

	@Override
	public void flush() throws IOException {
		// TODO 自动生成的方法存根
		
	}
}
