public void ProcessEquity( string dateFormat, string equityMembersXml, ITraceMessenger messenger ) { //we can't create the special equity layout without both beginning and ending balances //if there are none, exit early. XmlDocument membersXDoc; ValidateEquityStructure( equityMembersXml, out membersXDoc ); //ensure that all rows/columns/cells are in sync this.SynchronizeGrid(); /** * Consider the possible SQL statement as a model for this process: * * SELECT [Element values by Segment] * FROM [Equity Statement] * GROUP BY [Reporting Period] * ORDER BY [Element Presentation Id] * **/ EquityDataSet dataSet = new EquityDataSet( membersXDoc ); //#1 - this will be our X axis - a set of unique segments and scenarios, minus adjustments and previously reported dataSet.LoadSegmentScenarioColumns( this ); //#2 - this will be the GROUPING for our Y axis - a set of unique calendars dataSet.LoadCalendarColumns( this ); //#3 - Get each type of row role so that we can control the position dataSet.LoadRowTypes( this ); if( !dataSet.PopulateEquityReport( this ) ) throw new IncompleteEquityException( IncompleteEquityException.ErrorType.Incomplete ); //ensure that all rows/columns/cells are in sync dataSet.EquityCandidate.SynchronizeGrid(); dataSet.CleanupEquityColumns(); dataSet.CleanupEquityRows( dateFormat, membersXDoc ); //repair any elements or segments which might not fit the preferred rendering dataSet.EquityCandidate.SynchronizeGrid(); dataSet.AdjustEquityPeriods( this ); if( dataSet.EquityCandidate.Columns.Count == 0 || dataSet.EquityCandidate.Rows.Count == 0 ) throw new IncompleteEquityException( IncompleteEquityException.ErrorType.Incomplete ); this.Columns.Clear(); this.Columns.AddRange( dataSet.EquityCandidate.Columns ); this.Rows.Clear(); this.Rows.AddRange( dataSet.EquityCandidate.Rows ); this.Footnotes.Clear(); this.Footnotes.AddRange( dataSet.EquityCandidate.Footnotes ); //ensure that all rows/columns/cells are in sync this.SynchronizeGrid(); this.PromoteCurrencyCode(); }
private void ProcessRoundingLevel(ITraceMessenger messenger) { bool isRuleEnabled = this.FireRuleProcessing(RulesEngineUtils.ROUNDING_RULE); if (isRuleEnabled) { Dictionary <string, object> contextObjects = new Dictionary <string, object>(); contextObjects.Add("InstanceReport", this); contextObjects.Add("messenger", messenger); builderRules.ProcessRule(RulesEngineUtils.ROUNDING_RULE, contextObjects); this.FireRuleProcessed(RulesEngineUtils.ROUNDING_RULE); } }
private bool ProcessEquitySegments(ITraceMessenger messenger) { bool isRuleEnabled = this.FireRuleProcessing(RulesEngineUtils.EQUITY_STATEMENT_RULE); if (isRuleEnabled) { Dictionary <string, object> contextObjects = new Dictionary <string, object>(); contextObjects.Add("InstanceReport", this); contextObjects.Add("messenger", messenger); IBRERuleResult ruleResult; builderRules.ProcessRule(RulesEngineUtils.EQUITY_STATEMENT_RULE, contextObjects, out ruleResult); this.FireRuleProcessed(RulesEngineUtils.EQUITY_STATEMENT_RULE); Exception outerException = ruleResult.Result as Exception; if (outerException != null) { IncompleteEquityException equityEx = outerException.InnerException as IncompleteEquityException; if (equityEx != null && messenger != null) { switch (equityEx.Type) { case IncompleteEquityException.ErrorType.Incomplete: messenger.TraceError("Error: The equity rendering routine did not create any data for " + this.ReportLongName + "." + Environment.NewLine + "The equity statement will use the basic rendering."); break; case IncompleteEquityException.ErrorType.MissingBeginningBalance: messenger.TraceWarning("Warning: The equity rendering routine was not applied to " + this.ReportLongName + "." + Environment.NewLine + "None of the elements feature the 'periodStartLabel' preferred label role."); break; case IncompleteEquityException.ErrorType.MissingEndingBalance: messenger.TraceWarning("Warning: The equity rendering routine was not applied to " + this.ReportLongName + "." + Environment.NewLine + "None of the elements feature the 'periodEndLabel' preferred label role."); break; } } return(false); } } return(true); }
private void ProcessRounding(ITraceMessenger messenger) { ProcessRoundingLevel(messenger); bool hasMonetary = this.MonetaryRoundingLevel > RoundingLevel.NoRounding; bool hasShares = this.SharesRoundingLevel > RoundingLevel.NoRounding; bool hasPerShare = this.PerShareRoundingLevel > RoundingLevel.NoRounding; if (hasMonetary || hasShares || hasPerShare) { decimal monetaryDivisor = GetRoundingDivisor(this.MonetaryRoundingLevel); decimal sharesDivisor = GetRoundingDivisor(this.SharesRoundingLevel); decimal perSharesDivisor = GetRoundingDivisor(this.PerShareRoundingLevel); decimal exchangeRateDivisor = GetRoundingDivisor(this.ExchangeRateRoundingLevel); //Process rounded values - monetary this.Rows.FindAll(row => row.IsMonetary).ForEach( row => row.ApplyRounding(monetaryDivisor)); //Process rounded values - shares this.Rows.FindAll(row => row.IsShares).ForEach( row => row.ApplyRounding(sharesDivisor)); //Process rounded values - EPS this.Rows.FindAll(row => row.IsEPS).ForEach( row => row.ApplyRounding(perSharesDivisor)); //Process rounded values - Exchange rate this.Rows.FindAll(row => row.IsExchangeRate).ForEach( row => row.ApplyRounding(exchangeRateDivisor)); this.Rows.FindAll(row => row.Unit == 0 || row.Unit > UnitType.StandardUnits).ForEach( row => row.ApplyRounding(1)); } else { this.Rows.ForEach( row => row.Cells.ForEach( cell => cell.RoundedNumericAmount = cell.NumericAmount.ToString() ) ); } }
private bool ProcessEquitySegments( ITraceMessenger messenger ) { bool isRuleEnabled = this.FireRuleProcessing( RulesEngineUtils.EQUITY_STATEMENT_RULE ); if( isRuleEnabled ) { Dictionary<string, object> contextObjects = new Dictionary<string, object>(); contextObjects.Add( "InstanceReport", this ); contextObjects.Add( "messenger", messenger ); IBRERuleResult ruleResult; builderRules.ProcessRule( RulesEngineUtils.EQUITY_STATEMENT_RULE, contextObjects, out ruleResult ); this.FireRuleProcessed( RulesEngineUtils.EQUITY_STATEMENT_RULE ); Exception outerException = ruleResult.Result as Exception; if( outerException != null ) { IncompleteEquityException equityEx = outerException.InnerException as IncompleteEquityException; if( equityEx != null && messenger != null ) { switch( equityEx.Type ) { case IncompleteEquityException.ErrorType.Incomplete: messenger.TraceError( "Error: The equity rendering routine did not create any data for " + this.ReportLongName + "." + Environment.NewLine + "The equity statement will use the basic rendering." ); break; case IncompleteEquityException.ErrorType.MissingBeginningBalance: messenger.TraceWarning( "Warning: The equity rendering routine was not applied to " + this.ReportLongName + "." + Environment.NewLine + "None of the elements feature the 'periodStartLabel' preferred label role." ); break; case IncompleteEquityException.ErrorType.MissingEndingBalance: messenger.TraceWarning( "Warning: The equity rendering routine was not applied to " + this.ReportLongName + "." + Environment.NewLine + "None of the elements feature the 'periodEndLabel' preferred label role." ); break; } } return false; } } return true; }
public void EvaluateRoundingLevels( ITraceMessenger messenger ) { this.HasCustomUnits = false; Dictionary<UnitType, RoundingLevel> selectedRounding = new Dictionary<UnitType, RoundingLevel>(); foreach( int unit in this.UnitDictionary.Keys ) { UnitType ut = (UnitType)unit; selectedRounding[ ut ] = RoundingLevel.UnKnown; List<InstanceReportRow> unitRows = this.Rows.FindAll( row => row.Unit == ut ); if( unitRows.Count == 0 ) continue; if( !this.HasCustomUnits ) { switch( ut ) { case UnitType.EPS: case UnitType.ExchangeRate: case UnitType.Monetary: case UnitType.Shares: break; default: this.HasCustomUnits = true; break; } } foreach( InstanceReportRow row in unitRows ) { if( row.MyPrecision == null ) continue; //Numeric data that is Nill for all values will not have a precision //defined, so we don't want to include these rows in our processing logic if( row.IsNumericDataNil() ) continue; RoundingLevel currentRounding = InstanceUtils.GetRoundingLevelFromPrecision( row.MyPrecision ); selectedRounding[ ut ] = this.SelectRoundingLevel( row.Unit, selectedRounding[ row.Unit ], currentRounding, row.ElementName, messenger ); if( selectedRounding[ ut ] > RoundingLevel.NoRounding ) { double factor = Math.Pow( 10, row.MyPrecision.NumberOfDigits * -1 ); foreach( Cell cell in row.Cells ) { if( cell.IsNil ) continue; if( !cell.HasData || cell.NumericAmount == 0 ) continue; if( Math.Abs( (double)cell.NumericAmount ) < factor ) { selectedRounding[ row.Unit ] = RoundingLevel.NoRounding; break; } } } if( selectedRounding[ row.Unit ] == RoundingLevel.NoRounding ) break; } } this.MonetaryRoundingLevel = RoundingLevel.UnKnown; if( selectedRounding.ContainsKey( UnitType.Monetary ) ) this.MonetaryRoundingLevel = selectedRounding[ UnitType.Monetary ]; this.SharesRoundingLevel = RoundingLevel.UnKnown; if( selectedRounding.ContainsKey( UnitType.Shares ) ) this.SharesRoundingLevel = selectedRounding[ UnitType.Shares ]; this.PerShareRoundingLevel = RoundingLevel.UnKnown; if( selectedRounding.ContainsKey( UnitType.EPS ) ) this.PerShareRoundingLevel = selectedRounding[ UnitType.EPS ]; this.ExchangeRateRoundingLevel = RoundingLevel.UnKnown; if( selectedRounding.ContainsKey( UnitType.ExchangeRate ) ) this.ExchangeRateRoundingLevel = selectedRounding[ UnitType.ExchangeRate ]; }
private RoundingLevel SelectRoundingLevel( UnitType unitType, RoundingLevel unitTypeRounding, RoundingLevel elementRounding, string elementName, ITraceMessenger messenger ) { string typeName = string.Empty; switch( unitType ) { case UnitType.Monetary: typeName = "Monetary"; break; case UnitType.Shares: typeName = "Shares"; break; case UnitType.EPS: typeName = "Per Share"; break; case UnitType.ExchangeRate: typeName = "Exchange Rate"; break; } if( unitTypeRounding == RoundingLevel.UnKnown ) { //If sharesRounding has not been set yet then set the value equal to the //value of the current row return elementRounding; } else if( !AreRoundingLevelsEquivalent( unitTypeRounding, elementRounding ) ) { if( messenger != null ) { string info = "'" + typeName + "' elements on report '" + this.ReportLongName + "' had a mix of different decimal attribute values."; messenger.TraceInformation( info ); } //Make sure the rounding level on the current row matches //the rounding of the previous rows return RoundingLevel.NoRounding; } else if( elementRounding < unitTypeRounding ) { if( elementRounding == RoundingLevel.NoRounding || elementRounding == RoundingLevel.UnKnown ) { if( messenger != null ) { string info = "'" + typeName + "' elements on report '" + this.ReportLongName + "' had a mix of different decimal attribute values."; messenger.TraceInformation( info ); } } //The rounding levels are equivalent, now make sure we use the //"Lowest" equivalent RoundingLevel return elementRounding; } return unitTypeRounding; }
private void ProcessRoundingLevel( ITraceMessenger messenger ) { bool isRuleEnabled = this.FireRuleProcessing( RulesEngineUtils.ROUNDING_RULE ); if( isRuleEnabled ) { Dictionary<string, object> contextObjects = new Dictionary<string, object>(); contextObjects.Add( "InstanceReport", this ); contextObjects.Add( "messenger", messenger ); builderRules.ProcessRule( RulesEngineUtils.ROUNDING_RULE, contextObjects ); this.FireRuleProcessed( RulesEngineUtils.ROUNDING_RULE ); } }
private void ProcessRounding( ITraceMessenger messenger ) { ProcessRoundingLevel( messenger ); bool hasMonetary = this.MonetaryRoundingLevel > RoundingLevel.NoRounding; bool hasShares = this.SharesRoundingLevel > RoundingLevel.NoRounding; bool hasPerShare = this.PerShareRoundingLevel > RoundingLevel.NoRounding; if( hasMonetary || hasShares || hasPerShare ) { decimal monetaryDivisor = GetRoundingDivisor( this.MonetaryRoundingLevel ); decimal sharesDivisor = GetRoundingDivisor( this.SharesRoundingLevel ); decimal perSharesDivisor = GetRoundingDivisor( this.PerShareRoundingLevel ); decimal exchangeRateDivisor = GetRoundingDivisor( this.ExchangeRateRoundingLevel ); //Process rounded values - monetary this.Rows.FindAll( row => row.IsMonetary ).ForEach( row => row.ApplyRounding( monetaryDivisor ) ); //Process rounded values - shares this.Rows.FindAll( row => row.IsShares ).ForEach( row => row.ApplyRounding( sharesDivisor ) ); //Process rounded values - EPS this.Rows.FindAll( row => row.IsEPS ).ForEach( row => row.ApplyRounding( perSharesDivisor ) ); //Process rounded values - Exchange rate this.Rows.FindAll( row => row.IsExchangeRate ).ForEach( row => row.ApplyRounding( exchangeRateDivisor ) ); this.Rows.FindAll( row => row.Unit == 0 || row.Unit > UnitType.StandardUnits ).ForEach( row => row.ApplyRounding( 1 ) ); } else { this.Rows.ForEach( row => row.Cells.ForEach( cell => cell.RoundedNumericAmount = cell.NumericAmount.ToString() ) ); } }
private bool ApplyRowStylesHierarchically( int depth, ref int r, LinkedListNode<CommandIterator> iteratorNode, Stack<CommandIterator> iteratorHierarchy, bool hasUnitCell, ITraceMessenger messenger ) { if( iteratorNode == null ) { InstanceReportRow row = this.Rows[ r ]; row.Level = depth; foreach( CommandIterator ci in iteratorHierarchy ) { if( ci.Style == CommandIterator.StyleType.Grouped ) { row.EmbedRequirements.HideLabel( ci, ci.SelectionString ); } } row.GenerateEmbedLabel(); if( row.Label.Trim() == string.Empty ) ShowLastNonDefaultLabel( depth, iteratorHierarchy, row ); //if( row.Label.Trim() == string.Empty ) //{ // InstanceReportRow prevRow = null; // for( int pr = r - 1; pr > 0; pr-- ) // { // prevRow = this.Rows[ pr ]; // if( IsMemberGroupRow( prevRow ) ) // { // ShowLastNonDefaultLabel( depth, iteratorHierarchy, row ); // break; // } // } //} return true; } CommandIterator iterator = iteratorNode.Value; if( iterator.Style != CommandIterator.StyleType.Grouped || iterator.Selection != CommandIterator.SelectionType.Axis ) { return this.ApplyRowStylesHierarchically( depth, ref r, iteratorNode.Next, iteratorHierarchy, hasUnitCell, messenger ); } Segment defaultMember = this.AxisMemberDefaults.ContainsKey( iterator.AxisName ) ? this.AxisMemberDefaults[ iterator.AxisName ] : null; if( defaultMember == null ) { if( messenger != null ) { //Keyword ‘grouped’ has [...] no impact on a ‘primary’ axis //Keyword ‘grouped’ reverts to the same treatment as ‘compact’ when its axis has no default member. messenger.TraceWarning( "Warning: Default member is missing for '" + iterator.AxisName + "'." + Environment.NewLine + "The keyword ‘grouped’ reverts to the same treatment as ‘compact’ when its axis has no default member." ); } return this.ApplyRowStylesHierarchically( depth, ref r, iteratorNode.Next, iteratorHierarchy, hasUnitCell, messenger ); } KeyValuePair<string, object> memberGroupValue = new KeyValuePair<string, object>(); Dictionary<string, object> matchValues = CreateHierarchicalDictionary( this.Rows[ r ], iteratorHierarchy ); for( ; r < this.Rows.Count; ) { InstanceReportRow row = this.Rows[ r ]; row.Level = depth; KeyValuePair<string, object> member = row.EmbedRequirements.GetMemberKeyValue( iterator ); if( !RowMatchesHierarchy( row, iteratorHierarchy, matchValues ) ) return false; int cmp = Comparer<object>.Default.Compare( memberGroupValue.Value, member.Value ); if( cmp != 0 ) { memberGroupValue = member; InstanceReportRow memberRow = this.CreateStyleRow( depth, iterator, member.Value ); this.Rows.Insert( r++, memberRow ); } iteratorHierarchy.Push( iterator ); if( this.ApplyRowStylesHierarchically( depth + 1, ref r, iteratorNode.Next, iteratorHierarchy, hasUnitCell, messenger ) ) r++; iteratorHierarchy.Pop(); } return true; }
private void ApplyRowStyles( CommandIterator[] rowIterators, ITraceMessenger messenger ) { int r = 0; int depth = 0; Stack<CommandIterator> iteratorHierarchy = new Stack<CommandIterator>(); LinkedList<CommandIterator> iterators = new LinkedList<CommandIterator>( rowIterators ); bool hasUnitCell = Array.Exists( rowIterators, itr => itr.Style == CommandIterator.StyleType.UnitCell ); this.ApplyRowStylesHierarchically( depth, ref r, iterators.First, iteratorHierarchy, hasUnitCell, messenger ); }
//TODO make private public void ProcessIteratorsHierarchically(LinkedList <CommandIterator> iterators, ITraceMessenger messenger) { Stack <CommandIterator> iteratorHierarchy = new Stack <CommandIterator>(); ProcessIteratorsHierarchically(iterators.First, iteratorHierarchy, messenger); }
private RoundingLevel SelectRoundingLevel(UnitType unitType, RoundingLevel unitTypeRounding, RoundingLevel elementRounding, string elementName, ITraceMessenger messenger) { string typeName = string.Empty; switch (unitType) { case UnitType.Monetary: typeName = "Monetary"; break; case UnitType.Shares: typeName = "Shares"; break; case UnitType.EPS: typeName = "Per Share"; break; case UnitType.ExchangeRate: typeName = "Exchange Rate"; break; } if (unitTypeRounding == RoundingLevel.UnKnown) { //If sharesRounding has not been set yet then set the value equal to the //value of the current row return(elementRounding); } else if (!AreRoundingLevelsEquivalent(unitTypeRounding, elementRounding)) { if (messenger != null) { string info = "'" + typeName + "' elements on report '" + this.ReportLongName + "' had a mix of different decimal attribute values."; messenger.TraceInformation(info); } //Make sure the rounding level on the current row matches //the rounding of the previous rows return(RoundingLevel.NoRounding); } else if (elementRounding < unitTypeRounding) { if (elementRounding == RoundingLevel.NoRounding || elementRounding == RoundingLevel.UnKnown) { if (messenger != null) { string info = "'" + typeName + "' elements on report '" + this.ReportLongName + "' had a mix of different decimal attribute values."; messenger.TraceInformation(info); } } //The rounding levels are equivalent, now make sure we use the //"Lowest" equivalent RoundingLevel return(elementRounding); } return(unitTypeRounding); }
public void EvaluateRoundingLevels(ITraceMessenger messenger) { this.HasCustomUnits = false; Dictionary <UnitType, RoundingLevel> selectedRounding = new Dictionary <UnitType, RoundingLevel>(); foreach (int unit in this.UnitDictionary.Keys) { UnitType ut = (UnitType)unit; selectedRounding[ut] = RoundingLevel.UnKnown; List <InstanceReportRow> unitRows = this.Rows.FindAll(row => row.Unit == ut); if (unitRows.Count == 0) { continue; } if (!this.HasCustomUnits) { switch (ut) { case UnitType.EPS: case UnitType.ExchangeRate: case UnitType.Monetary: case UnitType.Shares: break; default: this.HasCustomUnits = true; break; } } foreach (InstanceReportRow row in unitRows) { if (row.MyPrecision == null) { continue; } //Numeric data that is Nill for all values will not have a precision //defined, so we don't want to include these rows in our processing logic if (row.IsNumericDataNil()) { continue; } RoundingLevel currentRounding = InstanceUtils.GetRoundingLevelFromPrecision(row.MyPrecision); selectedRounding[ut] = this.SelectRoundingLevel(row.Unit, selectedRounding[row.Unit], currentRounding, row.ElementName, messenger); if (selectedRounding[ut] > RoundingLevel.NoRounding) { double factor = Math.Pow(10, row.MyPrecision.NumberOfDigits * -1); foreach (Cell cell in row.Cells) { if (cell.IsNil) { continue; } if (!cell.HasData || cell.NumericAmount == 0) { continue; } if (Math.Abs((double)cell.NumericAmount) < factor) { selectedRounding[row.Unit] = RoundingLevel.NoRounding; break; } } } if (selectedRounding[row.Unit] == RoundingLevel.NoRounding) { break; } } } this.MonetaryRoundingLevel = RoundingLevel.UnKnown; if (selectedRounding.ContainsKey(UnitType.Monetary)) { this.MonetaryRoundingLevel = selectedRounding[UnitType.Monetary]; } this.SharesRoundingLevel = RoundingLevel.UnKnown; if (selectedRounding.ContainsKey(UnitType.Shares)) { this.SharesRoundingLevel = selectedRounding[UnitType.Shares]; } this.PerShareRoundingLevel = RoundingLevel.UnKnown; if (selectedRounding.ContainsKey(UnitType.EPS)) { this.PerShareRoundingLevel = selectedRounding[UnitType.EPS]; } this.ExchangeRateRoundingLevel = RoundingLevel.UnKnown; if (selectedRounding.ContainsKey(UnitType.ExchangeRate)) { this.ExchangeRateRoundingLevel = selectedRounding[UnitType.ExchangeRate]; } }
private void ProcessIteratorsHierarchically(LinkedListNode <CommandIterator> iterator, Stack <CommandIterator> iteratorHierarchy, ITraceMessenger messenger) { if (iterator == null) { this.selectionCount++; Dictionary <CommandIterator.IteratorType, List <CommandIterator> > itrs = new Dictionary <CommandIterator.IteratorType, List <CommandIterator> >(); itrs[CommandIterator.IteratorType.Column] = new List <CommandIterator>(); itrs[CommandIterator.IteratorType.Row] = new List <CommandIterator>(); Dictionary <CommandIterator.IteratorType, ColumnRowRequirement> reqs = new Dictionary <CommandIterator.IteratorType, ColumnRowRequirement>(); reqs[CommandIterator.IteratorType.Column] = new ColumnRowRequirement(); reqs[CommandIterator.IteratorType.Row] = new ColumnRowRequirement(); List <CommandIterator> iterators = new List <CommandIterator>(iteratorHierarchy); iterators.Reverse(); foreach (CommandIterator iMember in iterators) { itrs[iMember.Type].Add(iMember); switch (iMember.Selection) { case CommandIterator.SelectionType.Axis: reqs[iMember.Type].Segments.Add((Segment)iMember.TempCurrentMemberValue); break; case CommandIterator.SelectionType.Element: reqs[iMember.Type].ElementRow = (InstanceReportRow)iMember.TempCurrentMemberValue; break; case CommandIterator.SelectionType.Period: reqs[iMember.Type].Period = (CalendarPeriod)iMember.TempCurrentMemberValue; break; case CommandIterator.SelectionType.Unit: reqs[iMember.Type].Unit = (EmbeddedUnitWrapper)iMember.TempCurrentMemberValue; break; } } //if either the rows or columns are missing, this intersection cannot be created - skip it. if (itrs[CommandIterator.IteratorType.Column].Count == 0 || itrs[CommandIterator.IteratorType.Row].Count == 0) { return; } //write the column { ColumnRowRequirement colReqs = reqs[CommandIterator.IteratorType.Column]; colReqs.EmbedCommands = itrs[CommandIterator.IteratorType.Column].ToArray(); bool areSame = false; //Check if the previous column matches this one - this only works because column iterators are first if (this.InstanceReport.Columns.Count > 0) { InstanceReportColumn prevCol = this.InstanceReport.Columns[this.InstanceReport.Columns.Count - 1]; areSame = ColumnRowRequirement.AreSameExceptCurrency(prevCol.EmbedRequirements, colReqs); if (areSame) { //the previous check doesn't check currency - check it here areSame = string.Equals(prevCol.EmbedRequirements.UnitCode, colReqs.UnitCode); } } //If they are the same, skip the new one - we don't want or need duplicates if (!areSame) { InstanceReportColumn col = new InstanceReportColumn(); col.EmbedRequirements = colReqs; col.HasMultiCurrency = this.hasMultiCurrency; if (col.EmbedRequirements.HasSelectionType(CommandIterator.SelectionType.Period)) { col.MCU = new MergedContextUnitsWrapper(); col.MCU.CurrencyCode = string.Empty; col.MCU.CurrencySymbol = string.Empty; col.MCU.contextRef = new ContextProperty(); if (col.EmbedRequirements.Period.PeriodType == Element.PeriodType.instant) { col.MCU.contextRef.PeriodType = Element.PeriodType.instant; col.MCU.contextRef.PeriodStartDate = col.EmbedRequirements.Period.StartDate; } else if (col.EmbedRequirements.Period.PeriodType == Element.PeriodType.duration) { col.MCU.contextRef.PeriodType = Element.PeriodType.duration; col.MCU.contextRef.PeriodStartDate = col.EmbedRequirements.Period.StartDate; col.MCU.contextRef.PeriodEndDate = col.EmbedRequirements.Period.EndDate; } } this.InstanceReport.Columns.Add(col); } } //write the row { ColumnRowRequirement rowReqs = reqs[CommandIterator.IteratorType.Row]; rowReqs.EmbedCommands = itrs[CommandIterator.IteratorType.Row].ToArray(); bool areSame = false; //Check if ANY of the previous rows matches this one... if (this.InstanceReport.Rows.Count > 0) { foreach (InstanceReportRow prevRow in this.InstanceReport.Rows) { areSame = ColumnRowRequirement.AreSameExceptCurrency(prevRow.EmbedRequirements, rowReqs); if (areSame) { //the previous check doesn't check currency - check it here areSame = string.Equals(prevRow.EmbedRequirements.UnitCode, rowReqs.UnitCode); } //let `areSame` fall through, and this row will not get picked up if (areSame) { break; } } } //If they are the same, skip the new one - we don't want or need duplicates if (!areSame) { InstanceReportRow row = new InstanceReportRow(); row.EmbedRequirements = rowReqs; row.HasMultiCurrency = this.hasMultiCurrency; if (row.EmbedRequirements.ElementRow != null) { row.EmbedRequirements.ElementRow.ApplyDataTo(row); } this.InstanceReport.Rows.Add(row); } } } else if (iterator.Value.Selection == CommandIterator.SelectionType.Separator) { iteratorHierarchy.Push(iterator.Value); ProcessIteratorsHierarchically(iterator.Next, iteratorHierarchy, messenger); iteratorHierarchy.Pop(); } else { bool hasDefaultMember; Dictionary <string, object> memberValues = this.GetSelectionMembers(iteratorHierarchy, iterator.Value, out hasDefaultMember); if (memberValues.Count == 0) { if (messenger != null) { messenger.TraceWarning("Warning: The selection of the following command, '" + iterator.Value.SelectionString + "', did not match any values available on this report:" + Environment.NewLine + iterator.Value.ToString()); } return; } switch (iterator.Value.Selection) { case CommandIterator.SelectionType.Axis: if (!hasDefaultMember) { iterator.Value.Style = CommandIterator.StyleType.Compact; } break; case CommandIterator.SelectionType.Unit: if (memberValues.Count > 1) { if (memberValues.ContainsKey(string.Empty) && memberValues.Count == 2) { this.hasMultiCurrency = false; } else { this.hasMultiCurrency = true; } } break; } int valuesFound = 0; foreach (KeyValuePair <string, object> member in memberValues) { if (string.Equals(iterator.Value.Filter, "*") || string.Equals(iterator.Value.Filter, member.Key, StringComparison.CurrentCultureIgnoreCase)) { valuesFound++; iteratorHierarchy.Push(iterator.Value); iterator.Value.TempCurrentMemberKey = member.Key; iterator.Value.TempCurrentMemberValue = member.Value; ProcessIteratorsHierarchically(iterator.Next, iteratorHierarchy, messenger); iterator.Value.TempCurrentMemberKey = null; iterator.Value.TempCurrentMemberValue = null; iteratorHierarchy.Pop(); } } if (valuesFound == 0) { if (messenger != null) { messenger.TraceWarning("Warning: The filter '" + iterator.Value.Filter + "' of following embed command did not match any values available on this report:" + Environment.NewLine + iterator.Value.ToString()); } } } }
public void PopulateEmbeddedReport( InstanceReport baseReport, CommandIterator[] columnIterators, CommandIterator[] rowIterators, ITraceMessenger messenger ) { this.IsMultiCurrency = baseReport.IsMultiCurrency; foreach( InstanceReportColumn col in this.Columns ) { col.GenerateEmbedLabel(); } foreach( InstanceReportRow row in this.Rows ) { row.Cells.Clear(); row.GenerateEmbedLabel(); for( int c = 0; c < this.Columns.Count; c++ ) row.Cells.Add( new Cell() ); } ColumnRowRequirement[,] netCells = new ColumnRowRequirement[ this.Rows.Count, this.Columns.Count ]; for( int r = 0; r < this.Rows.Count; r++ ) { for( int c = 0; c < this.Columns.Count; c++ ) { netCells[ r, c ] = BuildNetCell( this.Rows[ r ].EmbedRequirements, this.Columns[ c ].EmbedRequirements ); } } for( int r = 0; r < this.Rows.Count; r++ ) { for( int c = 0; c < this.Columns.Count; c++ ) { List<InstanceReportColumn> baseColumns = FindBaseColumns( netCells[ r, c ], baseReport.Columns ); if( baseColumns.Count == 0 ) continue; List<InstanceReportRow> baseRows = FindBaseRows( netCells[ r, c ], baseReport.Rows ); if( baseRows.Count == 0 ) continue; bool found = false; foreach( InstanceReportColumn col in baseColumns ) { foreach( InstanceReportRow row in baseRows ) { //CEE: By moving this up, we are using the "strict" logic //Strict: Instead of seeking to the first populated cell // the netCell is expected to point to 1 and only 1 cell //found = true; Cell bCell = row.Cells.Find( cell => cell.Id == col.Id ); if( bCell != null && bCell.HasData ) { Cell clone = (Cell)bCell.Clone(); clone.ShowCurrencySymbol = false; if( !this.IsEquityReport && this.IsMultiCurrency && row.IsMonetary ) { clone.CurrencyCode = col.CurrencyCode; clone.CurrencySymbol = col.CurrencySymbol; clone.IsMonetary = true; } this.Rows[ r ].Cells.RemoveAt( c ); this.Rows[ r ].Cells.Insert( c, clone ); //CEE: By moving this down, we are using the "loose" logic //Loose: Instead of expecting the netCell to point to // 1 and only 1 cell, we seek to the first populated cell found = true; break; } } if( found ) break; } } } //clean up columns this.RemoveEmptyColumns(); if( this.Columns.Count == 0 ) return; //clean up rows this.RemoveEmptyRows(); this.MergeCurrencyDifferences(); this.CheckAndScrubCurrencies(); this.ApplyCustomUnitsEmbedded(); //apply grouped and unitcell this.ApplyRowStyles( rowIterators, messenger ); if( !this.IsEquityReport ) { this.PromoteDefaultMemberGroups(); this.RemoveDefaultMemberHeaders(); } this.RelabelDefaultTotalRow(); this.ApplyUnitCell(); //how many unique periods are on these columns? //if 1, remove the label this.RemoveSingularPeriod(); //if a unit occurs on all columns... // remove it from the columns so it can't get promoted as "shared" // save it so it can be added last string currencyLabel = this.RemoveSharedCurrency(); //if a label occurs on all columns, shift it to the header this.PromoteSharedLabels(); //if there is a shared currency label, add it last if( !string.IsNullOrEmpty( currencyLabel ) ) this.ReportName += Environment.NewLine + currencyLabel; //copy over the footnotes this.PromoteFootnotes( baseReport ); this.SynchronizeGrid(); this.ProcessColumnHeaders(); }
public void ProcessEquity(string dateFormat, string equityMembersXml, ITraceMessenger messenger) { //we can't create the special equity layout without both beginning and ending balances //if there are none, exit early. XmlDocument membersXDoc; ValidateEquityStructure(equityMembersXml, out membersXDoc); //ensure that all rows/columns/cells are in sync this.SynchronizeGrid(); /** * Consider the possible SQL statement as a model for this process: * * SELECT [Element values by Segment] * FROM [Equity Statement] * GROUP BY [Reporting Period] * ORDER BY [Element Presentation Id] * **/ EquityDataSet dataSet = new EquityDataSet(membersXDoc); //#1 - this will be our X axis - a set of unique segments and scenarios, minus adjustments and previously reported dataSet.LoadSegmentScenarioColumns(this); //#2 - this will be the GROUPING for our Y axis - a set of unique calendars dataSet.LoadCalendarColumns(this); //#3 - Get each type of row role so that we can control the position dataSet.LoadRowTypes(this); if (!dataSet.PopulateEquityReport(this)) { throw new IncompleteEquityException(IncompleteEquityException.ErrorType.Incomplete); } //ensure that all rows/columns/cells are in sync dataSet.EquityCandidate.SynchronizeGrid(); dataSet.CleanupEquityColumns(); dataSet.CleanupEquityRows(dateFormat, membersXDoc); //repair any elements or segments which might not fit the preferred rendering dataSet.EquityCandidate.SynchronizeGrid(); dataSet.AdjustEquityPeriods(this); if (dataSet.EquityCandidate.Columns.Count == 0 || dataSet.EquityCandidate.Rows.Count == 0) { throw new IncompleteEquityException(IncompleteEquityException.ErrorType.Incomplete); } this.Columns.Clear(); this.Columns.AddRange(dataSet.EquityCandidate.Columns); this.Rows.Clear(); this.Rows.AddRange(dataSet.EquityCandidate.Rows); this.Footnotes.Clear(); this.Footnotes.AddRange(dataSet.EquityCandidate.Footnotes); //ensure that all rows/columns/cells are in sync this.SynchronizeGrid(); this.PromoteCurrencyCode(); }
/// <summary> /// Process the embed commands within the given <paramref /// name="baseReport"/>. /// </summary> /// <param name="baseReport">The <see cref="InstanceReport"/> in which /// to process embed commands.</param> /// <param name="messenger">An <see cref="ITraceMessenger"/> on which /// to log messages encountered during processing commands.</param> /// <returns></returns> public bool ProcessEmbedCommands(InstanceReport baseReport, ITraceMessenger messenger) { //Fill this in in case bar charts need to generate values if (this.IsBarChartReport()) { //TODO: audit this... foreach (InstanceReportRow row in baseReport.Rows) { row.EmbedRequirements = new ColumnRowRequirement { ElementRow = (InstanceReportRow)row.Clone() }; } } if (ReportUtils.IsShowElements(baseReport.ReportLongName)) { this.InstanceReport = baseReport; return(false); } try { this.AddDefaultIterators(baseReport); if (this.RowIterators.Length == 0) { messenger.TraceWarning("Warning: The embed commands for '" + baseReport.ReportLongName + "' are incomplete." + Environment.NewLine + "No 'row' commands were found."); this.InstanceReport = baseReport; return(false); } if (this.ColumnIterators.Length == 0) { messenger.TraceWarning("Warning: The embed commands for '" + baseReport.ReportLongName + "' are incomplete." + Environment.NewLine + "No 'column' commands were found."); this.InstanceReport = baseReport; return(false); } //Console.WriteLine( "Building Embedded Report: " + baseReport.ReportLongName ); foreach (CommandIterator itr in this.selections.Values) { //Console.WriteLine( "\t"+ itr.ToString() ); } this.IsTransposed = ReportUtils.IsTransposeReport(baseReport.ReportLongName); if (this.IsTransposed) { this.TransposeIterators(); } this.baseReport = baseReport; this.InstanceReport = new InstanceReport(); this.InstanceReport.AxisByPresentation = this.baseReport.AxisByPresentation; this.InstanceReport.AxisMembersByPresentation = this.baseReport.AxisMembersByPresentation; this.InstanceReport.AxisMemberDefaults = this.baseReport.AxisMemberDefaults; this.InstanceReport.IsEquityReport = this.baseReport.IsEquityReport; LinkedList <CommandIterator> iterators = new LinkedList <CommandIterator>(this.ColumnIterators); foreach (CommandIterator itr in this.RowIterators) { iterators.AddLast(itr); } DateTime start = DateTime.Now; { this.selectionCount = 0; this.ProcessIteratorsHierarchically(iterators, messenger); TimeSpan ts = DateTime.Now - start; //Console.WriteLine( this.selectionCount + " selections performed in " + ts.ToString() ); //because the rows might come in out of order, we simply need to correct the order at the last moment. this.SortByCommands(this.RowIterators); } if (this.InstanceReport.Rows.Count == 0 || this.InstanceReport.Columns.Count == 0) { this.InstanceReport = baseReport; return(false); } this.InstanceReport.PopulateEmbeddedReport(this.baseReport, this.ColumnIterators, this.RowIterators, messenger); if (this.InstanceReport.Rows.Count == 0 || this.InstanceReport.Columns.Count == 0) { this.InstanceReport = baseReport; this.baseReport = null; //a little cleanup return(false); } else { this.baseReport = null; //a little cleanup return(true); } } finally { this.InstanceReport.ReportLongName = baseReport.ReportLongName; this.InstanceReport.ShowElementNames = ReportUtils.IsShowElements(baseReport.ReportLongName); this.InstanceReport.RemoveLabelColumn(); #if DEBUG this.InstanceReport.Footnotes.Add( new Footnote(99, this.EmbedInstruction.Replace("<", "<").Replace(">", ">")) ); #endif } }