using IOB_UT_NEXT;
using MTConnect.Clients;
using MTConnect.Observations;
using MTConnect.Streams;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace IOB_WIN_MTC
{
    public partial class MainForm : Form
    {
        #region Public Constructors

        public MainForm()
        {
            InitializeComponent();
            prbClient = new MTConnectHttpProbeClient(baseUrl);
            uiTimer.Interval = 1000;
            uiTimer.Elapsed += UiTimer_Elapsed;
            uiTimer.Start();
        }

        private void UiTimer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
        {
            doLog("...");
        }

        private System.Timers.Timer uiTimer = new System.Timers.Timer();

        #endregion Public Constructors

        #region Public Properties

        /// <summary>
        /// Logwatcher (in modalità "accodamento in testa" ultimi messaggi...)
        /// </summary>
        public string logWatcher
        {
            get
            {
                return lblOut.Text;
            }
            set
            {
                try
                {
                    // aggiungo in testa la NUOVA stringa (eventualmente multiline)
                    logWatchString.Enqueue(value);
                    // se supero limite --> trim!
                    string sTemp = "";
                    while (logWatchString.Count > 50)
                    {
                        logWatchString.TryDequeue(out sTemp);
                    }
                    DateTime adesso = DateTime.Now;
                    if (logWatchWriteVeto < adesso)
                    {
                        this.UIThread(delegate
                        {
                            lblOut.Text = string.Join(Environment.NewLine, logWatchString);
                            lblOut.Refresh();
                        });
                        logWatchWriteVeto = adesso.AddMilliseconds(delayShowLogMs);
                    }
                }
                catch (Exception exc)
                {
                }
            }
        }
        /// <summary>
        /// Veto a NUOVE scritture in logWatch...
        /// </summary>
        private DateTime logWatchWriteVeto { get; set; } = DateTime.Now;

        protected int delayShowLogMs = 500;

        #endregion Public Properties

        #region Protected Fields

        protected string baseUrl = "192.168.1.27:5000";

        #endregion Protected Fields

        #region Protected Properties

        protected MTConnectHttpClient client { get; set; }

        /// <summary>
        /// Lista String da mostrare quale WatchLog corrente...
        /// </summary>
        protected ConcurrentQueue<string> logWatchString { get; set; } = new ConcurrentQueue<string>();

        protected MTConnectHttpProbeClient prbClient { get; set; } = new MTConnectHttpProbeClient("");

        #endregion Protected Properties

        #region Private Fields

        private string sep = "---------------------";

        #endregion Private Fields

        #region Private Methods

        private void button1_Click(object sender, EventArgs e)
        {
            // inizio ciclo
            doLog(sep);
            doLog("Rest Client test application");
            doLog(sep);

            doPreliminaryProbe();
            doLog();
            doLog(sep);
            doLog();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            client = new MTConnectHttpClient(baseUrl);
            // sample interval
            client.Interval = 500;
            // timeout x richieste
            client.Timeout = 4000;
            // timeout riconnessione
            client.ReconnectionInterval = 5000;

            // aggancio eventi
            client.ClientStarted += Client_ClientStarted;
            client.ClientStopped += Client_ClientStopped;
            client.ConnectionError += Client_ConnectionError;
            client.ProbeReceived += Client_ProbeReceived;
            client.AssetsReceived += Client_AssetsReceived;
            client.CurrentReceived += Client_CurrentReceived;
            client.SampleReceived += Client_SampleReceived;
            // conviene usare sample x avere la stessa cosa ma con altre info...
            //client.ObservationReceived += Client_ObservationReceived;

            // vero avvio
            client.Start();
            Task.Delay(5000);
            doLog("Request start...");
        }

        private void button3_Click(object sender, EventArgs e)
        {
            client.Stop();
        }

        private void Client_AssetsReceived(object sender, MTConnect.Assets.IAssetsResponseDocument document)
        {
            doLog(sep);
            doLog("ASSET");
            doLog(sep);
            foreach (var asset in document.Assets)
            {
                // Print AssetId to the Console
                doLog($"Asset: {asset.AssetId}");
            }
            doLog(sep);
            doLog();
        }

        private void Client_ClientStarted(object sender, EventArgs e)
        {
            doLog(sep);
            doLog($"Client Started! | {e}");
            doLog(sep);
            doLog("Press ESC to exit");
        }

        private void Client_ClientStopped(object sender, EventArgs e)
        {
            doLog(sep);
            doLog($"Client Stopped! | {e}");
            doLog(sep);
            doLog("Press ESC to exit");
        }

        private void Client_ConnectionError(object sender, Exception exc)
        {
            doLog(sep);
            doLog($"CONNECTION ERROR returned!");
            doLog($"{exc}");
            doLog(sep);
            doLog("Press ESC to exit");
        }

        private void Client_CurrentReceived(object sender, MTConnect.Streams.IStreamsResponseDocument document)
        {
            doLog(sep);
            doLog("CURRENT");
            doLog(sep);
            foreach (var deviceStream in document.Streams)
            {
                // DeviceStream
                doLog($"Stream: {deviceStream.Name}");

                // Component Streams
                foreach (var componentStream in deviceStream.ComponentStreams)
                {
                    processData(componentStream);
                }
            }
            doLog(sep);
            doLog();
        }

        private void Client_ObservationReceived(object sender, IObservation observ)
        {
            doLog(sep);
            doLog("OBSERVATION");
            doLog(sep);
            processObservation(observ);
        }

        private void Client_ProbeReceived(object sender, MTConnect.Devices.IDevicesResponseDocument document)
        {
            doLog(sep);
            doLog("PROBE returned");
            doLog(sep);
            foreach (var device in document.Devices)
            {
                // Device
                doLog($"DEV: {device.Id}");

                // All DataItems (traverse the entire Device model)
                if (device.DataItems.Count() > 0)
                {
                    foreach (var dataItem in device.GetDataItems())
                    {
                        doLog($" DItm | {dataItem.IdPath}");
                    }
                }

                // All Components (traverse the entire Device model)
                if (device.Components.Count() > 0)
                {
                    foreach (var component in device.GetComponents())
                    {
                        doLog($" Comp | {component.IdPath}");
                    }
                }

                // All Compositions (traverse the entire Device model)
                if (device.Compositions.Count() > 0)
                {
                    foreach (var composition in device.GetCompositions())
                    {
                        doLog($" Cpst | {composition.IdPath}");
                    }
                }
            }
            doLog(sep);
            doLog();
        }

        private void Client_SampleReceived(object sender, MTConnect.Streams.IStreamsResponseDocument document)
        {
            doLog(sep);
            doLog("SAMPLE");
            doLog(sep);
            foreach (var deviceStream in document.Streams)
            {
                // DeviceStream
                doLog($"Stream: {deviceStream.Name}");
                // Component Streams
                foreach (var componentStream in deviceStream.ComponentStreams)
                {
                    processData(componentStream);
                }
            }
            doLog(sep);
            doLog();
        }

        private void doLog(string msg = "")
        {
            string dtMessage = $"{DateTime.Now:HH:mm:ss.fff} | {msg}";
            logWatcher = dtMessage;
        }

        private void doPreliminaryProbe()
        {
            doLog();
            doLog("Call Probe");

            prbClient.Timeout = 20000;
            var prbDoc = prbClient.Get();
            if (prbDoc == null)
            {
                doLog("Preliminari Probe | No answer, continue...");
            }
            else
            {
                doLog(sep);
                doLog("Preliminary PROBE");
                doLog(sep);
                foreach (var device in prbDoc.Devices)
                {
                    // Device
                    doLog($"DEV: {device.Id}");

                    // All DataItems (traverse the entire Device model)
                    if (device.DataItems.Count() > 0)
                    {
                        foreach (var dataItem in device.GetDataItems())
                        {
                            doLog($" DItm | {dataItem.IdPath}");
                        }
                    }

                    // All Components (traverse the entire Device model)
                    if (device.Components.Count() > 0)
                    {
                        foreach (var component in device.GetComponents())
                        {
                            doLog($" Comp | {component.IdPath}");
                        }
                    }

                    // All Compositions (traverse the entire Device model)
                    if (device.Compositions.Count() > 0)
                    {
                        foreach (var composition in device.GetCompositions())
                        {
                            doLog($" Cpst | {composition.IdPath}");
                        }
                    }
                }
                doLog(sep);
                doLog();
            }
        }

        private void processData(IComponentStream dataStream)
        {
            doLog($"Component {dataStream.Name} -->");
            // DataItems (Samples, Events, and Conditions)
            foreach (var observation in dataStream.Observations)
            {
                processObservation(observation);
            }
        }

        private void processObservation(IObservation observation)
        {
            string sMsg = $" - {observation.DataItemId} | {observation.Category}";
            //switch (observation.Category)
            //{
            //    case Devices.DataItemCategory.CONDITION:
            //        break;

            //    case Devices.DataItemCategory.EVENT:
            //        break;

            //    case Devices.DataItemCategory.SAMPLE:
            //        break;

            //    default:
            //        break;
            //}
            if (observation.Values != null && observation.Values.Count() > 0)
            {
                foreach (var item in observation.Values)
                {
                    sMsg += $" | {item.Key}: {item.Value}";
                }
            }
            doLog(sMsg);
        }

        #endregion Private Methods
    }
}