package com.xixun.communicate;

import android.util.Log;

import com.xixun.display.BuildConfig;
import com.xixun.display.MainActivity;
import com.xixun.display.MyApp;
import com.xixun.display.MyLog;
import com.xixun.display.MyService;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import static java.lang.Thread.sleep;

/**
 * Created by Administrator on 17/3/31.
 */
public class ClientsManage {
	// 二次开发接口部分：
	public static final int IP_PORT_BASE = 31296;                                          // 一组TCP/UDP通讯起始端口。
	public static final int IP_PORT_BROADCAST = IP_PORT_BASE+0;
	public static final int IP_PORT_3G_OR_INTERNET_REPORT_TO_HOST = IP_PORT_BASE+1;
	public static final int IP_PORT_STRING = IP_PORT_BASE+2;
	public static final int IP_PORT_NO_STRING = IP_PORT_BASE+3;
	
	public static final int UDP_PORT = IP_PORT_BASE+10;
	public static final int TCP_PORT_COMMUNICATION = IP_PORT_BASE + 11;
	public static final int TCP_PORT_FILE_SEND = IP_PORT_BASE + 12;
	public static final int UDP_PORT_ACTIVE = IP_PORT_BASE+13;
    public static final int TCP_PORT_FILE_RECE = IP_PORT_BASE + 14;
    public static final int UDP_PORT_SEND_SYNC_TIME = IP_PORT_BASE+15;
    public static final int UDP_GPS_REPORT = IP_PORT_BASE+16;

	public static final int HEART_INTERVAL = Define.bRunOnDebug ? 300:3000;


    public LedCardCommunication ledCardCommunication=null;


    LinkedList clientsTable=null;

    public ServerSocket serverSocket_tcpCommunication = null;
    public ServerSocket serverSocket_SendFile = null;
    public DatagramSocket udpSendSocket =null;
    InetSocketAddress inetSocketAddress =null;

    //UdpRece udpRece=null;

    public MyService ms=null;

    public  ClientsManage(MyService service) {
            ms = service;
        clientsTable = new LinkedList();

        new Thread() {
		     public void run() {
			     Process();
		     }
	     }.start();

     }



    public void TransData_Byte(String strIdence, byte ucCommand,byte ucIdence, byte ucPipeId, byte[] DataBuffer, int iLength)
    {
        if (NeedExit()) return;
        if (clientsTable == null) return;

        for (int iOffset=0;iOffset<clientsTable.size();iOffset++) {
            if (NeedExit()) return;
            ClientManage clientManage = (ClientManage) clientsTable.get(iOffset);
            if (clientManage == null) continue;
            if (clientManage.NeedExit()) continue;
            if (clientManage.IdenceJundge(strIdence)) {
                clientManage.TransData_Byte(ucCommand, ucIdence, ucPipeId, DataBuffer, iLength);
            }
        }
    }

	// 获取当前客户端的连接数。
	public int Clients_GetConnectNumber(){   if (NeedExit()) return 0;
		if (clientsTable==null) return 0;
		return clientsTable.size();
	}
	

	// 得到某显示屏的内部参数
    public ClientManage Get_ClientManage(String clientID)
	{   if (NeedExit()) return null;
		if (clientID==null)  return null;
		if (clientID.length()==0)  return null;

		for (int iOffset=0;iOffset<clientsTable.size();iOffset++) {
			if (NeedExit()) return null;
            ClientManage clientManage=(ClientManage)clientsTable.get(iOffset);
			if (clientManage==null) continue;
			if (clientManage.NeedExit()) continue;

			if (clientManage.Client_IdenceJundge(clientID)) return clientManage;
		}
		return null;
	}


    public void Process(){
        ledCardCommunication=new LedCardCommunication(this,"127.0.0.1",IP_PORT_NO_STRING);
        new Thread() {
            public void run() {
                Clients_tcpCommunication_ConnectProcess();
            }
        }.start();
/*
        new Thread() {
            public void run() {
                Clients_SendFile_ConnectProcess();
            }
        }.start();
*/
        if (ledCardCommunication.bTestInNewFpga==false) {
            new Thread() {
                public void run() {
                    Clients_UdpSendBroadcaseInformations();
                }
            }.start();// 最后开始UDP通播.
        }

        if (Define.bSyncPlay_Main_Sub) {
            new Thread() {
                public void run() {
                    Clients_UdpSendTime();
                }
            }.start();// 最后开始UDP通播.
        }
        else{
            //udpRece=new UdpRece(UDP_PORT_SEND_SYNC_TIME);
        }
        while (NeedExit()==false) {
            for (int iOffset = 0; iOffset < clientsTable.size(); iOffset++) {
                if (NeedExit()) return;
                ClientManage hostManage = (ClientManage) clientsTable.get(iOffset);
                if (hostManage == null) continue;
                if (hostManage.NeedExit()) continue;

            }
            if (bRequestRestart)   //   false
            {
                MyLog.i(" "+ Thread.currentThread().getStackTrace()[2].getFileName() + "-->"
                        +   "Function: " +Thread.currentThread().getStackTrace()[2].getMethodName() + "-->"
                        +   "Line" +Thread.currentThread().getStackTrace()[2].getLineNumber() + ": Received Exit.\r\n"
                );
                Exit(null);
                break;
            }
            if (strExitIdence != null)  //strExitIdence = null
            {
                Exit(strExitIdence);
                strExitIdence = null;
            }
            MyLog.sleepForSecond(5);
        }
	}

