
using System;
using System.Collections.Generic;
using System.Linq;

namespace iq2dev.com.iqCommLib
{
    public class IQVersion
    {
        #region Constant

        /// <summary>
        /// default numbers of digits, used for Version
        /// </summary>
        private const UInt32 DefaultVersionDataSize = 4;

        #endregion Constant

        #region Fields

        /// <summary>
        /// Define, how much numbers has been used for Version
        /// </summary>
        private UInt32 _versionDataSize = DefaultVersionDataSize;

        private string _warningMessage = string.Empty;

        #endregion Fields

        #region Properties

        public UInt32 Major { get; set; }

        public UInt32 Minor { get; set; }

        public UInt32 Revision { get; set; }

        public UInt32 Build { get; set; }

        public UInt32 VersionDataSize { get { return _versionDataSize; } }

        #endregion Properties

        #region Constructors

        public IQVersion()
        {
            Major = 0;
            Minor = 0;
            Revision = 0;
            Build = 0;
        }

        public IQVersion(UInt32 major, UInt32 minor)
        {
            Major = major;
            Minor = minor;
            _versionDataSize = 2;
        }

        public IQVersion(UInt32 major, UInt32 minor, UInt32 revision, UInt32 build)
        {
            Major = major;
            Minor = minor;
            Revision = revision;
            Build = build;
        }

        public IQVersion(IList<byte> list, UInt32 versionDataSize = DefaultVersionDataSize)
        {
            Parse<byte>(list, versionDataSize);
        }

        #endregion Constructors

        #region Public Methods

        public void Parse<T>(IList<T> versionBytesList, UInt32 versionDataSize = DefaultVersionDataSize)
        {
            if ((versionBytesList.Count == 0) || (versionDataSize == 0))
            {
                throw new ArgumentException(string.Format("Number of digits cannot be ZERO"));
            }

            if (versionDataSize > DefaultVersionDataSize)
            {
                throw new ArgumentException(string.Format("Number of digits cannot be greater as {0}, but {1}", DefaultVersionDataSize, versionDataSize));
            }

            //if (versionBytesList.Count != versionDataSize)
            //{
            //    throw new ArgumentException(string.Format("Invalid number of digits {0} in versioning, expected {1}", versionBytesList.Count, versionDataSize));
            //}

            Major = Convert.ToUInt32(versionBytesList[0]);

            if (versionDataSize > 1)
            {
                Minor = Convert.ToUInt32(versionBytesList[1]);
            }

            if (versionDataSize > 2)
            {
                Revision = Convert.ToUInt32(versionBytesList[2]);
            }

            if (versionDataSize > 3)
            {
                Build = Convert.ToUInt32(versionBytesList[3]);
            }

            _versionDataSize = versionDataSize;
        }

        public void Parse<T>(T[] versionBytesArray, UInt32 versionDataSize = DefaultVersionDataSize)
        {
            Parse(versionBytesArray.ToList(), versionDataSize);
        }

        public override string ToString()
        {
            string resultVersion;

            if (IsEqual(0, 0, 0, 0) == true)
            {
                if (string.IsNullOrEmpty(_warningMessage) == true)
                {
                    resultVersion = "NA";
                }
                else
                {
                    resultVersion = _warningMessage;
                }
            }
            else
            {
                resultVersion = Major.ToString();

                if (_versionDataSize > 1)
                {
                    resultVersion += string.Format(".{0}", Minor.ToString()); ;
                }

                if (_versionDataSize > 2)
                {
                    resultVersion += string.Format(".{0}", Revision.ToString()); ;
                }

                if (_versionDataSize > 3)
                {
                    resultVersion += string.Format(".{0}", Build.ToString()); ;
                }
            }

            return resultVersion;
        }

        public List<byte> ToList()
        {
            var versionList = new List<byte>();

            versionList.Add((byte)Major);

            if (_versionDataSize > 1)
            {
                versionList.Add((byte)Minor);
            }

            if (_versionDataSize > 2)
            {
                versionList.Add((byte)Revision);
            }

            if (_versionDataSize > 3)
            {
                versionList.Add((byte)Build);
            }

            return versionList;
        }

