/// <summary> /// /// Intents: /// /// E = Editable , !E = NotEditable /// R = Removable, !R = NotRemovable /// /// This table shows how conflicts are solved /// on a specific market /// /// (Rule 1, Rule 2) => Result /// (E, R) => E /// (E, !R) => E /// (E, E1) => See below /// (E, !E) => !E /// /// (R, !R) => !R /// (R, R) => R /// (R, !E) => R /// /// (!R, !R) => !R /// (!R, !E) => !E + !R /// /// (!E, !E) => !E /// /// When there are more than one rule that want to edit a specific market, the /// MarketRuleEditIntent.OperationType is considered. /// /// OperationType can be: CHANGE_SELECTIONS (CS), ADD_SELECTIONS (AS), REMOVE_SELECTIONS (RS), CHANGE_DATA (CD) /// /// (CS, AS) => CS + AS (changing operation will be perfomed on the existing selections. Newly added selections will not be edited) /// (CS, RS) => CS /// (CS, CS) => CS + CS (this might cause unexpected results) /// (CS, CD) => CS + CD /// /// (AS, RS) => RS + AS (existing selection will be removed and only after that the new one are added) /// (AS, CD) => AS + CD /// (AS, AS) => AS + AS /// /// (CD, CD) => CD + CD (this might cause unexpected results) /// (CD, RS) => CD + RS /// /// (RS, RS) => RS + RS /// /// </summary> /// <param name="fixture"></param> /// <param name="intents"></param> private void MergeIntents(Fixture fixture, Dictionary <IMarketRule, IMarketRuleResultIntent> intents, bool isRemovalDisabled = false) { Dictionary <Market, bool> toRemove = new Dictionary <Market, bool>(); Dictionary <Market, string> dueRule = new Dictionary <Market, string>(); //this creates empty dictionary the object there is only to generate the type var toAdd = Anonymous.CreateDictionaryWithAnonymousObject(String.Empty, new { Market = new Market(), Intent = new MarketRuleAddIntent(MarketRuleAddIntent.OperationType.ADD_SELECTIONS) }); Dictionary <Market, Dictionary <MarketRuleEditIntent, string> > toedit = new Dictionary <Market, Dictionary <MarketRuleEditIntent, string> >(); foreach (var rule in intents.Keys) { var intent = intents[rule]; /* "toremove" lists all the markets that a rule wants to remove. * Those that will be removed are only those * whose flag is set to true. Those that have the flag * set to false are markets that some rule wanted to * remove but some other rule marked them as not * removable. As we follow a conservative approch * we only remove a market if no other rule specified * otherwise. */ if (!isRemovalDisabled) { foreach (var mkt in intent.RemovableMarkets) { // if it already contains the market, don't do // anything as the flag could be "false" if (!toRemove.ContainsKey(mkt)) { toRemove.Add(mkt, true); dueRule[mkt] = rule.Name; } } } foreach (var mkt in intent.UnRemovableMarkets) { // if it is already present, then // set its flag to false if (toRemove.ContainsKey(mkt)) { toRemove[mkt] = false; } else { toRemove.Add(mkt, false); } } /* For "editable" markets we follow the same * reasoning we do for removing the markets, * except here the flag is the action to perform * or null if a rule marked the market to be * not-editable */ foreach (var mkt in intent.EditedMarkets) { if (!toedit.ContainsKey(mkt)) { toedit.Add(mkt, new Dictionary <MarketRuleEditIntent, string> { { intent.GetEditingAction(mkt), rule.Name } }); } else if (toedit[mkt] != null) { toedit[mkt].Add(intent.GetEditingAction(mkt), rule.Name); } } foreach (var mkt in intent.UnEditableMarkets) { if (toedit.ContainsKey(mkt)) { toedit[mkt] = null; } else { toedit.Add(mkt, null); } } foreach (var mkt in intent.NewMarkets) { if (toAdd.ContainsKey(mkt.Id)) { var firstAddition = toAdd[mkt.Id]; if (ShouldKeepFirstMarket(firstAddition.Intent, intent.GetAddAction(mkt))) { continue; } } toAdd[mkt.Id] = new { Market = mkt, Intent = intent.GetAddAction(mkt) }; dueRule[mkt] = rule.Name; } } // ADD foreach (var addItem in toAdd) { var market = addItem.Value.Market; _logger.DebugFormat("Adding {0} to fixtureId={1} due rule={2}", market, fixture.Id, dueRule[market]); // as we might have changed import details of the market, we need to update the market state var marketState = _currentTransaction[market.Id]; if (marketState != null) { ((IUpdatableMarketState)marketState).Update(market, false); } fixture.Markets.Add(market); } // EDIT MergeEditIntents(fixture, toedit); if (isRemovalDisabled) { return; } // REMOVE foreach (var mkt in toRemove.Keys) { // we need to check that a removable market // wasn't marked as editable or not editable if (toRemove[mkt] && !toedit.ContainsKey(mkt)) { _logger.DebugFormat("Removing {0} of fixtureId={1} due rule={2}", mkt, fixture.Id, dueRule[mkt]); fixture.Markets.Remove(mkt); } } }