    private void Clients_tcpCommunication_ConnectProcess(){
        int iCounter=0;
        while(!NeedExit()) {
        try {
            //serverSocket = new ServerSocket(TCP_PORT_COMMUNICATION);
//            if (serverSocket_tcpCommunication == null){
                serverSocket_tcpCommunication = new ServerSocket();
                serverSocket_tcpCommunication.setReuseAddress(true); // 设置为可复用.
                serverSocket_tcpCommunication.bind(new InetSocketAddress(TCP_PORT_COMMUNICATION));  // 31307
//            }
          //  MyLog.i("----------------------------Wait Port Connect: "+TCP_PORT_COMMUNICATION);
          //  iCounter=0;
            while (!NeedExit()) {
                MyLog.i("Wait for client =======================================");
                Socket socket = serverSocket_tcpCommunication.accept();//set ip point
                if (NeedExit())  // N
                {   socket.close();
                    break;
                }
                synchronized (this) {              // 等待ledsyncset打开建立连接
                    socket.setReuseAddress(true);
                    String clientIpAddress = socket.getInetAddress().getHostAddress(); // clientIpAddress = 192.168.1.127
                    if (clientIpAddress == null) continue;
                    if (clientIpAddress.length() < 8) continue;
                    MyLog.i("----------------------------New IP Connect: "+clientIpAddress);
                    if (Get_ClientManage(clientIpAddress) == null) {
                        ClientManage clientManage = new ClientManage(this, clientIpAddress);
                        if (clientManage == null) continue;
                         clientsTable.add(clientManage);
                    }

                    ClientManage clientManage = Get_ClientManage(clientIpAddress);
                    if (clientManage != null) clientManage.SettcpCommunicationSocket(socket);
                }
            }
        } catch (Exception e) {
            /*if (NeedExit() == false)
                MyLog.i(Thread.currentThread().getStackTrace()[2].getFileName() + "-->"
                        + "Function: " + Thread.currentThread().getStackTrace()[2].getMethodName() + "-->"
                        + "Line" + Thread.currentThread().getStackTrace()[2].getLineNumber() + ":\r\n"
                        + "    Error:" + e.getMessage() + "\r\n\r\n"
                );*/
            e.printStackTrace();
        }
        try {
            ClientsExit();
            if (serverSocket_tcpCommunication != null) {
                serverSocket_tcpCommunication.close();
                serverSocket_tcpCommunication=null;
            }
            sleep(2000);

            iCounter++;
            if (iCounter>100) {
                break;
            }
        }catch (Exception e) {}


    }
        Exit(null);
    }

    public void Clients_SendFile_ConnectProcess(){
        int iCounter=0;
        while(NeedExit()==false) {
        try {
            serverSocket_SendFile = new ServerSocket();
            serverSocket_SendFile.setReuseAddress(true);
            serverSocket_SendFile.bind(new InetSocketAddress(TCP_PORT_FILE_SEND));

            while (NeedExit() == false) {
                Socket socket = serverSocket_SendFile.accept();
                if (NeedExit()) break;
                iCounter=0;
                synchronized (this) {
                    String clientIpAddress = socket.getInetAddress().getHostAddress();
                    if (clientIpAddress == null) continue;
                    if (clientIpAddress.length() < 8) continue;
                    if (Get_ClientManage(clientIpAddress) == null) {
                        ClientManage clientManage = new ClientManage(this, clientIpAddress);
                        if (clientManage == null) continue;
                        clientsTable.add(clientManage);
                    }
                    ClientManage clientManage = Get_ClientManage(clientIpAddress);
                    if (clientManage != null) clientManage.SetSendFileSocket(socket);
                }
            }
        } catch (Exception e) {
            if (NeedExit() == false)
                MyLog.i(Thread.currentThread().getStackTrace()[2].getFileName() + "-->"
                        + "Function: " + Thread.currentThread().getStackTrace()[2].getMethodName() + "-->"
                        + "Line" + Thread.currentThread().getStackTrace()[2].getLineNumber() + ":\r\n"
                        + "    Error:" + e.getMessage() + "\r\n\r\n"
                );
        }
        try {
            if (serverSocket_SendFile != null) {
                serverSocket_SendFile.close();
                serverSocket_SendFile=null;
            }
            iCounter++;
            if (iCounter>1000) {
                sleep(1000);
                break;
            }
        }catch (Exception e) {}
    }
        Exit(null);
    }

