using System;
using System.Collections.Generic;
using System.Text;

using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;

/*Ping Test관련은 프로그램마다 구현 필요. override해놓지 않았음 귀찮앙 나중에 할랭ㅋ*/
class MySocket
{
    internal string hostIp;
    internal int portNum;
    internal WinformSocketServer.MySocketForm form;

    public void InitForm(WinformSocketServer.MySocketForm form)
    {
        Console.WriteLine(form.ToString());

        this.form = form; 
        this.form.onReceive = this.form.Receive;
    }
}

class SocketClient : MySocket
{

    private string rxMsg;
    TcpClient clientSocket = null;
    private bool isClient = false;//Client Connected State

    public SocketClient()//생성자
    {
        Console.WriteLine("Socket Client Construct");
    }
    ~SocketClient()//소멸자
    {

    }

    public bool Connect(string hostIp, int portNum)
    {
        if (hostIp == null)//호스트아이피 입력 안 하면 127.0.0.1
        {
            hostIp = "127.0.0.1";
            this.portNum = portNum;
        }
        else
        {
            this.hostIp = hostIp;
            this.portNum = portNum;
        }
        try
        {
            Console.WriteLine("Connect Host : {0} : {1}", hostIp, portNum);
            clientSocket = new TcpClient(hostIp, portNum);

            Thread tClientReceive = new Thread(new ParameterizedThreadStart(Receive));
            tClientReceive.Start(this.clientSocket);
            this.isClient = true;

            Console.WriteLine("Connection Success");
            return true;
        }
        catch
        {
            Console.WriteLine("Connection Err");
            return false;
        }
    }

    public void Disconnect()
    {
        try
        {
            this.clientSocket.Close();
            Console.WriteLine("Disconnect");
            this.isClient = false;
        }
        catch
        {
            Console.WriteLine("Failed Disconnect Err");
        }
    }

    private void Receive(object tcpClient)
    {
        TcpClient tcp = tcpClient as TcpClient;

        Stream stream = tcp.GetStream();
        int dataLength;
        byte[] bytes = new byte[1024];

        while (isClient)
        {
            try
            {
                if ((dataLength = stream.Read(bytes, 0, bytes.Length)) != 0)
                {
                    this.rxMsg = Encoding.Default.GetString(bytes, 0, dataLength);/*rxMsg*/
                    Console.WriteLine("receMsg : {0}", this.rxMsg);
                    /*WinForm Receive Start*/
                    try
                    {
                        if (this.form != null)
                        {
                            this.form.onReceive(this.rxMsg);
                        }
                    }
                    catch
                    {

                    }
                    /*WinfForm Receive End*/
                }
                else
                {
                    break;
                }
            }
            catch
            {
                break;
            }
        }
    }

    public void SendMessage(string data)
    {
        byte[] txMsg = Encoding.Default.GetBytes(data);
        try
        {
            Stream stream = this.clientSocket.GetStream();
            stream.Write(txMsg, 0, data.Length);/*txMsg*/
        }
        catch (SocketException socketErr)
        {
                Console.WriteLine("socketErr : {0}", socketErr.ErrorCode);
        }
        catch (Exception err)
        {
            if(err.HResult == -2146232800)
            {
                Console.WriteLine("Server Shut Down");
            }
            else
            {
                Console.WriteLine("err : {0}", err);
            }
        }
    }

    public bool GetState()
    {
        if (this.isClient)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

class SocketServer : MySocket
{
    TcpListener server = null;//서버
    TcpClient clientSocket = null;//소켓
    private int clientCount;//사용자 수
    private Thread tAcceptClient;
    private bool isServer = false;//Server Ready State
    private string rxMsg;

    private Dictionary<string, TcpClient> dicClientList = new Dictionary<string, TcpClient>();//클라이언트 모음 딕셔너리

    public SocketServer()//생성자
    {
        Console.WriteLine("Socket Server Construct");
    }
    ~SocketServer()//소멸자
    {

    }

    public bool StartServer(string hostIp, int portNum)
    {
        if(hostIp == null)//호스트아이피 입력 안 하면 127.0.0.1
        {
            this.hostIp = "127.0.0.1";
            this.portNum = portNum;
        }
        else
        {
            this.hostIp = hostIp;
            this.portNum = portNum;
        }
        try
        {
            this.server = new TcpListener(IPAddress.Parse(this.hostIp), this.portNum);
            this.clientSocket = default(TcpClient);
            this.server.Start();
            Console.WriteLine("Start Server, {0} : {1}", IPAddress.Parse(this.hostIp), this.portNum);

            this.isServer = true;

            this.tAcceptClient = new Thread(new ThreadStart(AcceptClient));
            this.tAcceptClient.Start();

            return true;
        }
        catch
        {
            Console.WriteLine("Failed to Start Server");

            return false;
        }
    }

    private void AcceptClient()
    {
        while (this.isServer)
        {
            try
            {
                this.clientCount++;
                this.clientSocket = server.AcceptTcpClient();

                var clientIp = clientSocket.Client.RemoteEndPoint;
                Thread tServerReceive = new Thread(new ParameterizedThreadStart(this.Receive));
                tServerReceive.Start(this.clientSocket);

                dicClientList.Add(clientIp.ToString(), clientSocket); // cleint 리스트에 추가<ip, handle>

                Console.WriteLine("Accpet Client, {0}", clientIp.ToString());
            }
            catch (SocketException socketErr)
            {
                if (socketErr.ErrorCode == 10004)
                {
                    Console.WriteLine("tSocket Server Close");
                }
                else
                {
                    Console.WriteLine("socketErr : {0}", socketErr);
                }

            }
            catch (Exception err)
            {
                Console.WriteLine("err : {0}", err);
            }
        }
    }

    public void CloseServer()
    {
        Console.WriteLine("Socket Server Close");
        this.isServer = false;
        this.server.Stop();
    }

    private void Receive(object tcpClient)
    {
        TcpClient tcp = tcpClient as TcpClient;

        Stream stream = tcp.GetStream();
        int dataLength;
        byte[] bytes = new byte[1024];

        while ((dataLength = stream.Read(bytes, 0, bytes.Length)) != 0)
        {
            this.rxMsg = Encoding.Default.GetString(bytes, 0, dataLength);/*rxMsg*/
            Console.WriteLine("receMsg : {0}", rxMsg);

            /*WinForm Receive Start*/
            try
            {
                if (this.form != null)
                {
                    this.form.onReceive(this.rxMsg);
                }
            }
            catch
            {

            }
            /*WinfForm Receive End*/
        }
    }
    public void SendMessageAll(string data)
    {
        byte[] txMsg = Encoding.Default.GetBytes(data);
        foreach (var pair in dicClientList)
        {
            try
            {
                Stream stream = pair.Value.GetStream();
                stream.Write(txMsg, 0, data.Length);/*txMsg*/
            }
            catch
            {
                Console.WriteLine("send err");
            }
        }
    }
    public bool GetState()
    {
        if (this.isServer)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}