/// <summary>
	    /// Recomputes power distribution in subset of all priority groups (in range
	    /// from startPriorityIdx until the end). Passing index 0 recomputes all priority groups.
	    /// </summary>
	    private static MyResourceStateEnum RecomputeResourceDistributionPartial(
			ref MyDefinitionId typeId,
			int startPriorityIdx, 
			MySinkGroupData[] sinkDataByPriority,
			MySourceGroupData[] sourceDataByPriority,
            ref MyTuple<MySinkGroupData, MySourceGroupData> sinkSourceData,
            HashSet<MyResourceSinkComponent>[] sinksByPriority,
			HashSet<MyResourceSourceComponent>[] sourcesByPriority,
            List<MyTuple<MyResourceSinkComponent, MyResourceSourceComponent>> sinkSourcePairs,
			List<int> stockpilingStorageList,
			List<int> otherStorageList,
			float availableResource)
	    {
            ProfilerShort.Begin("MyResourceDistributor.RecomputeResourceDistributionPartial");
		    ProfilerShort.Begin("Non-zero inputs");
		    float totalAvailableResource = availableResource;
		    int sinkPriorityIndex = startPriorityIdx;

            // Distribute power over the sinks by priority
			for (; sinkPriorityIndex < sinksByPriority.Length; ++sinkPriorityIndex)
		    {
				sinkDataByPriority[sinkPriorityIndex].RemainingAvailableResource = availableResource;

				if (sinkDataByPriority[sinkPriorityIndex].RequiredInput <= availableResource)
			    {
				    // Run everything in the group at max.
					availableResource -= sinkDataByPriority[sinkPriorityIndex].RequiredInput;
				    foreach (MyResourceSinkComponent sink in sinksByPriority[sinkPriorityIndex])
						sink.SetInputFromDistributor(typeId, sink.RequiredInputByType(typeId), sinkDataByPriority[sinkPriorityIndex].IsAdaptible);
			    }
				else if (sinkDataByPriority[sinkPriorityIndex].IsAdaptible && availableResource > 0.0f)
			    {
				    // Distribute power in this group based on ratio of its requirement vs. group requirement.
				    foreach (MyResourceSinkComponent sink in sinksByPriority[sinkPriorityIndex])
				    {
						float ratio = sink.RequiredInputByType(typeId) / sinkDataByPriority[sinkPriorityIndex].RequiredInput;
						sink.SetInputFromDistributor(typeId, ratio * availableResource, true);
				    }
				    availableResource = 0.0f;
			    }
			    else
			    {
				    // Not enough power for this group and members can't adapt.
				    // None of the lower priority groups will get any power either.
                    foreach (MyResourceSinkComponent sink in sinksByPriority[sinkPriorityIndex])
						sink.SetInputFromDistributor(typeId, 0.0f, sinkDataByPriority[sinkPriorityIndex].IsAdaptible);
					sinkDataByPriority[sinkPriorityIndex].RemainingAvailableResource = availableResource;
				    ++sinkPriorityIndex; // move on to next group
				    break;
			    }
		    }
            ProfilerShort.End();
            ProfilerShort.Begin("Zero inputs");
		    // Set remaining data.
			for (; sinkPriorityIndex < sinkDataByPriority.Length; ++sinkPriorityIndex)
		    {
				sinkDataByPriority[sinkPriorityIndex].RemainingAvailableResource = 0.0f;
				foreach (MyResourceSinkComponent sink in sinksByPriority[sinkPriorityIndex])
					sink.SetInputFromDistributor(typeId, 0.0f, sinkDataByPriority[sinkPriorityIndex].IsAdaptible);
		    }
            ProfilerShort.End();
            float consumptionForNonStorage = totalAvailableResource - availableResource + (startPriorityIdx != 0 ? sinkDataByPriority[0].RemainingAvailableResource - sinkDataByPriority[startPriorityIdx].RemainingAvailableResource : 0f);

            // Distribute remaining energy over stockpiling storage
	        float totalAvailableResourcesForStockpiles = Math.Max(totalAvailableResource - consumptionForNonStorage, 0);
	        float availableResourcesForStockpiles = totalAvailableResourcesForStockpiles;
            if (stockpilingStorageList.Count > 0)
            {
                ProfilerShort.Begin("Stockpiles");
				float stockpilesRequiredInput = sinkSourceData.Item1.RequiredInputCumulative;
				if (stockpilesRequiredInput <= availableResourcesForStockpiles)
                {
					availableResourcesForStockpiles -= stockpilesRequiredInput;
                    //ToArray = Hotfix for collection modified exception
                    foreach (int pairIndex in stockpilingStorageList.ToArray())
                    {
                        var sink = sinkSourcePairs[pairIndex].Item1;
                        sink.SetInputFromDistributor(typeId, sink.RequiredInputByType(typeId), true);
                    }
                    sinkSourceData.Item1.RemainingAvailableResource = availableResourcesForStockpiles;
                }
                else
                {
                    //ToArray = Hotfix for collection modified exception
                    foreach (int pairIndex in stockpilingStorageList.ToArray())
                    {
                        var sink = sinkSourcePairs[pairIndex].Item1;
						float ratio = sink.RequiredInputByType(typeId) / stockpilesRequiredInput;
                        sink.SetInputFromDistributor(typeId, ratio * totalAvailableResourcesForStockpiles, true);
                    }
                    availableResourcesForStockpiles = 0f;
                    sinkSourceData.Item1.RemainingAvailableResource = availableResourcesForStockpiles;
                }
                ProfilerShort.End();
            }

            // Distribute remaining power over non-stockpiling storage
	        float consumptionForStockpiles = totalAvailableResourcesForStockpiles - availableResourcesForStockpiles;
            float totalAvailableResourcesForStorage = Math.Max(totalAvailableResource - (sinkSourceData.Item2.MaxAvailableResource - sinkSourceData.Item2.MaxAvailableResource * sinkSourceData.Item2.UsageRatio) - consumptionForNonStorage - consumptionForStockpiles, 0);
            float availableResourcesForStorage = totalAvailableResourcesForStorage;
            if (otherStorageList.Count > 0)
            {
                ProfilerShort.Begin("Non-stockpiling storage");
				float ordinaryStorageRequiredInput = sinkSourceData.Item1.RequiredInput - sinkSourceData.Item1.RequiredInputCumulative;
				if (ordinaryStorageRequiredInput <= availableResourcesForStorage)
                {
					availableResourcesForStorage -= ordinaryStorageRequiredInput;
                    foreach (int pairIndex in otherStorageList)
                    {
                        var sink = sinkSourcePairs[pairIndex].Item1;
                        sink.SetInputFromDistributor(typeId, sink.RequiredInputByType(typeId), true);
                    }
                    sinkSourceData.Item1.RemainingAvailableResource = availableResourcesForStorage;
                }
                else
                {
                    foreach (int pairIndex in otherStorageList)
                    {
                        var sink = sinkSourcePairs[pairIndex].Item1;
                        float ratio = sink.RequiredInputByType(typeId) / ordinaryStorageRequiredInput;
                        sink.SetInputFromDistributor(typeId, ratio * availableResourcesForStorage, true);
                    }
                    availableResourcesForStorage = 0f;
                    sinkSourceData.Item1.RemainingAvailableResource = availableResourcesForStorage;
                }
                ProfilerShort.End();
            }
            
            ProfilerShort.Begin("Sources");
            float consumptionForStorage = totalAvailableResourcesForStorage - availableResourcesForStorage;
	        float consumptionForNonStorageAndStockpiles = consumptionForStockpiles + consumptionForNonStorage;
	        if (sinkSourceData.Item2.MaxAvailableResource > 0)
	        {
                float amountToSupply = consumptionForNonStorageAndStockpiles;
	            sinkSourceData.Item2.UsageRatio = Math.Min(1f, amountToSupply/sinkSourceData.Item2.MaxAvailableResource);
                consumptionForNonStorageAndStockpiles -= Math.Min(amountToSupply, sinkSourceData.Item2.MaxAvailableResource);
	        }
	        else
	            sinkSourceData.Item2.UsageRatio = 0f;

            sinkSourceData.Item2.ActiveCount = 0;
            foreach (int pairIndex in otherStorageList)
            {
                var source = sinkSourcePairs[pairIndex].Item2;
                if (!source.Enabled || !source.ProductionEnabledByType(typeId) || !source.HasCapacityRemainingByType(typeId))
                    continue;

                ++sinkSourceData.Item2.ActiveCount;
                ProfilerShort.Begin("Set CurrentOutput");
                source.SetOutputByType(typeId, sinkSourceData.Item2.UsageRatio * source.MaxOutputByType(typeId));
                ProfilerShort.End();
            }

	        int sourcePriorityIndex = 0;
            float totalRemainingConsumption = consumptionForNonStorageAndStockpiles + consumptionForStorage;
			for (; sourcePriorityIndex < sourcesByPriority.Length; ++sourcePriorityIndex)
		    {
			    if (sourceDataByPriority[sourcePriorityIndex].MaxAvailableResource > 0f)
			    {
                    float amountToSupply = Math.Max(totalRemainingConsumption, 0f);
				    sourceDataByPriority[sourcePriorityIndex].UsageRatio = Math.Min(1f, amountToSupply/sourceDataByPriority[sourcePriorityIndex].MaxAvailableResource);
                    totalRemainingConsumption -= Math.Min(amountToSupply, sourceDataByPriority[sourcePriorityIndex].MaxAvailableResource);
			    }
			    else
				    sourceDataByPriority[sourcePriorityIndex].UsageRatio = 0f;

			    sourceDataByPriority[sourcePriorityIndex].ActiveCount = 0;
			    foreach (MyResourceSourceComponent source in sourcesByPriority[sourcePriorityIndex])
			    {
				    if (!source.Enabled || !source.HasCapacityRemainingByType(typeId))
					    continue;

				    ++sourceDataByPriority[sourcePriorityIndex].ActiveCount;
				    ProfilerShort.Begin("Set CurrentOutput");
                    source.SetOutputByType(typeId, sourceDataByPriority[sourcePriorityIndex].UsageRatio * source.MaxOutputByType(typeId));
				    ProfilerShort.End();
			    }
		    }

		    MyResourceStateEnum resultState;
			if (totalAvailableResource == 0.0f)
				resultState = MyResourceStateEnum.NoPower;
			else if (sinkDataByPriority[m_sinkGroupPrioritiesTotal - 1].RequiredInputCumulative > totalAvailableResource)
		    {
				MySinkGroupData lastGroup = sinkDataByPriority.Last();
			    if (lastGroup.IsAdaptible && lastGroup.RemainingAvailableResource != 0.0f)
					resultState = MyResourceStateEnum.OverloadAdaptible;
			    else
					resultState = MyResourceStateEnum.OverloadBlackout;
		    }
		    else
				resultState = MyResourceStateEnum.Ok;
		    ProfilerShort.End();

            ProfilerShort.End();

		    return resultState;
	    }
		private void InitializeNewType(ref MyDefinitionId typeId)
		{
			m_typeIdToIndex.Add(typeId, m_typeGroupCount++);
			m_typeIdToConveyorConnectionRequired.Add(typeId, IsConveyorConnectionRequiredTotal(ref typeId));

            var sinksByPriority = new HashSet<MyResourceSinkComponent>[m_sinkGroupPrioritiesTotal];
            var sourceByPriority = new HashSet<MyResourceSourceComponent>[m_sourceGroupPrioritiesTotal];
            var inputOutputList = new List<MyTuple<MyResourceSinkComponent, MyResourceSourceComponent>>();

            for (int priorityIndex = 0; priorityIndex < sinksByPriority.Length; ++priorityIndex)
                sinksByPriority[priorityIndex] = new HashSet<MyResourceSinkComponent>();

            for (int priorityIndex = 0; priorityIndex < sourceByPriority.Length; ++priorityIndex)
                sourceByPriority[priorityIndex] = new HashSet<MyResourceSourceComponent>();

            List<MyPhysicalDistributionGroup> distributionGroups = null;
		    int distributionGroupsInUse = 0;

		    MySinkGroupData[] sinkGroupDataByPriority = null;
		    MySourceGroupData[] sourceGroupDatabyPriority = null;
		    List<int> stockpilingStorageIndices = null;
		    List<int> otherStorageIndices = null;

		    if (IsConveyorConnectionRequired(ref typeId))
		    {
                distributionGroups = new List<MyPhysicalDistributionGroup>();
		    }
		    else
		    {
                sinkGroupDataByPriority = new MySinkGroupData[m_sinkGroupPrioritiesTotal];
                sourceGroupDatabyPriority = new MySourceGroupData[m_sourceGroupPrioritiesTotal];
                stockpilingStorageIndices = new List<int>();
                otherStorageIndices = new List<int>();
		    }

            m_dataPerType.Add(new PerTypeData
            {
                SinkDataByPriority = sinkGroupDataByPriority,
                SourceDataByPriority = sourceGroupDatabyPriority,
                InputOutputData = new MyTuple<MySinkGroupData, MySourceGroupData>(),
                SinksByPriority = sinksByPriority,
                SourcesByPriority = sourceByPriority,
                InputOutputList = inputOutputList,
                StockpilingStorageIndices = stockpilingStorageIndices,
                OtherStorageIndices = otherStorageIndices,
                DistributionGroups = distributionGroups,
                DistributionGroupsInUse = distributionGroupsInUse,
                NeedsRecompute = true,
                GroupsDirty = true,
                SourceCount = 0,
                RemainingFuelTime = 0,
                RemainingFuelTimeDirty = true,
                LastFuelTimeCompute = 0,
                MaxAvailableResource = 0,
                SourcesEnabled = MyMultipleEnabledEnum.NoObjects,
                SourcesEnabledDirty = true,
                ResourceState = MyResourceStateEnum.NoPower,
            });

			m_initializedTypes.Add(typeId);
		}
		private static void ComputeInitialDistributionData(
			ref MyDefinitionId typeId,
			MySinkGroupData[] sinkDataByPriority,
			MySourceGroupData[] sourceDataByPriority,
            ref MyTuple<MySinkGroupData, MySourceGroupData> sinkSourceData,
            HashSet<MyResourceSinkComponent>[] sinksByPriority,
			HashSet<MyResourceSourceComponent>[] sourcesByPriority,
            List<MyTuple<MyResourceSinkComponent, MyResourceSourceComponent>> sinkSourcePairs,
			List<int> stockpilingStorageList,
			List<int> otherStorageList,
			out float maxAvailableResource)
		{
			// Clear state of all sources and sinks. Also find out how 
			// much of resource is available for distribution.
			maxAvailableResource = 0.0f;

			Debug.Assert(sourceDataByPriority.Length == sourcesByPriority.Length);
			for (int i = 0; i < sourceDataByPriority.Length; ++i)
			{
				var resourceSources = sourcesByPriority[i];
				MySourceGroupData sourceGroupData = sourceDataByPriority[i];
				sourceGroupData.MaxAvailableResource = 0f;
				foreach (MyResourceSourceComponent source in resourceSources)
				{
					if (!source.Enabled || !source.HasCapacityRemainingByType(typeId))
						continue;

					sourceGroupData.MaxAvailableResource += source.MaxOutputByType(typeId);
					sourceGroupData.InfiniteCapacity = source.IsInfiniteCapacity;
				}
				maxAvailableResource += sourceGroupData.MaxAvailableResource;
				sourceDataByPriority[i] = sourceGroupData;
			}

			float requiredInputCumulative = 0.0f;
			for (int i = 0; i < sinksByPriority.Length; ++i)
			{
				float requiredInput = 0.0f;
				bool isAdaptible = true;
				foreach (MyResourceSinkComponent sink in sinksByPriority[i])
				{
					requiredInput += sink.RequiredInputByType(typeId);
					isAdaptible = isAdaptible && IsAdaptible(sink);
				}
				sinkDataByPriority[i].RequiredInput = requiredInput;
				sinkDataByPriority[i].IsAdaptible = isAdaptible;

				requiredInputCumulative += requiredInput;
				sinkDataByPriority[i].RequiredInputCumulative = requiredInputCumulative;
			}

            PrepareSinkSourceData(ref typeId, ref sinkSourceData, sinkSourcePairs, stockpilingStorageList, otherStorageList);
            maxAvailableResource += sinkSourceData.Item2.MaxAvailableResource;
		}