/// <summary>
 /// Initializes a new instance of the <see cref="BudgetConfig"/> class
 /// </summary>
 /// <param name="elements">The root <see cref="ElementDefinition"/>s for which the budget is calculated</param>
 /// <param name="subSystemDef">The sub-system definition</param>
 /// <param name="parameterWithMargin">The parameter to used in the budget calculation</param>
 /// <param name="numberOfElementParameterType">The number of element parameter-type</param>
 /// <param name="systemLevel">The Parameter-type representing the system-level to use in the budget calculation by default</param>
 /// <param name="subsysLevelDef">The <see cref="EnumerationValueDefinition"/> representing a sub-system</param>
 /// <param name="equipmentLevelDef">The <see cref="EnumerationValueDefinition"/> representing an equipment</param>
 public BudgetConfig(
     IReadOnlyList <ElementDefinition> elements,
     IReadOnlyList <SubSystemDefinition> subSystemDef,
     BudgetParameterConfigBase parameterWithMargin,
     QuantityKind numberOfElementParameterType,
     EnumerationParameterType systemLevel,
     EnumerationValueDefinition subsysLevelDef,
     EnumerationValueDefinition equipmentLevelDef)
 {
     this.Elements = elements;
     this.NumberOfElementParameterType = numberOfElementParameterType;
     this.BudgetParameterConfig        = parameterWithMargin;
     this.SubSystemDefinition          = subSystemDef;
     this.SystemLevelToUse             = systemLevel;
     this.SubSystemLevelEnum           = subsysLevelDef;
     this.EquipmentLevelEnum           = equipmentLevelDef;
 }
        /// <summary>
        /// Initializes an instance of <see cref="BudgetConfig"/> from this <see cref="BudgetConfigDto"/> given the available <see cref="QuantityKind"/>, <see cref="EnumerationParameterType"/> and <see cref="Category"/>
        /// </summary>
        /// <param name="usedQuantityKinds">The available <see cref="QuantityKind"/></param>
        /// <param name="enumerationParameterTypes">The available <see cref="EnumerationParameterType"/></param>
        /// <param name="usedCategories">The available <see cref="Category"/></param>
        /// <returns>The <see cref="BudgetConfig"/></returns>
        public BudgetConfig ToBudgetConfig(IReadOnlyList <QuantityKind> usedQuantityKinds, IReadOnlyList <EnumerationParameterType> enumerationParameterTypes, IReadOnlyList <Category> usedCategories)
        {
            QuantityKind               numberOfElementPt  = null;
            EnumerationParameterType   systemLevelPt      = null;
            EnumerationValueDefinition subSystemLevelEnum = null;
            EnumerationValueDefinition equipmentLevelEnum = null;

            if (this.NumberOfElement.HasValue)
            {
                numberOfElementPt = usedQuantityKinds.FirstOrDefault(x => x.Iid == this.NumberOfElement.Value);
            }

            if (this.SystemLevel.HasValue)
            {
                systemLevelPt = enumerationParameterTypes.FirstOrDefault(x => x.Iid == this.SystemLevel.Value);

                if (this.SubSystemLevelEnum.HasValue && systemLevelPt != null)
                {
                    subSystemLevelEnum = systemLevelPt.ValueDefinition.FirstOrDefault(x => x.Iid == this.SubSystemLevelEnum.Value);
                }

                if (this.EquipmentLevelEnum.HasValue && systemLevelPt != null)
                {
                    equipmentLevelEnum = systemLevelPt.ValueDefinition.FirstOrDefault(x => x.Iid == this.EquipmentLevelEnum.Value);;
                }
            }

            // resolve Parameter-Configuration
            var          massConfig     = this.ParameterConfig as MassParameterConfigDto;
            QuantityKind configMarginPt = null;

            BudgetParameterConfigBase parameterConfigBase = null;

            if (massConfig != null)
            {
                var configPt = usedQuantityKinds.FirstOrDefault(x => x.Iid == massConfig.ParameterType);

                if (massConfig.MarginParameterType.HasValue)
                {
                    configMarginPt = usedQuantityKinds.FirstOrDefault(x => x.Iid == massConfig.MarginParameterType.Value);
                }

                var extraConfigList = new List <ExtraMassContributionConfiguration>();
                foreach (var extraContributionDto in massConfig.ExtraContribution)
                {
                    QuantityKind extraContributionMarginPt = null;
                    var          extraContributionPt       = usedQuantityKinds.FirstOrDefault(x => x.Iid == extraContributionDto.ParameterType);

                    if (extraContributionDto.MarginParameterType.HasValue)
                    {
                        extraContributionMarginPt = usedQuantityKinds.FirstOrDefault(x => x.Iid == extraContributionDto.MarginParameterType.Value);
                    }

                    var extraContributionCategories = new List <Category>();
                    foreach (var categoryId in extraContributionDto.Categories)
                    {
                        var category = usedCategories.FirstOrDefault(x => x.Iid == categoryId);
                        if (category != null)
                        {
                            extraContributionCategories.Add(category);
                        }
                    }

                    var extraContributionConfig = new ExtraMassContributionConfiguration(extraContributionCategories, extraContributionPt, extraContributionMarginPt);
                    extraConfigList.Add(extraContributionConfig);
                }

                parameterConfigBase = new MassBudgetParameterConfig(new BudgetParameterMarginPair(configPt, configMarginPt), extraConfigList);
            }

            // resolve Parameter-Configuration
            var genericConfig = this.ParameterConfig as GenericParameterConfigDto;

            if (genericConfig != null)
            {
                var configPt = usedQuantityKinds.FirstOrDefault(x => x.Iid == genericConfig.ParameterType);

                if (genericConfig.MarginParameterType.HasValue)
                {
                    configMarginPt = usedQuantityKinds.FirstOrDefault(x => x.Iid == genericConfig.MarginParameterType.Value);
                }

                parameterConfigBase = new GenericBudgetParameterConfig(new BudgetParameterMarginPair(configPt, configMarginPt));
            }

            // resolve sub-systems
            var subSystemDef = new List <SubSystemDefinition>();

            foreach (var subSystemDefinitionDto in this.SubSystemDefinition)
            {
                var subSysCat    = new List <Category>();
                var equipmentCat = new List <Category>();

                foreach (var catId in subSystemDefinitionDto.Categories)
                {
                    var category = usedCategories.FirstOrDefault(x => x.Iid == catId);
                    if (category != null)
                    {
                        subSysCat.Add(category);
                    }
                }

                foreach (var catId in subSystemDefinitionDto.ElementCategories)
                {
                    var category = usedCategories.FirstOrDefault(x => x.Iid == catId);
                    if (category != null)
                    {
                        equipmentCat.Add(category);
                    }
                }

                subSystemDef.Add(new SubSystemDefinition(subSysCat, equipmentCat));
            }

            return(new BudgetConfig(null, subSystemDef, parameterConfigBase, numberOfElementPt, systemLevelPt, subSystemLevelEnum, equipmentLevelEnum));
        }