using System;
using System.Xml;

namespace Wayne.ForecourtControl
{
    /// <summary>
    /// Fuelling data, contains serializable data from a fuelling.
    /// </summary>
    public sealed class FuellingData
    {
        #region Fields

        #endregion

        #region Construction

        /// <summary>
        /// Initializes a new fuellingdata object when applying discount.
        /// </summary>
        /// <param name="fuellingSequenceNumber"></param>
        /// <param name="nozzleId"></param>
        /// <param name="pumpId"></param>
        /// <param name="fuellingType"></param>
        /// <param name="quantity"></param>
        /// <param name="amount"></param>
        /// <param name="presetValue"></param>
        /// <param name="presetType"></param>
        /// <param name="price"></param>
        /// <param name="completionDateTiem"></param>
        /// <param name="completionReason"></param>
        /// <param name="fuelGrade"></param>
        /// <param name="priceGroup"></param>
        /// <param name="fuelPeriodId"></param>
        /// <param name="authorizationId"></param>
        /// <param name="reservingDeviceId"></param>
        /// <param name="priceRevision"></param>
        /// <param name="signatureReceiptLines"></param>
        public FuellingData(int fuellingSequenceNumber,
            int nozzleId,
            int pumpId,
            FuellingType fuellingType,
            decimal quantity,
            decimal amount,
            decimal presetValue,
            PresetType presetType,
            decimal price,
            DateTime completionDateTiem,
            int completionReason,
            int fuelGrade,
            PriceGroup priceGroup,
            int fuelPeriodId,
            long authorizationId,
            byte reservingDeviceId,
            byte priceRevision,
            string signatureReceiptLines)
            : this(fuellingSequenceNumber, nozzleId, pumpId, fuellingType, quantity, amount, presetValue, presetType, price, completionDateTiem, completionReason, fuelGrade, priceGroup, fuelPeriodId, authorizationId, reservingDeviceId, priceRevision, signatureReceiptLines, signatureReceiptLines)
        {
        }
        /// <summary>
        /// Initializes a new fuellingdata object when applying discount.
        /// </summary>
        /// <param name="fuellingSequenceNumber"></param>
        /// <param name="nozzleId"></param>
        /// <param name="pumpId"></param>
        /// <param name="fuellingType"></param>
        /// <param name="quantity"></param>
        /// <param name="amount"></param>
        /// <param name="presetValue"></param>
        /// <param name="presetType"></param>
        /// <param name="price"></param>
        /// <param name="completionDateTiem"></param>
        /// <param name="completionReason"></param>
        /// <param name="fuelGrade"></param>
        /// <param name="priceGroup"></param>
        /// <param name="fuelPeriodId"></param>
        /// <param name="authorizationId"></param>
        /// <param name="reservingDeviceId"></param>
        /// <param name="priceRevision"></param>
        /// <param name="signatureReceiptLines"></param>
        /// <param name="signatureReceiptLinesWide"></param>
        public FuellingData(int fuellingSequenceNumber,
            int nozzleId,
            int pumpId,
            FuellingType fuellingType,
            decimal quantity,
            decimal amount,
            decimal presetValue,
            PresetType presetType,
            decimal price,
            DateTime completionDateTiem,
            int completionReason,
            int fuelGrade,
            PriceGroup priceGroup,
            int fuelPeriodId,
            long authorizationId,
            byte reservingDeviceId,
            byte priceRevision,
            string signatureReceiptLines,
            string signatureReceiptLinesWide)
        {
            FuellingSequenceNumber = fuellingSequenceNumber;
            NozzleId = nozzleId;
            PumpId = pumpId;
            this.Type = fuellingType;
            Quantity = quantity;
            Amount = amount;
            PresetValue = presetValue;
            PresetType = presetType;
            Price = price;
            CompletionDateTime = completionDateTiem;
            CompletionReason = completionReason;
            FuelGrade = fuelGrade;
            PriceGroup = priceGroup;
            FuelPeriodId = fuelPeriodId;
            AuthorizationId = authorizationId;
            ReservingDeviceId = reservingDeviceId;
            PriceRevision = priceRevision;
            SignedReceiptLines = signatureReceiptLines;
            SignedReceiptLinesWide = signatureReceiptLinesWide;
        }

