﻿using System.IO;
using System.Security.AccessControl;
using System.Web.Script.Serialization;
using WebSocket4Net;
using Clopduino.TrayNotifier.Data.Managers.Events;
using Clopduino.TrayNotifier.Data.Transfers;
using Clopduino.TrayNotifier.Data.Transfers.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ErrorEventArgs = SuperSocket.ClientEngine.ErrorEventArgs;

namespace Clopduino.TrayNotifier.Data.Managers
{
    public class ClopduinoManager
    {
        #region Singleton       
        private WebSocket websocket;

        public void Open()
        {
            if (websocket.State == WebSocketState.Closed || websocket.State == WebSocketState.None)
            {
                websocket.Open();
            }
            else if (websocket.State == WebSocketState.Connecting || websocket.State == WebSocketState.Closing)
            {
                resetSocket();
            }
        }

        public void Close()
        {
            if (websocket.State == WebSocketState.Closed || websocket.State == WebSocketState.None)
            {
                if (Closed != null) Closed(this, null);
            }
            else if (websocket.State == WebSocketState.Connecting || websocket.State == WebSocketState.Closing)
            {
                resetSocket();
                if (Closed != null) Closed(this, null);
            }
            else
            {
                websocket.Close();
            }
        }

        public event EventHandler Opened;
        public event EventHandler Closed;
        public event EventHandler Updated;
        public event ErrorEventHandler Error;

        public string Uri { get; set; }
        public string Protocol { get; set; }
        
        public ClopduinoManager(string uri, string protocol)
        {
            Uri = uri;
            Protocol = protocol;
            resetSocket();
        }

        void resetSocket()
        {
            websocket = new WebSocket(Uri, Protocol);

            websocket.Closed += websocket_Closed;
            websocket.Opened += websocket_Opened;
            websocket.MessageReceived += websocket_MessageReceived;
            websocket.Error += websocket_Error;

            ToiletTransfer toilet1 = new ToiletTransfer()
            {
                Name = "Męska",
                Type = ToiletType.Male,
                Status = ToiletStatus.IsDisconnected
            };

            ToiletTransfer toilet2 = new ToiletTransfer()
            {
                Name = "Damska",
                Type = ToiletType.Female,
                Status = ToiletStatus.IsDisconnected
            };
            ToiletList = new List<ToiletTransfer>();
            ToiletList.Add(toilet1);
            ToiletList.Add(toilet2);
        }


        void websocket_Error(object sender, SuperSocket.ClientEngine.ErrorEventArgs e)
        {
            resetSocket();
            OnError(new System.IO.ErrorEventArgs(e.Exception));
        }

        void websocket_MessageReceived(object sender, MessageReceivedEventArgs e)
        {
            var javaScriptSerializer = new JavaScriptSerializer();

            try
            {
                var toilets = javaScriptSerializer.Deserialize<Toilets>(e.Message);

                if (toilets == null) return;

                ToiletList[0].Update(toilets.Men);
                ToiletList[1].Update(toilets.Women);

                if (Updated != null) Updated(this, e);
            }
            catch (Exception ex)
            {
                OnError(new System.IO.ErrorEventArgs(ex));
            }
        }

        void websocket_Opened(object sender, EventArgs e)
        {
            if (Opened != null) Opened(this, e);
        }

        void websocket_Closed(object sender, EventArgs e)
        {
            if (Closed != null) Closed(this, e);            
        }

        private void OnError(System.IO.ErrorEventArgs e)
        {
            if (Error != null) Error(this, e);
        }
        #endregion

        public List<ToiletTransfer> ToiletList { get; private set; }

    }
}

