// inspired and modified from https://gist.github.com/danielbierwirth/0636650b005834204cb19ef5ae6ccedb
// This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. 
// To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/ 
// or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System;

//version 1

public class DataConnectorTcpClient : MonoBehaviour
{
    public string serverIP = "127.0.0.1";
    public int serverPort = 8052;
    
    private NetworkStream stream;
    private Thread clientReceiveThread;
    private DataConnector dataConnector;
    private TcpClient socketConnection;
    public bool ShowLogMessages;

    void Start()
    {
        dataConnector = GetComponent<DataConnector>();
        ConnectToServer();
    }

    void ConnectToServer()
    {
        try
        {
            // Start a separate thread for receiving data to avoid blocking the main thread
            clientReceiveThread = new Thread(new ThreadStart(ListenForData));
            clientReceiveThread.IsBackground = true; // Allow thread to terminate with application
            clientReceiveThread.Start();
        }
        catch (SocketException socketException)
        {
            Debug.LogError("Socket exception: " + socketException);
        }
    }

    private void Update()
    {
        if (socketConnection.Connected == false)
        {
            dataConnector.ClearCaches();
            return;
        }


        if (dataConnector.gazeData.Count > 0)
        {
            foreach (var v in dataConnector.gazeData)
            {
                SendData(v.ToString());
            }
        }
        if (dataConnector.fixationData.Count > 0)
        {
            foreach (var v in dataConnector.fixationData)
            {
                SendData(v.ToString());
            }
        }
        if (dataConnector.customEventData.Count > 0)
        {
            foreach (var v in dataConnector.customEventData)
            {
                SendData(v.ToString());
            }
        }
        if (dataConnector.dynamicData.Count > 0)
        {
            foreach (var v in dataConnector.dynamicData)
            {
                SendData(v.ToString());
            }
        }
        if (dataConnector.sensorData.Count > 0)
        {
            foreach (var v in dataConnector.sensorData)
            {
                SendData(v.ToString());
            }
        }
        if (dataConnector.boundaryData.Count > 0)
        {
            foreach (var v in dataConnector.boundaryData)
            {
                SendData(v.ToString());
            }
        }
        dataConnector.ClearCaches();
    }

    //send data to server
    public void SendData(string serializedData)
    {
        if (socketConnection == null)
        {
            return;
        }
        try
        {
            // Get a stream object for writing. 			
            NetworkStream stream = socketConnection.GetStream();
            if (stream.CanWrite)
            {
                string clientMessage = "This is a message from one of your clients.";
                // Convert string message to byte array.                 
                byte[] clientMessageAsByteArray = Encoding.ASCII.GetBytes(clientMessage);
                // Write byte array to socketConnection stream.                 
                stream.Write(clientMessageAsByteArray, 0, clientMessageAsByteArray.Length);
                if (ShowLogMessages)
                {
                    Debug.Log("Client sent " + serializedData);
                }
            }
        }
        catch (SocketException socketException)
        {
            Debug.Log("Socket exception: " + socketException);
        }
    }
    
    // listen to incoming data from the server
    private void ListenForData()
    {
        try
        {
            socketConnection = new TcpClient(serverIP, serverPort);
            Byte[] bytes = new Byte[1024];
            while (true)
            {
                // Get a stream object for reading 				
                using (NetworkStream stream = socketConnection.GetStream())
                {
                    int length;
                    // Read incomming stream into byte arrary. 					
                    while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        var incommingData = new byte[length];
                        Array.Copy(bytes, 0, incommingData, 0, length);
                        // Convert byte array to string message. 						
                        string serverMessage = Encoding.ASCII.GetString(incommingData);
                        if (ShowLogMessages)
                        {
                            Debug.Log("Client recieved message " + serverMessage);
                        }
                    }
                }
            }
        }
        catch (SocketException socketException)
        {
            Debug.Log("Socket exception: " + socketException);
        }
    }

    void OnDisable()
    {
        Disconnect();
    }

    void Disconnect()
    {
        if (socketConnection != null)
        {
            socketConnection.Close();
            socketConnection = null;
        }
        if (stream != null)
        {
            stream.Close();
            stream = null;
        }
        if (clientReceiveThread != null && clientReceiveThread.IsAlive)
        {
            clientReceiveThread.Abort(); // Terminate the receive thread
        }
        Debug.Log("Disconnected from server");
    }
}