        /// <summary>
        /// Used when deserializing.
        /// </summary>
        private FuellingData()
        {
        }

        /// <summary>
        /// Initializes a new fuellingdata object using a ForecourtControl IFuelling object.
        /// </summary>
        /// <param name="fuelling"></param>

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.ArgumentException.#ctor(System.String)")]
        public FuellingData(IFuelling fuelling)
        {
            if (fuelling == null)
                throw new ArgumentException("IFuelling can't be null");

            FuellingSequenceNumber = fuelling.FuellingSequenceNumber;

            if (fuelling.Pump != null)
            {
                PumpId = fuelling.Pump.Id;
            }

            if (fuelling.Nozzle != null)
            {
                NozzleId = fuelling.Nozzle.Id;
            }

            Type = fuelling.Type;
            Quantity = fuelling.Quantity;
            Amount = fuelling.Amount;
            PresetValue = fuelling.PresetValue;
            PresetType = fuelling.PresetType;
            Price = fuelling.Price;
            CompletionDateTime = fuelling.CompletionDateTime;
            CompletionReason = fuelling.CompletionReason;
            FuelGrade = fuelling.FuelGrade;
            if ((fuelling.PriceGroup >= PriceGroup.MinValue) && (fuelling.PriceGroup <= PriceGroup.MaxValue))
            {
                PriceGroup = fuelling.PriceGroup;
            }
            else
            {
                PriceGroup = 0;
            }

            FuelPeriodId = fuelling.FuelPeriodId;
            AuthorizationId = fuelling.AuthorizationId;
            ReservingDeviceId = fuelling.ReservingDeviceId;
            PriceRevision = fuelling.PriceRevision;
            SignedReceiptLines = fuelling.SignedReceiptLines;
            SignedReceiptLinesWide = fuelling.SignedReceiptLinesWide;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Fuelling sequence number is a unique number created for ever
        /// completed fuelling. Begins to count from 1 at system cold-start
        /// </summary>
        public int FuellingSequenceNumber { get; private set; }

        /// <summary>
        /// Id of the nozzle that performed the fuelling
        /// </summary>
        public int NozzleId { get; private set; }

        /// <summary>
        /// Id of the pump that performed the fuelling
        /// </summary>
        public int PumpId { get; private set; }

        /// <summary>
        /// Type of the fuelling
        /// </summary>
        public FuellingType Type { get; private set; }

        /// <summary>
        /// Fuelled quantity
        /// </summary>
        public decimal Quantity { get; private set; }

        /// <summary>
        /// Fuelled amount
        /// </summary>
        public decimal Amount { get; private set; }

        /// <summary>
        /// Preset amount or quantity
        /// </summary>
        public decimal PresetValue { get; private set; }

        /// <summary>
        /// Indicates if the preset value contains an amount or quantity.
        /// </summary>
        public PresetType PresetType { get; private set; }

        /// <summary>
        /// Unit price of the fuelling.
        /// </summary>
        public decimal Price { get; private set; }

        /// <summary>
        /// Date and time when the fuelling completed.
        /// </summary>
        public DateTime CompletionDateTime { get; private set; }

        /// <summary>
        /// A status code signaling why the fuelling stopped.
        /// </summary>
        public int CompletionReason { get; private set; }

        /// <summary>
        /// Fuelgrade that was used in the fuelling.
        /// </summary>
        public int FuelGrade { get; private set; }

        /// <summary>
        /// Price group that was used to calculate the price in the fuelling.
        /// </summary>
        public PriceGroup PriceGroup { get; private set; }

        /// <summary>
        /// Fuel period that the fuelling belongs to.
        /// </summary>
        public int FuelPeriodId { get; private set; }

        /// <summary>
        /// Authorization Id of the fuelling authorization.
        /// </summary>
        public long AuthorizationId { get; private set; }

        /// <summary>
        /// Device Id that was supplied in the reservation of the pump before authorization of the fuelling.
        /// </summary>
        public byte ReservingDeviceId { get; private set; }

        /// <summary>
        /// Internal Price revision number that was active when the fuelling took place.
        /// </summary>
        public byte PriceRevision { get; private set; }

        /// <summary>
        /// Application extension data.
        /// </summary>
        public string ApplicationExtension { get; set; }

        /// <summary>
        /// The MID Signed ReceiptLines.
        /// </summary>
        public string SignedReceiptLines { get; private set; }

        /// <summary>
        /// The MID Signed ReceiptLines for Wide printer.
        /// </summary>
        public string SignedReceiptLinesWide { get; private set; }

        #endregion


        /// <summary>
        /// Serializes the fuelling data.
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="prefix"></param>

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.ArgumentException.#ctor(System.String)")]
        public void WriteXml(XmlWriter writer, string prefix)
        {
            if (writer != null)
            {
                writer.WriteStartElement(prefix, "FuellingData", ForecourtControlXml.Ns);
                writer.WriteAttributeString("FuellingSequenceNumber", XmlConvert.ToString(FuellingSequenceNumber));
                writer.WriteElementString(prefix, "PumpId", ForecourtControlXml.Ns, XmlConvert.ToString(PumpId));
                writer.WriteElementString(prefix, "NozzleId", ForecourtControlXml.Ns, XmlConvert.ToString(NozzleId));
                writer.WriteElementString(prefix, "FuellingType", ForecourtControlXml.Ns, Type.ToString());
                writer.WriteElementString(prefix, "Amount", ForecourtControlXml.Ns, XmlConvert.ToString(Amount));
                writer.WriteElementString(prefix, "Quantity", ForecourtControlXml.Ns, XmlConvert.ToString(Quantity));
                writer.WriteElementString(prefix, "PresetValue", ForecourtControlXml.Ns, XmlConvert.ToString(PresetValue));
                writer.WriteElementString(prefix, "PresetType", ForecourtControlXml.Ns, PresetType.ToString());
                writer.WriteElementString(prefix, "Price", ForecourtControlXml.Ns, XmlConvert.ToString(Price));
                writer.WriteElementString(prefix, "CompletionDateTime", ForecourtControlXml.Ns, XmlConvert.ToString(CompletionDateTime, XmlDateTimeSerializationMode.Local));
                writer.WriteElementString(prefix, "CompletionReason", ForecourtControlXml.Ns, XmlConvert.ToString(CompletionReason));
                writer.WriteElementString(prefix, "FuelGrade", ForecourtControlXml.Ns, XmlConvert.ToString(FuelGrade));
                writer.WriteElementString(prefix, "PriceGroup", ForecourtControlXml.Ns, XmlConvert.ToString((int)PriceGroup));
                writer.WriteElementString(prefix, "FuelPeriodId", ForecourtControlXml.Ns, XmlConvert.ToString(FuelPeriodId));
                writer.WriteElementString(prefix, "AuthorizationId", ForecourtControlXml.Ns, XmlConvert.ToString(AuthorizationId));
                writer.WriteElementString(prefix, "ReservingDeviceId", ForecourtControlXml.Ns, XmlConvert.ToString(ReservingDeviceId));
                writer.WriteElementString(prefix, "PriceRevision", ForecourtControlXml.Ns, XmlConvert.ToString(PriceRevision));
                writer.WriteElementString(prefix, "SignedReceiptLines", ForecourtControlXml.Ns, SignedReceiptLines);
                writer.WriteElementString(prefix, "SignedReceiptLinesWide", ForecourtControlXml.Ns, SignedReceiptLinesWide);
                if (ApplicationExtension != null)
                    writer.WriteElementString(prefix, "ApplicationExtension", ForecourtControlXml.Ns, ApplicationExtension);

                writer.WriteEndElement();//FuellingData
            }
            else
                throw new ArgumentException("XmlWriter cannot be null");
        }

        /// <summary>
        /// Recreates a fuelling data object from an Xml element.
        /// </summary>
        /// <param name="fuellingDataElement"></param>
        /// <returns></returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.ArgumentException.#ctor(System.String)")]
        public static FuellingData Deserialize(XmlElement fuellingDataElement)
        {
            if (fuellingDataElement == null)
                throw new ArgumentException("Fuelling data element cannot be null");
            FuellingData data = new FuellingData();

            data.FuellingSequenceNumber = XmlConvert.ToInt32(fuellingDataElement.Attributes["FuellingSequenceNumber"].Value);

            data.PumpId = XmlConvert.ToInt32(fuellingDataElement["PumpId", ForecourtControlXml.Ns].InnerText);
            data.NozzleId = XmlConvert.ToInt32(fuellingDataElement["NozzleId", ForecourtControlXml.Ns].InnerText);
            data.Type = (FuellingType)Enum.Parse(typeof(FuellingType), fuellingDataElement["FuellingType", ForecourtControlXml.Ns].InnerText, false);
            data.Quantity = XmlConvert.ToDecimal(fuellingDataElement["Quantity", ForecourtControlXml.Ns].InnerText);
            data.Amount = XmlConvert.ToDecimal(fuellingDataElement["Amount", ForecourtControlXml.Ns].InnerText);
            data.PresetValue = XmlConvert.ToDecimal(fuellingDataElement["PresetValue", ForecourtControlXml.Ns].InnerText);
            data.PresetType = (PresetType)Enum.Parse(typeof(PresetType), fuellingDataElement["PresetType", ForecourtControlXml.Ns].InnerText, false);
            data.Price = XmlConvert.ToDecimal(fuellingDataElement["Price", ForecourtControlXml.Ns].InnerText);
            data.CompletionDateTime = XmlConvert.ToDateTime(fuellingDataElement["CompletionDateTime", ForecourtControlXml.Ns].InnerText, XmlDateTimeSerializationMode.Local);
            data.CompletionReason = XmlConvert.ToInt32(fuellingDataElement["CompletionReason", ForecourtControlXml.Ns].InnerText);
            data.FuelGrade = XmlConvert.ToInt32(fuellingDataElement["FuelGrade", ForecourtControlXml.Ns].InnerText);
            data.PriceGroup = XmlConvert.ToInt32(fuellingDataElement["PriceGroup", ForecourtControlXml.Ns].InnerText);
            data.FuelPeriodId = XmlConvert.ToInt32(fuellingDataElement["FuelPeriodId", ForecourtControlXml.Ns].InnerText);
            data.AuthorizationId = XmlConvert.ToInt32(fuellingDataElement["AuthorizationId", ForecourtControlXml.Ns].InnerText);
            XmlElement signedReceiptLinesElement = fuellingDataElement["SignedReceiptLines", ForecourtControlXml.Ns];
            if (signedReceiptLinesElement != null)
                data.SignedReceiptLines = signedReceiptLinesElement.InnerText;
            else
                data.SignedReceiptLines = "";
            XmlElement signedReceiptLinesWideElement = fuellingDataElement["SignedReceiptLinesWide", ForecourtControlXml.Ns];
            if (signedReceiptLinesWideElement != null)
                data.SignedReceiptLinesWide = signedReceiptLinesWideElement.InnerText;
            else
                data.SignedReceiptLinesWide = "";

            if (fuellingDataElement["ReservingDeviceId", ForecourtControlXml.Ns] != null)
                data.ReservingDeviceId = XmlConvert.ToByte(fuellingDataElement["ReservingDeviceId", ForecourtControlXml.Ns].InnerText);
            if (fuellingDataElement["PriceRevision", ForecourtControlXml.Ns] != null)
                data.PriceRevision = XmlConvert.ToByte(fuellingDataElement["PriceRevision", ForecourtControlXml.Ns].InnerText);
            if (fuellingDataElement["ApplicationExtension", ForecourtControlXml.Ns] != null)
                data.ApplicationExtension = fuellingDataElement["ApplicationExtension", ForecourtControlXml.Ns].InnerText;

            return data;
        }
    }
}