//Apply interaction on lowest level
        public void InteractionOnLowestTermLevel(ILevelState levelstate, ILevelFinancialInfo finTermInfo, int levelsize)
        {
            if (!finTermInfo.HasPercentDed)
            {
                float[] codeDed     = finTermInfo.GetCodedMinDeds();
                float[] codedMaxDed = finTermInfo.GetCodedMaxDeds();
                float[] codeLim     = finTermInfo.GetCodedLimits();

                int[] franchiseMinDedFlag = finTermInfo.GetFranchiseMinDedFlags();
                int[] franchiseMaxDedFlag = finTermInfo.GetFranchiseMaxDedFlags();

                float[] subjectloss = levelstate.GetSubjectLoss();
                float[] excess      = levelstate.GetExcess();
                float[] ded         = levelstate.GetDeductible();
                float[] recov       = levelstate.GetRecoverable();

                if (!finTermInfo.HasMaxDed)
                {
                    for (int j = 0; j < levelsize; j++)
                    {
                        // Main aplication of financial terms, and interaction...

                        //float tempDed = (subjectloss[j] <= codeDed[j]) ? subjectloss[j] : codeDed[j] * franchiseMinDedFlag[j];
                        ded[j]    = (subjectloss[j] <= codeDed[j]) ? subjectloss[j] : codeDed[j] * franchiseMinDedFlag[j];
                        ded[j]    = Math.Min(subjectloss[j] - excess[j], ded[j]);
                        excess[j] = Math.Max(0, subjectloss[j] - codeLim[j] - ded[j]);
                        excess[j] = Math.Min(subjectloss[j] - ded[j], excess[j]);
                        recov[j]  = subjectloss[j] - excess[j] - ded[j];
                    }
                }
                else
                {
                    for (int j = 0; j < levelsize; j++)
                    {
                        // Main aplication of financial terms, and interaction...

                        ded[j]    = (subjectloss[j] <= codeDed[j]) ? subjectloss[j] : codeDed[j] * franchiseMinDedFlag[j];
                        ded[j]    = Math.Min(ded[j], Math.Min(subjectloss[j], codedMaxDed[j]));
                        ded[j]    = Math.Min(subjectloss[j] - excess[j], ded[j]);
                        excess[j] = Math.Max(0, subjectloss[j] - codeLim[j] - ded[j]);
                        excess[j] = Math.Min(subjectloss[j] - ded[j], excess[j]);
                        recov[j]  = subjectloss[j] - excess[j] - ded[j];
                    }
                }
            }
            else
            {
                throw new NotSupportedException("Cannot currently handle percent deductibles");
            }
        }
        public void AggregateLevel(ILevelState childLevel, ISimpleLevelState childARITELevel, ILevelState parentLevel, ILevelNodeAggInfo childAggInfo, ILevelAtomicRITEInfo aRITEINfo, Stopwatch aggregation1)
        {
            int             childlevelsize = childAggInfo.NumOfNodes;
            IAggPatternInfo patterinInfo   = childAggInfo.GetNodePatternInfo();

            int[] partitions = childAggInfo.GetNodeAggregationPartitions();

            IAggPatternInfo aRITEpatterinInfo = aRITEINfo.GetARitePatternInfo();

            int[] aRITEpartitions = aRITEINfo.GetARiteAggregationPartitions();

            float[]       nodeFactors  = childLevel.GetFactors();      //childAggInfo.GetSimpleLevelInfo().Factors;
            float[]       riteFactor   = childARITELevel.GetFactors(); //aRITEINfo.GetaRiteInfo().Factors;
            FactorPattern nodeFPattern = childAggInfo.GetSimpleLevelInfo().ApplyFactorPattern;
            FactorPattern riteFPattern = aRITEINfo.GetaRiteInfo().ApplyFactorPattern;

            float[] childrenDed;
            float[] childrenExcess;

            //pre-process to multiply the Factor array
            if (nodeFPattern == FactorPattern.AllOnes)
            {
                childrenDed    = childLevel.GetDeductible();
                childrenExcess = childLevel.GetExcess();
            }
            else
            {
                childrenDed    = childLevel.GetDeductible().Zip(nodeFactors, (x1, x2) => x1 * x2).ToArray();
                childrenExcess = childLevel.GetExcess().Zip(nodeFactors, (x1, x2) => x1 * x2).ToArray();
            }

            //Aggregate D and X (ARITEs do not have D, X)
            switch (patterinInfo.GetLevelRelation)
            {
            case AggRelationship.OneToOne:
                Array.Copy(childrenDed, parentLevel.GetDeductible(), childlevelsize);
                Array.Copy(childrenExcess, parentLevel.GetExcess(), childlevelsize);
                break;

            case AggRelationship.RepeatedPattern:
                int groupSize = patterinInfo.RepeatedPartitionSize;
                SumArrayByPattern(childrenDed, parentLevel.GetDeductible(), groupSize);
                SumArrayByPattern(childrenExcess, parentLevel.GetExcess(), groupSize);
                break;

            case AggRelationship.NoPattern:
                SumArrayByPartition(childrenDed, parentLevel.GetDeductible(), partitions);

                aggregation1.Start();
                SumArrayByPartition(childrenExcess, parentLevel.GetExcess(), partitions);
                aggregation1.Stop();
                break;
            }

            // Aggregate S in case with Atomic Rites & Aggregate R for allocation
            float[] childrenNodeSubLoss;
            float[] childrenRiteSubLoss;
            float[] childrenRecov;

            if (nodeFPattern == FactorPattern.AllOnes)
            {
                childrenNodeSubLoss = childLevel.GetSubjectLoss();
                childrenRecov       = childLevel.GetRecoverable();
            }
            else
            {
                childrenNodeSubLoss = childLevel.GetSubjectLoss().Zip(nodeFactors, (x1, x2) => x1 * x2).ToArray();
                childrenRecov       = childLevel.GetRecoverable().Zip(nodeFactors, (x1, x2) => x1 * x2).ToArray();
            }

            if (aRITEINfo.HasAtomicRITEs)
            {
                //pre-process
                if (riteFPattern == FactorPattern.AllOnes)
                {
                    childrenRiteSubLoss = childARITELevel.GetSubjectLoss();
                }
                else
                {
                    childrenRiteSubLoss = childARITELevel.GetSubjectLoss().Zip(riteFactor, (x1, x2) => x1 * x2).ToArray();
                }

                if (aRITEpatterinInfo.GetLevelRelation == AggRelationship.NoPattern ||
                    patterinInfo.GetLevelRelation == AggRelationship.NoPattern)
                {
                    SumTwoArrayByPartition(childrenNodeSubLoss, childrenRiteSubLoss, parentLevel.GetSubjectLoss(), partitions, aRITEpartitions);
                    SumTwoArrayByPartition(childrenRecov, childrenRiteSubLoss, parentLevel.GetRecoverable(), partitions, aRITEpartitions);
                }
                else
                {
                    int termgroupsize;
                    int aRITEgroupsize;

                    switch (patterinInfo.GetLevelRelation)
                    {
                    case AggRelationship.OneToOne:
                        termgroupsize = 1;
                        break;

                    case AggRelationship.RepeatedPattern:
                        termgroupsize = aRITEpatterinInfo.RepeatedPartitionSize;
                        break;

                    default:
                        throw new NotSupportedException("The Level realtion " + patterinInfo.GetLevelRelation + " is currently not supported");
                    }

                    switch (aRITEpatterinInfo.GetLevelRelation)
                    {
                    case AggRelationship.OneToOne:
                        aRITEgroupsize = 1;
                        break;

                    case AggRelationship.RepeatedPattern:
                        aRITEgroupsize = aRITEpatterinInfo.RepeatedPartitionSize;
                        break;

                    default:
                        throw new NotSupportedException("The Level realtion " + patterinInfo.GetLevelRelation + " is currently not supported");
                    }

                    SumTwoArrayByPatternNew(childrenNodeSubLoss, childrenRiteSubLoss, parentLevel.GetSubjectLoss(), termgroupsize, aRITEgroupsize);
                    SumTwoArrayByPatternNew(childrenRecov, childrenRiteSubLoss, parentLevel.GetRecoverable(), termgroupsize, aRITEgroupsize);
                }
            }
            // Aggregate S in case with no Atomic Rites
            else
            {
                switch (patterinInfo.GetLevelRelation)
                {
                case AggRelationship.OneToOne:
                    Array.Copy(childrenNodeSubLoss, parentLevel.GetSubjectLoss(), childlevelsize);
                    Array.Copy(childrenRecov, parentLevel.GetRecoverable(), childlevelsize);
                    break;

                case AggRelationship.RepeatedPattern:
                    int groupSize = patterinInfo.RepeatedPartitionSize;
                    SumArrayByPattern(childrenNodeSubLoss, parentLevel.GetSubjectLoss(), groupSize);
                    SumArrayByPattern(childrenRecov, parentLevel.GetRecoverable(), groupSize);
                    break;

                case AggRelationship.NoPattern:
                    SumArrayByPartition(childrenNodeSubLoss, parentLevel.GetSubjectLoss(), partitions);
                    SumArrayByPartition(childrenRecov, parentLevel.GetRecoverable(), partitions);
                    break;
                }
            }
        }
        //!SublimitIsNetofDed && !DedisAbsorbable
        //Apply interaction on term levels
        public void ApplyInteraction(ILevelState levelstate, ILevelFinancialInfo finTermInfo, int levelsize)
        {
            if (!finTermInfo.HasMaxDed && !finTermInfo.HasPercentDed)
            {
                float[] codeDed     = finTermInfo.GetCodedMinDeds();
                float[] codedMaxDed = finTermInfo.GetCodedMaxDeds();
                float[] codeLim     = finTermInfo.GetCodedLimits();

                int[] franchiseMinDedFlag = finTermInfo.GetFranchiseMinDedFlags();
                int[] franchiseMaxDedFlag = finTermInfo.GetFranchiseMaxDedFlags();

                float[] subjectloss = levelstate.GetSubjectLoss();
                float[] excess      = levelstate.GetExcess();
                float[] ded         = levelstate.GetDeductible();
                float[] recov       = levelstate.GetRecoverable();
                float[] rRatio      = levelstate.GetAllocateRatioR();
                float[] dRatio      = levelstate.GetAllocateRatioD();
                //Nina:
                float dedFromBelow;
                float recoveFromBelow;
                float deltaD;

                if (!finTermInfo.HasMaxDed)
                {
                    for (int j = 0; j < levelsize; j++)
                    {
                        //Save ded and recoverable from below
                        dedFromBelow    = ded[j];
                        recoveFromBelow = recov[j];
                        //Nina: Recoverable from below need to be added since when dont aggregate R during aggregation?
                        //recoveFromBelow = ChildrenLevelState.GetRecoverable().Sum() + ChildrenAriteLevelState.GetRecoverable().Sum();

                        /////Initial All lines

                        //Main aplication of financial terms, and interaction...
                        excess[j] = Math.Max(excess[j], Math.Max(0, subjectloss[j] - codeLim[j]));
                        excess[j] = Math.Min(subjectloss[j] - ded[j], excess[j]);
                        //excess[j] = Math.Max(excess[j], (subjectloss[j] - codeLim[j]));
                        float tempDed = (subjectloss[j] <= codeDed[j]) ? subjectloss[j] : codeDed[j] * franchiseMinDedFlag[j];
                        ded[j]   = Math.Max(ded[j], tempDed);
                        ded[j]   = Math.Min(subjectloss[j] - excess[j], ded[j]);
                        recov[j] = subjectloss[j] - excess[j] - ded[j];

                        //Allocation Ratio Calculation
                        deltaD = ded[j] - dedFromBelow;
                        if (deltaD >= 0)
                        {
                            rRatio[j] = (recoveFromBelow == 0) ? 0 : (1 - deltaD / recoveFromBelow);
                            dRatio[j] = 1;
                        }
                        else
                        {
                            rRatio[j] = 1;
                            dRatio[j] = (dedFromBelow == 0) ? 0 : (1 + deltaD / dedFromBelow);
                        }
                    }
                }
                else
                {
                    for (int j = 0; j < levelsize; j++)
                    {
                        //Save ded and recoverable from below
                        dedFromBelow    = ded[j];
                        recoveFromBelow = recov[j];
                        //Nina: Recoverable from below need to be added since when dont aggregate R during aggregation?
                        //recoveFromBelow = ChildrenLevelState.GetRecoverable().Sum() + ChildrenAriteLevelState.GetRecoverable().Sum();

                        /////Initial All lines

                        //Main aplication of financial terms, and interaction...
                        excess[j] = Math.Max(excess[j], Math.Max(0, subjectloss[j] - codeLim[j]));
                        excess[j] = Math.Min(subjectloss[j] - ded[j], excess[j]);
                        //excess[j] = Math.Max(excess[j], (subjectloss[j] - codeLim[j]));
                        float tempDed = (subjectloss[j] <= codeDed[j]) ? subjectloss[j] : codeDed[j] * franchiseMinDedFlag[j];
                        ded[j]   = Math.Max(ded[j], tempDed);
                        ded[j]   = Math.Min(ded[j], Math.Min(subjectloss[j], codedMaxDed[j]));
                        ded[j]   = Math.Min(subjectloss[j] - excess[j], ded[j]);
                        recov[j] = subjectloss[j] - excess[j] - ded[j];

                        //Allocation Ratio Calculation
                        deltaD = ded[j] - dedFromBelow;
                        if (deltaD >= 0)
                        {
                            rRatio[j] = (recoveFromBelow == 0) ? 0 : (1 - deltaD / recoveFromBelow);
                            dRatio[j] = 1;
                        }
                        else
                        {
                            rRatio[j] = 1;
                            dRatio[j] = (dedFromBelow == 0) ? 0 : (1 + deltaD / dedFromBelow);
                        }
                    }
                }
            }
            else
            {
                throw new NotSupportedException("Cannot currently handle percent deductibles");
            }
        }