public OutputData Solve(InputData input, Settings settings, BackgroundWorker worker)
        {
            Random rand = new Random();
            OutputData result = new OutputData();

            //for (int i = 0; i < 200; i++)
            //{
            //    IterationBlock block = new IterationBlock
            //    {
            //        ProgressionCount = rand.Next(10),
            //        RegressionCount = rand.Next(10)
            //    };

            //    for (int j = 0; j < 10; j++)
            //    {
            //        block.Values.Add(new Iteration(j)
            //        {
            //            Cost = Math.Sin(i * (double)j * 10)
            //        });
            //    }

            //    worker.ReportProgress(0, block);
            //    result.Iterations.Add(block);

            //    if (worker.CancellationPending == true)
            //    {
            //        return null;
            //    }

            //    System.Threading.Thread.Sleep(50);
            //}


            //result.TotalCost = 10;
            //result.Solution = new List<int> { 4, 5, 6, 3, 2, 1, 0, 6, 5, 4, 3, 3, 4, 234, 234, 32, 34, 4, 43, 4 };

            return result;
        }
        public OutputData Solve(InputData input, Settings settings, BackgroundWorker worker)
        {
            // TODO
            // Gdy problem zadany bez stacji (fuel cap = 0), to coś sie psuje
            OutputData result = new OutputData();

            Operation operation = null;

            switch (settings.Operation)
            {
                case OperationType.Operation1:
                    operation = Operation1;
                    break;
                case OperationType.Operation2:
                    operation = Operation2;
                    break;
            }

            List<double> iterationBlockCosts = new List<double>(); 

            double currentCost = 0;
            double newCost = 0;
            double subtract = 0;

            int numIterations = settings.NumIterations;
            double temperature = settings.StartingTemperature;

            List<int> currentSolution = null;
            
            List<int> currentSolutionWithPetrolPlaces = new List<int>();
            if (input.FuelCapacity > 0)
            {
                int counter = 0;
                do
                {
                    if (counter > Math.Pow(input.NumPlaces, 2))
                    {
                        result.State = OutputState.NoSolution;
                        return result;
                    }
                    currentSolution = GetStartingSolution(input);
                    currentSolution.CopyListTo(currentSolutionWithPetrolPlaces);
                    counter++;
                }
                while (!PutPetrolPlaces(input, currentSolutionWithPetrolPlaces));
            }
            else
            {
                currentSolution = GetStartingSolution(input);
                currentSolution.CopyListTo(currentSolutionWithPetrolPlaces);
            }

            List<int> newSolution = new List<int>(new int[currentSolution.Count]);
            List<int> newSolutionWithPetrolPlaces = new List<int>();
            currentSolution.CopyListTo(newSolution);

            int currentSolutionCountMinusOne = currentSolutionWithPetrolPlaces.Count() - 1;
            for (int i = 0; i < currentSolutionCountMinusOne; i++)
            {
                //CurrentCost = CurrentCost + input.Places[CurrentSolution[i]][CurrentSolution[i + 1]];
                currentCost += input.Places[currentSolutionWithPetrolPlaces[i]][currentSolutionWithPetrolPlaces[i + 1]];
            }

            while (temperature > settings.EndingTemperature)
            {
                IterationBlock block = new IterationBlock();
                double 
                    minCost = currentCost, 
                    maxCost = currentCost;

                for (int i = 0; i < numIterations; i++)
                {
                    if (input.FuelCapacity > 0)
                    {
                        do
                        {
                            operation(currentSolution, newSolution);
                            newSolution.CopyListTo(newSolutionWithPetrolPlaces);
                        }
                        while (!PutPetrolPlaces(input, newSolutionWithPetrolPlaces));
                    }
                    else
                    {
                        operation(currentSolution, newSolution);
                        newSolution.CopyListTo(newSolutionWithPetrolPlaces);
                    }

                    newCost = 0;

                    int newSolutionCountMinusOne = newSolutionWithPetrolPlaces.Count() - 1;
                    for (int j = 0; j < newSolutionCountMinusOne; j++)
                    {
                        newCost += input.Places[newSolutionWithPetrolPlaces[j]][newSolutionWithPetrolPlaces[j + 1]];
                    }

                    subtract = newCost - currentCost;
                    double randomik = rand.NextDouble();
                    double zmienna = Math.Exp((-1) * (subtract / temperature));
                    if (subtract <= 0 || subtract > 0 && zmienna > randomik)
                    {
                        currentCost = newCost;

                        if (currentCost > maxCost)
                            maxCost = currentCost;
                        else if (currentCost < minCost)
                            minCost = currentCost;

                        newSolution.CopyListTo(currentSolution);
                        newSolutionWithPetrolPlaces.CopyListTo(currentSolutionWithPetrolPlaces);

                        if (subtract <= 0)
                            block.ProgressionCount++;
                        else
                            block.RegressionCount++;
                    }

                    //block.Values.Add(currentCost);
                    iterationBlockCosts.Add(currentCost);
                    if (iterationBlockCosts.Count == (int)(numIterations / settings.PointsPerIterationBlock))
                    {
                        block.Values.Add(iterationBlockCosts.ReduceCollectionToValue(x => x.Average()));
                        iterationBlockCosts.Clear();
                    }

                    if (worker.CancellationPending == true)
                    {
                        result.State = OutputState.Cancelled;
                        return result;
                    }
                }

                temperature *= settings.CoolingCoefficient;
                block.CurrentTemperature = temperature;
                numIterations = (int)((double)numIterations * settings.NumIterationsMultiplier);
                //block.Values = iterationBlockCosts.ReduceCollection(
                //    settings.PointsPerIterationBlock,
                //    x => x.Average()).ToList();
                block.Minimum = minCost;
                block.Maximum = maxCost;

                iterationBlockCosts.Clear();

                worker.ReportProgress(0, block);
                result.Iterations.Add(block);
            }

            result.Solution = currentSolutionWithPetrolPlaces;
            result.TotalCost = currentCost;

            result.State = OutputState.Done;
            return result;
        }
 public SolutionData(InputData input, OutputData output)
 {
     Input = input;
     Output = output;
 }
        //private IEnumerable<double> ReduceCollection(IEnumerable<double> collection, int desiredCount, Func<IEnumerable<double>,double> reducer)
        //{
        //    List<double> result = new List<double>();
        //    int elementsPerBlock = collection.Count() / desiredCount;
        //    int count = 0;
        //    List<double> container = new List<double>();

        //    while (count < collection.Count())
        //    {
        //        //double sum = 0;
        //        int i = 0;
        //        for (i = 0; i < elementsPerBlock && count < collection.Count(); i++, count++)
        //        {
        //            //sum += collection.ElementAt(count)
        //            container.Add(collection.ElementAt(count));
        //        }

        //        //result.Add(sum / (double)i);
        //        result.Add(reducer(container));
        //        container.Clear();
        //    }
        //    return result;
        //}

        private void PlotOutput(OutputData outputData)
        {
            for (int count = 0; count < outputData.Iterations.Count; count++)
            {
                IterationBlock iterationBlock = outputData.Iterations[count];

                OxyPlot.Series.ScatterSeries costSeries = VM.GraphPlotModel.Series[0] as OxyPlot.Series.ScatterSeries;
                OxyPlot.Series.StairStepSeries progressionSeries = VM.GraphPlotModel.Series[1] as OxyPlot.Series.StairStepSeries;
                OxyPlot.Series.StairStepSeries regressionSeries = VM.GraphPlotModel.Series[2] as OxyPlot.Series.StairStepSeries;

                //List<double> costs = iterationBlock.Values.Select(x => x.Cost).ToList();
                //List<double> reducedCosts = ReduceCollection(costs, DISPLAYED_COSTS_PER_BLOCK, x => x.Average()).ToList();

                for (int i = 0; i < iterationBlock.Values.Count; i++)
                {
                    costSeries.Points.Add(new ScatterPoint(
                        /*iteration.IterationNumber*/ 
                        (double)count + (double)i / (double)iterationBlock.Values.Count, 
                        iterationBlock.Values[i], 
                        LINES_THICKNESS));
                }
                progressionSeries.Points.Add(new ScatterPoint(count, iterationBlock.ProgressionCount));
                regressionSeries.Points.Add(new ScatterPoint(count, iterationBlock.RegressionCount));

                VM.TotalProgressions += iterationBlock.ProgressionCount;
                VM.TotalRegressions += iterationBlock.RegressionCount;
            }

            VM.GraphPlotModel.RefreshPlot(false);
        }