using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace arinc_1553_CSharpGUI
{
    using U64BIT = System.UInt64;
    using U32BIT = System.UInt32;
    using U16BIT = System.UInt16;
    using U8BIT = System.Byte;
    using S64BIT = System.Int64;
    using S32BIT = System.Int32;
    using S16BIT = System.Int16;
    using S8BIT = System.SByte;

    public struct EguParameterValueArinc429
    {
        public S32BIT s19Value;
        public U32BIT u19Value;
        public float fValue;
        public string strValue;
    }

    public class EguParameterArinc429
    {
        public string name;

        /* Data type for this parameter E.g. UNSIGNED INT */
        public string dataType;

        public string codedType;

        /* Location and length (in bits) of this parameter within the message data words */
        public uint length;
        public uint startBit;

        /* Scaling factor and offset for performing engineering unit conversion */
        public double scaleFactor;
        public double offset;

        public string units;

        /* Range to validate against when user inputs value to this engg parameter */
        public string rangeLow = "";
        public string rangeHigh = "";

        /* Reference to the message in which this Egu Parameter resides */
        public MsgArinc429 pMsg = new MsgArinc429();

        /* Current value of this parameter */
        public EguParameterValueArinc429 value = new EguParameterValueArinc429();

        /* Value edited by the user from the UI but not yet written to the data block of the message */
        public EguParameterValueArinc429 modifiedValue = new EguParameterValueArinc429();

        EguParameterValueArinc429 m_defaultValue = new EguParameterValueArinc429();
        string strDefaultValue;

        public ushort displayRowNoChan1, displayRowNoChan2;

        public bool isValid = false;

        /* Returns the parameter value as one or more 32-bit unsigned (WORD) values */
        public void GetRawValue(U32BIT[] buffer, List<CodedType> m_CodedTypes)
        {
            U32BIT uhwClearBits = 0;
            uhwClearBits = ~((uint)0x7FFFF << (int)length);
            uhwClearBits = (uhwClearBits << (int)startBit);

            if (dataType.ToUpper() == "UNSIGNED")
            {
                U32BIT uhwCount = (U32BIT)((value.u19Value - offset) / scaleFactor);
                uhwCount = uhwCount << (int)startBit;

                uhwCount = uhwCount & uhwClearBits;

                uhwClearBits = ~uhwClearBits;
                buffer[0] = (U32BIT)(buffer[0] & uhwClearBits);
                buffer[0] = (U32BIT)(buffer[0] | uhwCount);
            }
            else if (dataType.ToUpper() == "INTEGER")
            {
                U32BIT uhwCount = (U32BIT)((value.s19Value - offset) / scaleFactor);
                uhwCount = uhwCount << (int)startBit;

                uhwCount = uhwCount & uhwClearBits;

                uhwClearBits = ~uhwClearBits;
                buffer[0] = (U32BIT)(buffer[0] & uhwClearBits);
                buffer[0] = (U32BIT)(buffer[0] | uhwCount);
            }
            else if (dataType.ToUpper() == "REALIEEE754")
            {
                // store the val in buf
                double dlEngineeringData = (value.fValue - offset) / scaleFactor;

                U32BIT uhwCount = (U32BIT)dlEngineeringData;
                uhwCount = uhwCount << (int)startBit;

                uhwCount = uhwCount & uhwClearBits;

                uhwClearBits = ~uhwClearBits;
                buffer[0] = (U32BIT)(buffer[0] & uhwClearBits);
                buffer[0] = (U32BIT)(buffer[0] | uhwCount);
            }
            else if (dataType.ToUpper() == "CODED")
            {
                /* Get raw value corresponding to the coded string */
                buffer[0] = GetCodedStringRawValue(codedType, value.strValue, m_CodedTypes);

                /* position the raw value correctly by left shifting the raw value to the "startBit" */
                buffer[0] = (U32BIT)(buffer[0] << (int)startBit);
            }
            //else if (dataType == "BCD")
            //{
            //    /*        uhwWordValue = vrgst1553BBusInfo[ubyBus].pstMessageInfo[wMessageId].pstWord[wWordId].uhwModifiedWordValue;
            //            sscanf(szCellData,"%X",&uhwCount);
            //            uhwCount = uhwCount << vrgst1553BBusInfo[ubyBus].pstMessageInfo[wMessageId].pstWord[wWordId].pstParameter[wParaId].uhwStartBit;
            //            uhwClearBits = ~(0xFFFF << vrgst1553BBusInfo[ubyBus].pstMessageInfo[wMessageId].pstWord[wWordId].pstParameter[wParaId].ubyNoofBits);
            //            uhwClearBits = uhwClearBits << vrgst1553BBusInfo[ubyBus].pstMessageInfo[wMessageId].pstWord[wWordId].pstParameter[wParaId].uhwStartBit;

            //            uhwCount = uhwCount & uhwClearBits;

            //            uhwClearBits = ~uhwClearBits;
            //            uhwWordValue = uhwWordValue & uhwClearBits;

            //            uhwWordValue =  uhwWordValue | uhwCount;*/

            //    U32BIT uhwCount = (U32BIT)((value.u16Value - offset) / scaleFactor);
            //    uhwCount = uhwCount << (int)startBit;

            //    uhwCount = uhwCount & uhwClearBits;

            //    uhwClearBits = ~uhwClearBits;
            //    buffer[0] = (ushort) (buffer[0] & uhwClearBits);
            //    buffer[0] = (ushort) (buffer[0] | uhwCount);
            //}
        }

        U16BIT GetCodedStringRawValue(string codedTypeToMatch, string codedString, List<CodedType> m_CodedTypes)
        {
            U16BIT index = 0;
            foreach (CodedType ct in m_CodedTypes)
            {
                if (ct.type == codedTypeToMatch)
                {
                    foreach (string str in ct.values)
                    {
                        // We do a case insensitive comparison
                        if (str.ToUpper() == codedString.ToUpper())
                        {
                            return index;
                        }

                        index++;
                    }
                }
            }

            /* if we get here we did not find a match */
            return 0xFFFF;
        }

        public bool SetDefaultValue(string newStrDefValue, ref string errorString, List<CodedType> m_CodedTypes)
        {
            bool retValue = false;

            //if ((dataType == "UNSIGNED_REAL") || (dataType == "SIGNED_REAL"))
            if (dataType.ToUpper() == "REALIEEE754")
            {
                if (newStrDefValue.Length == 0)
                {
                    if (rangeLow.Length != 0)
                    {
                        m_defaultValue.fValue = float.Parse(rangeLow);
                    }
                    else
                    {
                        m_defaultValue.fValue = (float)0.0;
                    }
                    retValue = true;
                }
                else
                {
                    float val;
                    try
                    {
                        val = float.Parse(newStrDefValue);

                        if ((rangeHigh.Length != 0) && (val > float.Parse(rangeHigh)))
                        {
                            retValue = false;
                            errorString = "Default value out of range";
                        }
                        else if ((rangeLow.Length != 0) && (val < float.Parse(rangeLow)))
                        {
                            retValue = false;
                            errorString = "Default value out of range";
                        }
                        else
                        {
                            m_defaultValue.fValue = val;
                            retValue = true;
                        }
                    }
                    catch (Exception)
                    {
                        retValue = false;
                        errorString = "Could not convert default value to float";
                    }
                }
            }
            //else if ((dataType == "UNSIGNED_INTEGER") || (dataType == "BCD"))
            else if (dataType.ToUpper() == "UNSIGNED" || (dataType.ToUpper() == "BCD"))
            {
                if (newStrDefValue.Length == 0)
                {
                    if (rangeLow.Length != 0)
                    {
                        m_defaultValue.u19Value = UInt32.Parse(rangeLow);
                    }
                    else
                    {
                        m_defaultValue.u19Value = 0;
                    }
                    retValue = true;
                }
                else
                {
                    U32BIT val;
                    try
                    {
                        val = UInt32.Parse(newStrDefValue);

                        if ((rangeHigh.Length != 0) && (val > UInt32.Parse(rangeHigh)))
                        {
                            retValue = false;
                            errorString = "Default value out of range";
                        }
                        else if ((rangeLow.Length != 0) && (val < UInt32.Parse(rangeLow)))
                        {
                            retValue = false;
                            errorString = "Default value out of range";
                        }
                        else
                        {
                            m_defaultValue.u19Value = val;
                            retValue = true;
                        }
                    }
                    catch (Exception)
                    {
                        retValue = false;
                        errorString = "Could not convert default value to unsigned";
                    }
                }
            }
            else if (dataType.ToUpper() == "INTEGER")
            {
                if (newStrDefValue.Length == 0)
                {
                    if (rangeLow.Length != 0)
                    {
                        m_defaultValue.s19Value = Int32.Parse(rangeLow);
                    }
                    else
                    {
                        m_defaultValue.s19Value = 0;
                    }
                    retValue = true;
                }
                else
                {
                    S32BIT val;
                    try
                    {
                        val = Int32.Parse(newStrDefValue);

                        if ((rangeHigh.Length != 0) && (val > Int32.Parse(rangeHigh)))
                        {
                            retValue = false;
                            errorString = "Default value out of range";
                        }
                        else if ((rangeLow.Length != 0) && (val < Int32.Parse(rangeLow)))
                        {
                            retValue = false;
                            errorString = "Default value out of range";
                        }
                        else
                        {
                            m_defaultValue.s19Value = val;
                            retValue = true;
                        }
                    }
                    catch (Exception)
                    {
                        retValue = false;
                        errorString = "Could not convert default value to int";
                    }
                }
            }
            else if (dataType.ToUpper() == "CODED")
            {
                // TODO - handle condition where default string passed is empty
                if (newStrDefValue.Length == 0)
                {
                    //qDebug() << "Warning!!! Default value passed is empty";

                    // Since no default value is specified, choose one from the available coded values
                    List<string> codedValues = GetCodedValues(codedType, m_CodedTypes);
                    if (codedValues.Count > 0)
                    {
                        m_defaultValue.strValue = codedValues[0];
                        retValue = true;
                    }
                    else
                    {
                        //qDebug() << "Warning!!! Unknown coded type";
                    }
                }
                else
                {
                    // TODO: Check if the default value string matches at least one of the strings in coded values for this type
                    m_defaultValue.u19Value = GetCodedStringRawValue(codedType, newStrDefValue, m_CodedTypes);
                    if (m_defaultValue.u19Value != 0xFFFF) // GetCodedStringRawValue returns 0xFFFF if it does not find a match
                    {
                        m_defaultValue.strValue = newStrDefValue;
                        retValue = true;
                    }
                    else
                    {
                        retValue = false;
                        //qDebug() << "Default value passed does not match any values of this coded type";
                        errorString = "Default value passed does not match any values of this coded type";
                    }
                }
            }

            if (retValue == true)
            {
                strDefaultValue = newStrDefValue;
            }

            return retValue;
        }

        List<string> GetCodedValues(string codedType, List<CodedType> listCodedTypes)
        {
            List<string> codedValues = new List<string>();

            foreach (CodedType ct in listCodedTypes)
            {
                if (ct.type == codedType)
                {
                    codedValues = ct.values;
                    break;
                }
            }

            return codedValues;
        }

        string getStrDefaultValue()
        {
            return strDefaultValue;
        }

        public void LoadDefaultData()
        {
            value = m_defaultValue;
        }
    }
}
