using Opc.Ua.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace IMCS_CCS.Utils.DeviceProtocol
{
    public abstract class AProtocolBase
    {
        public abstract void ConnectAsync();
        public abstract void CloseConnect();
        public abstract object ReadData(int dataType, object dataParameter);
        public abstract bool WriteData(object obj);
        public abstract event MonitoredItemNotificationEventHandler OpcUaAlarmNotificationHandle;
        public string UserName { get; set; }
        public string UserPassword { get; set; }
        public abstract bool IsConnected { get; set; }
        private TaskCompletionSource<bool> mConnectTaskSource;
        private TaskCompletionSource<bool> mCloseTaskSource;

        public TaskCompletionSource<bool> MConnectTaskSource
        {
            get => mConnectTaskSource;
            set => mConnectTaskSource = value;
        }

        public TaskCompletionSource<bool> MCloseTaskSource
        {
            get => mCloseTaskSource;
            set => mCloseTaskSource = value;
        }

        public string IpEndPort { get; set; }

        public bool FinishConnectTask(bool result)
        {
            TaskCompletionSource<bool> connectTaskSource = this.mConnectTaskSource;
            if (connectTaskSource == null || Interlocked.CompareExchange<TaskCompletionSource<bool>>(ref this.mConnectTaskSource, (TaskCompletionSource<bool>)null, connectTaskSource) != connectTaskSource)
                return false;
            connectTaskSource.SetResult(result);
            return true;
        }

        public bool FinishCloseTask(bool result)
        {
            TaskCompletionSource<bool> closeTaskSource = this.mCloseTaskSource;
            if (closeTaskSource == null || Interlocked.CompareExchange<TaskCompletionSource<bool>>(ref this.mCloseTaskSource, (TaskCompletionSource<bool>)null, closeTaskSource) != closeTaskSource)
                return false;
            closeTaskSource.SetResult(result);
            return true;
        }

        public event EventHandler Connected;
        public event EventHandler Error;
        public event EventHandler Closed;

        protected virtual void OnConnected()
        {
            Connected?.Invoke(this, EventArgs.Empty);
        }

        protected virtual void OnErrorProtocol(ErrorEventArgs ags)
        {
            Error?.Invoke(this, ags);
        }


        protected virtual void OnClosed()
        {
            Closed?.Invoke(this, EventArgs.Empty);
        }
    }

    public class ErrorEventArgs : EventArgs
    {
        public Exception Exception { get; private set; }

        public ErrorEventArgs(Exception exception)
        {
            this.Exception = exception;
        }
    }
}
