using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Wayne.FDCPOSLibrary;
using WayneChina_IcCardReader_SinoChem.MessageEntity;

namespace WayneChina_IcCardReader_SinoChem
{
    public class TcpHandler : IDeviceHandler<byte[], IcCardReaderMessageBase>
    {
        #region Logger

        static NLog.Logger logger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("PumpHandler");

        #endregion

        public Guid Id => Guid.NewGuid();

        public IContext<byte[], IcCardReaderMessageBase> CardReaderContext { get; set; }

        public event EventHandler<CardReaderMessageEventArgs> OnCardReaderMessageReceived;

        #region Raw config string

        private string cardReaderConfig;

        #endregion

        #region Card reader config list

        private List<CardReaderConfig> readerList;

        #endregion

        #region Constructor

        public TcpHandler(int id, string cardReaderConfig)
        {
            DispenserId = id;
            this.cardReaderConfig = cardReaderConfig;

            readerList = ParseCardReaderConfig(cardReaderConfig);
        }

        private List<CardReaderConfig> ParseCardReaderConfig(string config)
        {
            var xml = System.Net.WebUtility.HtmlDecode(config);

            var readers = XDocument.Parse(xml)
                .Element("CardReaders")
                .Elements()
                .Select(FromXElement<CardReaderConfig>)
                .ToList();

            return readers;
        }

        #endregion

        public int DispenserId { get; }

        public void Init(IContext<byte[], IcCardReaderMessageBase> context)
        {
            CardReaderContext = context;
        }

        public void Write(IcCardReaderMessageBase message)
        {
            CardReaderContext.Outgoing.Write(message);
        }

        public Task Process(IContext<byte[], IcCardReaderMessageBase> context)
        {
            var sourcePumpId = GetPumpIdBySourceAddress(context.Incoming.Message.SourceAddress); 
            OnCardReaderMessageReceived?.Invoke(this, new CardReaderMessageEventArgs(sourcePumpId, context.Incoming.Message));
            return Task.CompletedTask;
        }

        /// <summary>
        /// Get all supported pumps (Fueling Points) of this handler.
        /// </summary>
        public List<int> SupportedNozzles
        {
            get
            {
                return readerList.Select(r => r.PumpId).ToList();
            }
        }

        /// <summary>
        /// Get the card reader address of the pump (fueling point).
        /// </summary>
        /// <param name="id">The fueling point id.</param>
        /// <returns>Source address of the reader.</returns>
        public byte GetAddressForNozzleId(int id)
        {
            if (SupportedNozzles.Contains(id))
            {
                return (byte)readerList.FirstOrDefault(r => r.PumpId == id).Address;
            }

            return 0x0F;
        }

        public byte GetPumpIdBySourceAddress(byte srcAddr)
        {
            var readerConfig = readerList.FirstOrDefault(r => r.Address == srcAddr);
            if (readerConfig != null)
                return (byte)readerConfig.PumpId;

            return 0x0F;
        }

        #region Helper methods

        private T FromXElement<T>(XElement element) where T : class, new()
        {
            T value = new T();

            foreach (var attr in element.Attributes())
            {
                var prop = typeof(T).GetProperty(attr.Name.LocalName);
                value.SetPropertyValue(prop.Name, attr.Value);
            }

            return value;
        }

        #endregion
    }
}