        //public List<byte> ToList()
        //{
        //    return new List<byte>() { Major, Minor, Revision, Build };
        //}

        /// <summary>
        /// Check, if software version is equal or greater then expected
        /// </summary>
        /// <param name="major"></param>
        /// <param name="minor"></param>
        /// <param name="revision"></param>
        /// <param name="build"></param>
        /// <returns></returns>
        public bool IsEqualOrGreater(UInt32 major, UInt32 minor = 0, UInt32 revision = 0, UInt32 build = 0)
        {
            if (IsEqual(major, minor, revision, build))
            {
                return true;
            }

            if (isGreater(major, minor, revision, build))
            {
                return true;
            }

            return false;
        }

        public bool IsEqualOrGreater(IQVersion version2Compare)
        {
            if (_versionDataSize != version2Compare.VersionDataSize)
            {
                throw new ArgumentException(string.Format("Version data size should be the same for comparation, but {0} != {1}", _versionDataSize, version2Compare.VersionDataSize));
            }

            return IsEqualOrGreater(version2Compare.Major, version2Compare.Minor, version2Compare.Revision, version2Compare.Build);
        }

        public bool IsLessOrEqual(UInt32 major, UInt32 minor = 0, UInt32 revision = 0, UInt32 build = 0)
        {
            if (IsEqual(major, minor, revision, build))
            {
                return true;
            }

            if (isGreater(major, minor, revision, build) == false)
            {
                return true;
            }

            return false;
        }

        public bool IsLessOrEqual(IQVersion version2Compare)
        {
            if (_versionDataSize != version2Compare.VersionDataSize)
            {
                throw new ArgumentException(string.Format("Version data size should be the same for comparation, but {0} != {1}", _versionDataSize, version2Compare.VersionDataSize));
            }

            return IsLessOrEqual(version2Compare.Major, version2Compare.Minor, version2Compare.Revision, version2Compare.Build);
        }

        public bool IsEqual(IQVersion version2Compare)
        {
            if (_versionDataSize != version2Compare.VersionDataSize)
            {
                throw new ArgumentException(string.Format("Version data size should be the same for comparation, but {0} != {1}", _versionDataSize, version2Compare.VersionDataSize));
            }

            return IsEqual(version2Compare.Major, version2Compare.Minor, version2Compare.Revision, version2Compare.Build);
        }

        public bool IsEqual(UInt32 major, UInt32 minor = 0, UInt32 revision = 0, UInt32 build = 0)
        {
            if (Major != major)
            {
                return false;
            }

            if (_versionDataSize > 1)
            {
                if (Minor != minor)
                {
                    return false;
                }
            }

            if (_versionDataSize > 2)
            {
                if (Revision != revision)
                {
                    return false;
                }
            }

            if (_versionDataSize > 3)
            {
                if (Build != build)
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// This string will be printed, if version is not set
        /// </summary>
        /// <param name="warningMessage"></param>
        public void SetWarningString(string warningMessage)
        {
            _warningMessage = warningMessage;
        }

        #endregion Public Methods

        #region private Methods

        private bool isGreater(UInt32 major, UInt32 minor = 0, UInt32 revision = 0, UInt32 build = 0)
        {
            if (Major > major)
            {
                return true;
            }
            else if (Major < major)
            {
                return false;
            }

            if (_versionDataSize > 1)
            {
                if (Minor > minor)
                {
                    return true;
                }
                else if (Minor < minor)
                {
                    return false;
                }
            }
            else
            {
                return true;
            }

            if (_versionDataSize > 2)
            {
                if (Revision > revision)
                {
                    return true;
                }
                else if (Revision < revision)
                {
                    return false;
                }
            }
            else
            {
                return true;
            }

            if (_versionDataSize > 3)
            {
                if (Build > build)
                {
                    return true;
                }
                else if (Build < build)
                {
                    return false;
                }
            }
            else
            {
                return true;
            }

            return false;
        }

        #endregion private Methods
    }
}