aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/ViewModels/ComparisonWizardViewVM.cs
blob: a58d69a93bedde6fb3597db0b79c9025720a2ea9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace Tango.Scripting.Basic.Properties {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    internal class Resources {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal Resources() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tango.Scripting.Basic.Properties.Resources", typeof(Resources).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Tango.BL;
using Tango.BL.Builders;
using Tango.BL.Entities;
using Tango.BL.Enumerations;
using Tango.Core.Commands;
using Tango.CSV;
using Tango.MachineStudio.Common.Notifications;
using Tango.MachineStudio.HardwareDesigner.Comparison;
using Tango.MachineStudio.HardwareDesigner.Report;
using Tango.SharedUI;

namespace Tango.MachineStudio.HardwareDesigner.ViewModels
{
    /// <summary>
    /// class ComparisonWizardViewVM is view model of dialog for compare properties of 2 hardware versions
    /// </summary>
    /// <seealso cref="Tango.SharedUI.DialogViewVM" />
    public class ComparisonWizardViewVM : DialogViewVM
    {
        private INotificationProvider _notification;
        #region Properties

        private ObservableCollection<HardwareVersion> _hardwareVersions;

        /// <summary>
        /// Gets or sets the hardware versions. Contains all available versions.
        /// </summary>
        /// <value>
        /// The hardware versions.
        /// </value>
        public ObservableCollection<HardwareVersion> HardwareVersions
        {
            get { return _hardwareVersions; }
            set { _hardwareVersions = value; RaisePropertyChangedAuto(); }
        }

        private HardwareVersion _selectedVersion1;

        /// <summary>
        /// Gets or sets the selected version1 contains selected value from left combo box
        /// </summary>
        /// <value>
        /// The selected version1.
        /// </value>
        public HardwareVersion SelectedVersion1
        {
            get { return _selectedVersion1; }
            set
            {
                if (value != null && (_selectedVersion1 == null || _selectedVersion1.Guid != value.Guid))
                {
                    _selectedVersion1 = value;
                    RaisePropertyChangedAuto();
                    OnSelectedVersionChanged();
                }
            }
        }

        private HardwareVersion _selectedVersion2;

        /// <summary>
        /// Gets or sets the selected version2 contains selected value from right combo box
        /// </summary>
        /// <value>
        /// The selected version2.
        /// </value>
        public HardwareVersion SelectedVersion2
        {
            get { return _selectedVersion2; }
            set
            {
                if (value != null && (_selectedVersion2 == null || _selectedVersion2.Guid != value.Guid))
                {
                    _selectedVersion2 = value;
                    RaisePropertyChangedAuto();
                    OnSelectedVersionChanged();
                }

            }
        }

        private bool _isShowDifference;

        /// <summary>
        /// Gets or sets a value indicating whether this instance is show difference. Binding to value of checkbox in GUI.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this instance is show difference; otherwise, <c>false</c>.
        /// </value>
        public bool IsShowDifference
        {
            get { return _isShowDifference; }
            set
            {
                _isShowDifference = value;
                RaisePropertyChangedAuto();
            }
        }

        private HardwareCompareResult _result;

        /// <summary>
        /// Gets or sets the result. Contains result of the comparison  properties from selected versions.
        /// </summary>
        /// <value>
        /// The result.
        /// </value>
        public HardwareCompareResult Result
        {
            get
            {
                return _result;
            }
            set
            {
                _result = value;
                RaisePropertyChangedAuto();
                InvalidateRelayCommands();
            }
        }

        private bool _isRunning;

        public bool IsRunning
        {
            get { return _isRunning; }
            set { _isRunning = value; RaisePropertyChangedAuto(); }
        }

        #endregion properties

        #region Command

        public RelayCommand GenerateReportCommand { get; set; }

        #endregion

        #region Constructors

        public ComparisonWizardViewVM(IEnumerable<HardwareVersion> availableVersions, HardwareVersion selectedVersion, INotificationProvider notification)
        {
            HardwareVersions = new ObservableCollection<HardwareVersion>(availableVersions);
            _selectedVersion1 = selectedVersion;

            _isShowDifference = false;
            IsRunning = false;
            IsShowDifference = true;
            _notification = notification;

            GenerateReportCommand = new RelayCommand(GenerateReport, () => Result != null);
        }

        #endregion

        #region Report

        /// <summary>
        /// Generates the report. Save properties in .csv file in format Collection name/Component name/Property name/Value1 of version1/Value2 of version 2
        /// </summary>
        private void GenerateReport()
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Title = "Save Report";
            dlg.Filter = "CSV Files|*.csv";
            dlg.FileName = $"hw_compare_report__{SelectedVersion1.Name}__vs__{SelectedVersion2.Name}";
            dlg.DefaultExt = ".csv";
            if (dlg.ShowDialog().Value)
            {
                try
                {
                    CsvFile<ReportModel> csvFile = new CsvFile<ReportModel>(new CsvDestination(dlg.FileName), new CsvDefinition()
                    {
                        Columns = new List<String>()
                         {
                             "Collection",
                             "Component",
                             "Property",
                             SelectedVersion1.Name,
                             SelectedVersion2.Name,
                         },
                    });

                    foreach (var collection in Result.Collections.Where(x => x.HasDifferences || !IsShowDifference))
                    {
                        ReportModel model_collection = new ReportModel();
                        model_collection.Collection = collection.CollectionName;
                        csvFile.Append(model_collection);
                        foreach (var component in collection.Components.Where(x => x.HasDifferences || !IsShowDifference))
                        {
                            ReportModel model_component = new ReportModel();

                            model_component.Component = component.ComponentName;
                            csvFile.Append(model_component);
                            foreach (var prop in component.Properties.Where(x => x.HasDifferences || !IsShowDifference))
                            {
                                ReportModel model = new ReportModel();
                                model.Property = prop.PropertyName;
                                model.HW_1 = prop.Value1;
                                model.HW_2 = prop.Value2;
                                csvFile.Append(model);
                            }
                        }
                    }

                    csvFile.Dispose();
                    _notification.ShowInfo("Report generated successfully.");
                }
                catch (Exception ex)
                {
                    LogManager.Log(ex, "Error generating HW version comparison report.");
                    _notification.ShowError($"Error generating HW version comparison report.\n{ex.Message}");
                }
            }
        }

        #endregion

        #region Selected Version Changed

        private async void OnSelectedVersionChanged()
        {
            if (SelectedVersion1 != null && SelectedVersion2 != null)
            {
                IsRunning = true;
                using (ObservablesContext db = ObservablesContext.CreateDefault())
                {
                    var h1 = await new HardwareVersionBuilder(db).Set(SelectedVersion1.Guid).WithHardwareComponents().BuildAsync();
                    var h2 = await new HardwareVersionBuilder(db).Set(SelectedVersion2.Guid).WithHardwareComponents().BuildAsync();

                    await Task.Factory.StartNew(() =>
                    {
                        Result = CompareHardwareVersions(h1, h2);
                        IsRunning = false;
                    });
                }
            }
        } 
        #endregion

        #region Compare Versions

        private HardwareCompareResult CompareHardwareVersions(HardwareVersion h1, HardwareVersion h2)
        {
            _result = new HardwareCompareResult();
            _result.Collections.Add(CompareMotorsCollection(h1, h2));
            _result.Collections.Add(CompareDancerCollection(h1, h2));
            _result.Collections.Add(ComparePidControlsCollection(h1, h2));
            _result.Collections.Add(CompareWindersCollection(h1, h2));
            _result.Collections.Add(CompareSpeedSensorsCollection(h1, h2));
            _result.Collections.Add(CompareBlowersCollection(h1, h2));
            _result.Collections.Add(CompareBreakSensorCollection(h1, h2));
            

            return _result;
        }

        private HardwareComponentCollectionCompareResult CompareMotorsCollection(HardwareVersion h1, HardwareVersion h2)
        {
            HardwareComponentCollectionCompareResult collection = new HardwareComponentCollectionCompareResult()
            {
                CollectionName = "MOTORS"
            };
            foreach (var motorTypeCode in Enum.GetValues(typeof(HardwareMotorTypes)).Cast<HardwareMotorTypes>())
            {
                var motor1 = h1.HardwareMotors.SingleOrDefault(x => x.HardwareMotorType.Code == motorTypeCode.ToInt32());
                var motor2 = h2.HardwareMotors.SingleOrDefault(x => x.HardwareMotorType.Code == motorTypeCode.ToInt32());

                var componentResult = CompareComponents(
                    motorTypeCode.ToDescription(),
                    GetComponentProperties(typeof(HardwareMotorBase)),
                    motor1,
                    motor2);

                collection.Components.Add(componentResult);
            }
            collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection();
            return collection;
        }

        private HardwareComponentCollectionCompareResult CompareDancerCollection(HardwareVersion h1, HardwareVersion h2)
        {
            HardwareComponentCollectionCompareResult collection = new HardwareComponentCollectionCompareResult()
            {
                CollectionName = "DANCERS"
            };
            foreach (var dancerTypeCode in Enum.GetValues(typeof(HardwareDancerTypes)).Cast<HardwareDancerTypes>())
            {
                var motor1 = h1.HardwareDancers.SingleOrDefault(x => x.HardwareDancerType.Code == dancerTypeCode.ToInt32());
                var motor2 = h2.HardwareDancers.SingleOrDefault(x => x.HardwareDancerType.Code == dancerTypeCode.ToInt32());

                var componentResult = CompareComponents(
                    dancerTypeCode.ToDescription(),
                    GetComponentProperties(typeof(HardwareDancerBase)),
                    motor1,
                    motor2);

                collection.Components.Add(componentResult);
            }
            collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection();
            return collection;
        }

        private HardwareComponentCollectionCompareResult ComparePidControlsCollection(HardwareVersion h1, HardwareVersion h2)
        {
            HardwareComponentCollectionCompareResult collection = new HardwareComponentCollectionCompareResult()
            {
                CollectionName = "PID CONTROLS"
            };
            foreach (var pidControlsTypeCode in Enum.GetValues(typeof(HardwarePidControlTypes)).Cast<HardwarePidControlTypes>())
            {
                var motor1 = h1.HardwarePidControls.SingleOrDefault(x => x.HardwarePidControlType.Code == pidControlsTypeCode.ToInt32());
                var motor2 = h2.HardwarePidControls.SingleOrDefault(x => x.HardwarePidControlType.Code == pidControlsTypeCode.ToInt32());

                var componentResult = CompareComponents(
                    pidControlsTypeCode.ToDescription(),
                    GetComponentProperties(typeof(HardwarePidControlBase)),
                    motor1,
                    motor2);

                collection.Components.Add(componentResult);
            }
            collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection();
            return collection;
        }

        private HardwareComponentCollectionCompareResult CompareWindersCollection(HardwareVersion h1, HardwareVersion h2)
        {
            HardwareComponentCollectionCompareResult collection = new HardwareComponentCollectionCompareResult()
            {
                CollectionName = "WINDERS"
            };
            foreach (var WinderTypeCode in Enum.GetValues(typeof(HardwareWinderTypes)).Cast<HardwareWinderTypes>())
            {
                var motor1 = h1.HardwareWinders.SingleOrDefault(x => x.HardwareWinderType.Code == WinderTypeCode.ToInt32());
                var motor2 = h2.HardwareWinders.SingleOrDefault(x => x.HardwareWinderType.Code == WinderTypeCode.ToInt32());

                var componentResult = CompareComponents(
                    WinderTypeCode.ToDescription(),
                    GetComponentProperties(typeof(HardwareWinderBase)),
                    motor1,
                    motor2);

                collection.Components.Add(componentResult);
            }
            collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection();
            return collection;
        }

        private HardwareComponentCollectionCompareResult CompareSpeedSensorsCollection(HardwareVersion h1, HardwareVersion h2)
        {
            HardwareComponentCollectionCompareResult collection = new HardwareComponentCollectionCompareResult()
            {
                CollectionName = "SPEED SENSORS"
            };
            foreach (var speedSewnsorsTypeCode in Enum.GetValues(typeof(HardwareSpeedSensorTypes)).Cast<HardwareSpeedSensorTypes>())
            {
                var motor1 = h1.HardwareSpeedSensors.SingleOrDefault(x => x.HardwareSpeedSensorType.Code == speedSewnsorsTypeCode.ToInt32());
                var motor2 = h2.HardwareSpeedSensors.SingleOrDefault(x => x.HardwareSpeedSensorType.Code == speedSewnsorsTypeCode.ToInt32());

                var componentResult = CompareComponents(
                    speedSewnsorsTypeCode.ToDescription(),
                    GetComponentProperties(typeof(HardwareSpeedSensorBase)),
                    motor1,
                    motor2);

                collection.Components.Add(componentResult);
            }
            collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection();
            return collection;
        }

        private HardwareComponentCollectionCompareResult CompareBlowersCollection(HardwareVersion h1, HardwareVersion h2)
        {
            HardwareComponentCollectionCompareResult collection = new HardwareComponentCollectionCompareResult()
            {
                CollectionName = "BLOWERS"
            };
            foreach (var blowersTypeCode in Enum.GetValues(typeof(HardwareBlowerTypes)).Cast<HardwareBlowerTypes>())
            {
                var motor1 = h1.HardwareBlowers.SingleOrDefault(x => x.HardwareBlowerType.Code == blowersTypeCode.ToInt32());
                var motor2 = h2.HardwareBlowers.SingleOrDefault(x => x.HardwareBlowerType.Code == blowersTypeCode.ToInt32());

                var componentResult = CompareComponents(
                    blowersTypeCode.ToDescription(),
                    GetComponentProperties(typeof(HardwareBlowerBase)),
                    motor1,
                    motor2);

                collection.Components.Add(componentResult);
            }
            collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection();
            return collection;
        }

        private HardwareComponentCollectionCompareResult CompareBreakSensorCollection(HardwareVersion h1, HardwareVersion h2)
        {
            HardwareComponentCollectionCompareResult collection = new HardwareComponentCollectionCompareResult()
            {
                CollectionName = "BREAK SENSOR"
            };
            foreach (var breakSewnsorsTypeCode in Enum.GetValues(typeof(HardwareBreakSensorTypes)).Cast<HardwareBreakSensorTypes>())
            {
                var motor1 = h1.HardwareBreakSensors.SingleOrDefault(x => x.HardwareBreakSensorType.Code == breakSewnsorsTypeCode.ToInt32());
                var motor2 = h2.HardwareBreakSensors.SingleOrDefault(x => x.HardwareBreakSensorType.Code == breakSewnsorsTypeCode.ToInt32());

                var componentResult = CompareComponents(
                    breakSewnsorsTypeCode.ToDescription(),
                    GetComponentProperties(typeof(HardwareBreakSensorBase)),
                    motor1,
                    motor2);

                collection.Components.Add(componentResult);
            }
            collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection();
            return collection;
        }
        
        private HardwareComponentCompareResult CompareComponents(String name, List<PropertyInfo> properties, Object component1, Object component2)
        {
            HardwareComponentCompareResult result = new HardwareComponentCompareResult();
            result.ComponentName = name;
            result.HasComponent1 = component1 != null;
            result.HasComponent2 = component2 != null;

            foreach (var prop in properties)
            {
                var hProp = new HardwareComponentPropertyResult();
                hProp.PropertyName = prop.Name;
                hProp.Value1 = component1 != null ? (prop.GetValue(component1) == null ? "" : prop.GetValue(component1).ToString()) : null;
                hProp.Value2 = component2 != null ? (prop.GetValue(component2) == null ? "" : prop.GetValue(component2).ToString()) : null;

                result.Properties.Add(hProp);
            }
            return result;
        }

        private List<PropertyInfo> GetComponentProperties(Type componentType)
        {
            List<String> exclude = new List<string>()
            {
                 "Guid",
                 "ID",
                 "LastUpdated",
                 "Parameters",
            };

            return componentType.GetProperties(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public).Where(x => !x.PropertyType.IsClass && !exclude.Contains(x.Name)).ToList();
        }

        #endregion
    }
}