/// <summary>
        /// Build the description of the orders needed to fulfill an <see cref="InvestorInstruction" /> which
        /// is aggregated within an <see cref="InstructionExecutionContext" /> instance.
        /// </summary>
        /// <param name="instructionExecutionContext">The <see cref="InstructionExecutionContext" /> instance that aggregates the <see cref="InvestorInstruction" />.</param>
        /// <returns>
        /// An <see cref="OrderBasket" /> containing all the orders to be routed in order to fulfill the initial <see cref="InvestorInstruction" />.
        /// </returns>
        public OrderBasket Solve(InstructionExecutionContext instructionExecutionContext)
        {
            var ordersDescription = new List<OrderDescription>();

            // Checks liquidities available to weighted average for execution
            int remainingQuantityToBeExecuted = instructionExecutionContext.Quantity;

            var requestedPrice = instructionExecutionContext.Price;

            var validMarkets = this.GetValidMarkets(requestedPrice);
            var availableQuantityOnMarkets = this.ComputeAvailableQuantityForThisPrice(validMarkets);

            if (availableQuantityOnMarkets == 0)
            {
                return new OrderBasket(new List<OrderDescription>());    
            }

            var ratio = remainingQuantityToBeExecuted / (decimal)availableQuantityOnMarkets;

            // ReSharper disable once LoopCanBeConvertedToQuery
            foreach (var marketInfo in validMarkets)
            {
                var convertedMarketQuantity = Math.Round(marketInfo.Market.SellQuantity * ratio, 2, MidpointRounding.AwayFromZero);
                var quantityToExecute = Convert.ToInt32(convertedMarketQuantity);

                if (quantityToExecute > 0)
                {
                    ordersDescription.Add(new OrderDescription(marketInfo.Market, instructionExecutionContext.Way, quantityToExecute, requestedPrice, instructionExecutionContext.AllowPartialExecution));
                }
            }

            return new OrderBasket(ordersDescription);
        }
        public void Route(InvestorInstructionDto investorInstructionDto)
        {
            // 1. Digest Investment instructions
            // 2. Prepare order book (solver)
            // 3. Send and monitor
            // 4. Feedback investor

            var investorInstruction = this.CreateInvestorInstruction(investorInstructionDto.UniqueIdentifier, null, investorInstructionDto.Way, investorInstructionDto.Quantity, investorInstructionDto.Price, investorInstructionDto.AllowPartialExecution, investorInstructionDto.GoodTill);

            var executionState = new InstructionExecutionContext(investorInstruction);

            this.RouteImpl(investorInstruction, executionState);
        }
        //// TODO: remove investor instruction as arg here?
        private void RouteImpl(InvestorInstruction investorInstruction, InstructionExecutionContext instructionExecutionContext)
        {
            var solver = new MarketSweepSolver(this.marketSnapshotProvider);

            var orderBasket = solver.Solve(instructionExecutionContext);
            
            EventHandler<DealExecutedEventArgs> handler = (executedOrder, args) => instructionExecutionContext.Executed(args.Quantity);
            EventHandler<OrderFailedEventArgs> failHandler = (s, failure) => this.SendOrderFailed(investorInstruction, failure, instructionExecutionContext);

            investorInstruction.Executed += (sender, e) => this.investorInstruction_Executed(sender, e);

            orderBasket.OrderExecuted += handler;
            orderBasket.OrderFailed += failHandler;

            orderBasket.Send();

            orderBasket.OrderExecuted -= handler;
            orderBasket.OrderFailed -= failHandler;
        }
        private void SendOrderFailed(InvestorInstruction investorInstruction, OrderFailedEventArgs reason, InstructionExecutionContext instructionExecutionContext)
        {
            this.marketSnapshotProvider.MarketFailed(reason.Market);

            if (investorInstruction.GoodTill != null && 
                investorInstruction.GoodTill > DateTime.Now && 
                instructionExecutionContext.Quantity > 0)
            {
                // retries
                this.RouteImpl(investorInstruction, instructionExecutionContext);
            }
            else
            {
                Action<string> failureCallback;
                if (this.failureCallbacks.TryGetValue(investorInstruction.IdentifierDto, out failureCallback))
                {
                    failureCallback(reason.Reason);
                }
            }
        }