    public void Clients_UdpSendBroadcaseInformations() {
        int iCounter=0;
        while(!NeedExit()) {
            try {
                String strSendString=
                                         "iTcpPort="        + TCP_PORT_COMMUNICATION + ";"
                                //   +   "iSendFilePort="        + TCP_PORT_FILE_SEND+ ";"
                                //   +   "iReceFilePort="        + TCP_PORT_FILE_RECE+ ";"
                                +   "iHeartInterval="       + HEART_INTERVAL+ ";";
                iCounter=0;
                while (ledCardCommunication.Get_DisplayID()==null){
                    if (NeedExit()) return;
                    iCounter++;
                    if (iCounter>5) break;
                    sleep(HEART_INTERVAL);
                    MyLog.i( "Wait Get ID："+strSendString  );
                }
                if (ledCardCommunication.Get_DisplayID()!=null)
                {   strSendString+=  "DisplayID="       + ledCardCommunication.Get_DisplayID()+ ";";
                strSendString+=" ver:"+BuildConfig.VERSION_NAME;
                }
                else
                {
                    strSendString+=  "DisplayID="       + "XiXun-Display" + ";";
                }
                List<String> strBoardCastIp=null;
                DatagramPacket sendPacket =null;
                byte sendDataBuffer[] = strSendString.getBytes();

                if(udpSendSocket==null){
                    udpSendSocket = new DatagramSocket(null);
                    udpSendSocket.setReuseAddress(true);
                    udpSendSocket.bind(new InetSocketAddress(UDP_PORT));
                }
                while (!NeedExit())
                {
                    try {
                        sleep(HEART_INTERVAL); // 第一次时，先等待其他服务端口套接字线程准备好。
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }

                    if ((strBoardCastIp!=NetDevicesManage.GetBoardCastIp())||(sendPacket==null))
                    {   iCounter=0;
                        while ((strBoardCastIp=NetDevicesManage.GetBoardCastIp())==null)
                        {   if (NeedExit()) return;
                            iCounter++;
                            if (iCounter>5) break;

                            sleep(HEART_INTERVAL);
                            MyLog.i( "Wait Get GetBoardCastIp");
                        }
                        if (strBoardCastIp==null) {
                            strBoardCastIp=new ArrayList<>();
                            strBoardCastIp.add(Define.AllNetBroadcaseIP);
                        }
                    }
//                    MyLog.i("UDP_PORT="+UDP_PORT+": "+strSendString+ " Board: " +strBoardCastIp);
                    for (String ip : strBoardCastIp) {
//                        MyLog.i(ip);
                        sendPacket = new DatagramPacket(sendDataBuffer, sendDataBuffer.length, InetAddress.getByName(ip), UDP_PORT);
                        udpSendSocket.send(sendPacket);
                    }
                }
            }catch(Exception e){
                if (false) // 180720a
                if (NeedExit()==false)
                    MyLog.i(Thread.currentThread().getStackTrace()[2].getFileName() + "-->"
                            +   "Function: " +Thread.currentThread().getStackTrace()[2].getMethodName() + "-->"
                            +   "Line" +Thread.currentThread().getStackTrace()[2].getLineNumber() + ":\r\n"
                            +   "    Error:" + e.getMessage() + "\r\n\r\n"
                    );
            }finally {
                if (udpSendSocket!=null) {
                    udpSendSocket.close();
                    udpSendSocket=null;
                }
            }
            try {
                sleep(HEART_INTERVAL);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
        Exit(null);
    }

    public void Clients_UdpSendTime() {
        int iCounter=0;
//return;
        while(NeedExit()==false) {

            try {
                if (udpSendSocket == null){
                    udpSendSocket = new DatagramSocket(null);
                    udpSendSocket.setReuseAddress(true);
                    udpSendSocket.bind(new InetSocketAddress(UDP_PORT_SEND_SYNC_TIME));
                }

                while (!NeedExit()){
                    String str ="Time="+ Define.GetTimeMs();
                    byte sendDataBuffer[] = str.getBytes();
                    DatagramPacket sendPacket = new DatagramPacket(sendDataBuffer, sendDataBuffer.length, InetAddress.getByName(Define.AllNetBroadcaseIP), UDP_PORT_SEND_SYNC_TIME);
                    try {
                        sleep(HEART_INTERVAL); // sleep(1000); // 第一次时，先等待其他服务端口套接字线程准备好。
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    //iCounter=0;
                    udpSendSocket.send(sendPacket);
                    MyLog.i( str  );
                }
            }catch(Exception e){
                if (!NeedExit())
                    MyLog.i(Thread.currentThread().getStackTrace()[2].getFileName() + "-->"
                            +   "Function: " +Thread.currentThread().getStackTrace()[2].getMethodName() + "-->"
                            +   "Line" +Thread.currentThread().getStackTrace()[2].getLineNumber() + ":\r\n"
                            +   "    Error:" + e.getMessage() + "\r\n\r\n"
                    );
            }finally {
                if (udpSendSocket!=null) {
                    udpSendSocket.close();
                    udpSendSocket=null;
                }
                //iCounter++;
                if (iCounter>10)
                    break;
            }
        }
        Exit(null);
    }


    boolean bRequestRestart=false;
    String strExitIdence = null;
    public void Request_Exit(String strDeviceIdence) // 不能直接调用Exit，调用的线程会被阻塞,列表不被删除。
    {
       // 全局申请退出优先级高。
        if (strDeviceIdence == null) {
            bRequestRestart=true;
            return;
        }

        // 有其他身份待退出，等待退出结束。
        int iCounter = 0;
        while (strExitIdence != null) {
            try { sleep(100);}catch (Exception e) {}
            iCounter++;
            if (iCounter > 60) break;
        }

        MyLog.i("ClientsManage Request_Exit:" + strDeviceIdence);
        strExitIdence = strDeviceIdence;
    }

    Boolean bNeedExit=false;
	public  boolean NeedExit() { return bNeedExit; }

	public void ClientsExit()
    {    synchronized (this) {
            if (clientsTable.size() > 0) {
                for (int iOffset = clientsTable.size() - 1; iOffset >= 0; iOffset--) { // 从最后一个开始删除。
                    ClientManage clientManage = (ClientManage) clientsTable.get(iOffset);
                    if (clientManage == null) continue;
                    clientManage.Exit();
                    clientsTable.remove(iOffset);
                }
            }
        }
    }

    public void Exit(String clientID)
    {   if (NeedExit()) return;

        if (clientID==null) {
            bNeedExit = true;

            if (ledCardCommunication!=null) ledCardCommunication.Exit();
            //if (udpRece!=null)  udpRece.Exit();
        }

        synchronized (this) {
            if (clientsTable.size() > 0) {
                for (int iOffset = clientsTable.size() - 1; iOffset >= 0; iOffset--) { // 从最后一个开始删除。
                    ClientManage clientManage = (ClientManage) clientsTable.get(iOffset);

                    if (clientManage == null) continue;

                    if (clientManage.Client_IdenceJundge(clientID)) {
                        clientManage.Exit();
                        clientsTable.remove(iOffset);
                        //break; // 删完不直接退出，防止有重复的控制卡列表。
                    }
                }
            }
        }

        if (clientID == null) {
            try {
                clientsTable.clear();
                if (serverSocket_tcpCommunication != null) {
					    serverSocket_tcpCommunication.close();
					    serverSocket_tcpCommunication=null;
				    }
                if (serverSocket_SendFile != null) {
					    serverSocket_SendFile.close();
					    serverSocket_SendFile=null;
				    }
                if (udpSendSocket != null) {
					    udpSendSocket.close();
					    udpSendSocket=null;
				}
             }catch (Exception e) {
                if (NeedExit() == false)
                    MyLog.i(Thread.currentThread().getStackTrace()[2].getFileName() + "-->"
                            +   "Function: " +Thread.currentThread().getStackTrace()[2].getMethodName() + "-->"
                            +   "Line" +Thread.currentThread().getStackTrace()[2].getLineNumber() + ":\r\n"
                            +   "    Error:" + e.getMessage() + "\r\n\r\n"
                    );
            }
            MyLog.i(" "+ Thread.currentThread().getStackTrace()[2].getFileName() + "-->"
                    +   "Function: " +Thread.currentThread().getStackTrace()[2].getMethodName() + "-->"
                    +   "Line" +Thread.currentThread().getStackTrace()[2].getLineNumber() + ":\r\n"
            );
            ms.AppRestart();
		 }

        //if (clientsTable.size() == 0) Activity.AppRestart();


        MyLog.i(" "+ Thread.currentThread().getStackTrace()[2].getFileName() + "-->"
                +   "Function: " +Thread.currentThread().getStackTrace()[2].getMethodName() + "-->"
                +   "Line" +Thread.currentThread().getStackTrace()[2].getLineNumber() + ":\r\n"
        );
    }
}