package org.kne.cloud.network;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.DatagramSocketImpl;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Flow.Subscriber;

public class DatagramServerSocket extends DatagramSocket {
	private Map<SocketAddress,SubDatagramSocket> clients=new ConcurrentHashMap<>();
	public DatagramServerSocket() throws SocketException {
		super((SocketAddress)null);
		setReuseAddress(true);
	}

	protected DatagramServerSocket(DatagramSocketImpl impl) throws SocketException {
		super(impl);
		setReuseAddress(true);
	}

	public DatagramServerSocket(int port, InetAddress laddr) throws SocketException {
		super((SocketAddress)null);
		setReuseAddress(true);
		bind(new InetSocketAddress(laddr, port));
	}

	public DatagramServerSocket(int port) throws SocketException {
		super((SocketAddress)null);
		setReuseAddress(true);
		bind(new InetSocketAddress(port));
	}

	public DatagramServerSocket(SocketAddress bindaddr) throws SocketException {
		super((SocketAddress)null);
		setReuseAddress(true);
		bind(bindaddr);
	}

	public DatagramServerSocket(int port, int backlog) throws SocketException {
		super((SocketAddress)null);
		setReuseAddress(true);
		bind(new InetSocketAddress(port));
	}

	@Override
	public synchronized void send(DatagramPacket p) throws IOException {
		// TODO 自动生成的方法存根
		super.send(p);
	}

	@Override
	public synchronized void receive(DatagramPacket p) throws IOException {
		// TODO 自动生成的方法存根
		super.receive(p);
	}

	public DatagramServerSocket(int port, int backlog, InetAddress laddr) throws SocketException {
		super((SocketAddress)null);
		setReuseAddress(true);
		bind(new InetSocketAddress(laddr, port));
	}
	public DatagramSocket accept()throws IOException{
		 if (isClosed())
	            throw new SocketException("Socket is closed");
	        if (!isBound())
	            throw new SocketException("Socket is not bound yet");
	        DatagramPacket dp=new DatagramPacket(new byte[65535], 65535);
	       do {
	        receive(dp);
	        System.out.println(dp);
	       }while(clients.containsKey(dp.getSocketAddress()));
	        System.out.println("accept");
	        SubDatagramSocket re=new SubDatagramSocket((SocketAddress)null);
	        re.dp=dp;
	        re.setReuseAddress(true);
	        re.bind(new InetSocketAddress(InetAddress.getByName("192.168.0.233"), getLocalPort()));
	        re.connect(dp.getSocketAddress());
	        return re;
	      /*  loop:while(true) {
	        receive(dp);
	        SocketAddress isa= dp.getSocketAddress() ;
	        synchronized (clients) {
	        	for (Iterator<SubDatagramSocket> iterator = clients.iterator(); iterator.hasNext();) {
					SubDatagramSocket subDatagramSocket = (SubDatagramSocket) iterator.next();
					if(subDatagramSocket.getRemoteSocketAddress().equals(isa)) {
						DatagramPacket dpx=dp;
			        	dp=new DatagramPacket(new byte[65535], 65535);
			        	subDatagramSocket.getFstq().offer(dpx);
			        	continue loop;
					}
				}
	        	DatagramPacket dpx=dp;
	        	dp=new DatagramPacket(new byte[65535], 65535);
	        	SubDatagramSocket sds=new SubDatagramSocket(isa);
	        	sds.getFstq().add(dpx);
	        	return sds;
	        
			}
	        }*/
	}
	private class SubDatagramSocket extends DatagramSocket{

        DatagramPacket dp;

		public SubDatagramSocket() throws SocketException {
			super();
		}

		protected SubDatagramSocket(DatagramSocketImpl impl) {
			super(impl);
		}

		public SubDatagramSocket(int port, InetAddress laddr) throws SocketException {
			super(port, laddr);
		}

		public SubDatagramSocket(int port) throws SocketException {
			super(port);
		}

		public SubDatagramSocket(SocketAddress bindaddr) throws SocketException {
			super(bindaddr);
		}

		@Override
		public void connect(InetAddress address, int port) {
			super.connect(address, port);
			clients.put(new InetSocketAddress(address, port),this);
		}

		@Override
		public void connect(SocketAddress addr) throws SocketException {
			super.connect(addr);
			clients.put(addr,this);
		}

		@Override
		public void receive(DatagramPacket p) throws IOException {
			if(dp!=null) {
				p.setLength(dp.getLength());
				System.arraycopy(dp.getData(), dp.getOffset(), p.getData(), p.getOffset(), dp.getLength());
				dp=null;
			}else {
			super.receive(p);
			}
		}
		
		@Override
		public void disconnect() {
			super.disconnect();
			SocketAddress sa=getRemoteSocketAddress();
			if(sa!=null)
			clients.remove(sa);
		}

		public void close() {
			super.close();
			SocketAddress sa=getRemoteSocketAddress();
			if(sa!=null)
			clients.remove(sa);
		}
	}
}
