using Aitex.Core.Common.DeviceData;
using MECF.Framework.Common.CommonData;
using System;
using System.Runtime.Serialization;

namespace MECF.Framework.Common.Utilities
{
    [Serializable]
    [DataContract]
    public class ReleaseVersion : NotifiableItem, ICloneable, IDeviceData
    {
        #region Variables

        private int _major;
        private int _minor;
        private int _patch;
        private int _build;
        private string _prefix;
        private string _suffix;

        private string _hyphen = "-";

        #endregion


        #region Constructors

        public ReleaseVersion()
        {

        }

        public ReleaseVersion(int major, int minor, int patch, int build, string prefix = "", string suffix = "")
        {
            Major = major;
            Minor = minor;
            Patch = patch;
            Build = build;
            Prefix = prefix.TrimStart(' ');
            Suffix = suffix.Trim(' ');
        }

        #endregion


        #region Properties

        [DataMember]
        public string Hyphen
        {
            get => _hyphen;
            set => Set(ref _hyphen, value);
        }

        [DataMember]
        public int Major
        {
            get => _major;
            set => Set(ref _major, value);
        }

        [DataMember]
        public int Minor
        {
            get => _minor;
            set => Set(ref _minor, value);
        }

        [DataMember]
        public int Patch
        {
            get => _patch;
            set => Set(ref _patch, value);
        }

        [DataMember]
        public int Build
        {
            get => _build;
            set => Set(ref _build, value);
        }

        [DataMember]
        public string Prefix
        {
            get => _prefix;
            set => Set(ref _prefix, value);
        }

        [DataMember]
        public string Suffix
        {
            get => _suffix;
            set => Set(ref _suffix, value);
        }

        #endregion

        #region Methods

        public static ReleaseVersion operator ++(ReleaseVersion ver)
        {
            if (ver is null)
                throw new NullReferenceException();

            ver.Patch++;
            return ver;
        }

        public static bool operator ==(ReleaseVersion v1, ReleaseVersion v2)
        {
            if (v1 is null && v2 is not null)
                return false;

            if (v1 is not null && v2 is null)
                return false;

            if (v1 is null)
                return false;

            return string.Compare(v1.Prefix, v2.Prefix, StringComparison.OrdinalIgnoreCase) == 0 &&
                   string.Compare(v1.Suffix, v2.Suffix, StringComparison.OrdinalIgnoreCase) == 0 &&
                   v1.Major == v2.Major &&
                   v1.Minor == v2.Minor &&
                   v1.Patch == v2.Patch &&
                   v1.Build == v2.Build;
        }

        public static bool operator !=(ReleaseVersion v1, ReleaseVersion v2)
        {
            return !(v1 == v2);
        }

        public static bool operator >(ReleaseVersion v1, ReleaseVersion v2)
        {
            if (v1 is null || v2 is null)
                throw new NullReferenceException();

            if (v1.Major > v2.Major) return true;
            if (v1.Minor > v2.Minor) return true;
            if (v1.Patch > v2.Patch) return true;
            if (v1.Build > v2.Build) return true;
            return false;
        }

        public static bool operator >=(ReleaseVersion v1, ReleaseVersion v2)
        {
            if (v1 is null || v2 is null)
                throw new NullReferenceException();

            if (v1.Major < v2.Major)
                return false;
            else
            {
                if (v1.Minor < v2.Minor)
                    return false;
                if (v1.Patch < v2.Patch)
                    return false;
                if (v1.Build < v2.Build)
                    return false;
                else
                    return true;
            }
        }

        public static bool operator <(ReleaseVersion v1, ReleaseVersion v2)
        {
            if (v1 is null || v2 is null)
                throw new NullReferenceException();

            if (v1.Major < v2.Major) return true;
            if (v1.Minor < v2.Minor) return true;
            if (v1.Patch < v2.Patch) return true;
            if (v1.Build < v2.Build) return true;
            return false;
        }
        public static bool operator <=(ReleaseVersion v1, ReleaseVersion v2)
        {
            if (v1 is null || v2 is null)
                return false;

            if (v1.Major > v2.Major)
                return false;
            else
            {
                if (v1.Minor > v2.Minor)
                    return false;
                if (v1.Patch > v2.Patch)
                    return false;
                if (v1.Build > v2.Build)
                    return false;
                else
                    return true;
            }
        }

        public override string ToString()
        {
            return $"{(string.IsNullOrEmpty(Prefix) ? "" : $"{Prefix}{Hyphen}")}" +
                   $"{Major}.{Minor}.{Patch}.{Build}" +
                   $"{(string.IsNullOrEmpty(Suffix) ? "" : $"{Hyphen}{Suffix}")}";
        }

        public object Clone()
        {
            var v = new ReleaseVersion(Major, Minor, Patch, Build, Prefix, Suffix);
            return v;
        }

        public override bool Equals(object obj)
        {
            if (obj is not ReleaseVersion version)
                return false;

            return this == version;
        }

        public override int GetHashCode()
        {
            return ToString().GetHashCode();
        }

        public void Update(IDeviceData data)
        {
            if(data is ReleaseVersion ver)
            {
                Major = ver.Major;
                Minor = ver.Minor;
                Patch = ver.Patch;
                Build = ver.Build;
                Prefix = ver.Prefix;
                Suffix = ver.Suffix;
                Hyphen = ver.Hyphen;
            }
        }

        #endregion
    }
}
