﻿using System;
using System.IO;
using System.Text;

namespace Db1K.PriorityQueueBenchmark
{
    class Program
    {
        static void Main(string[] args)
        {
            string filePath = Path.Combine(Directory.GetCurrentDirectory(), args[0], "PriorityQueueBenchmarks.md");
            Console.WriteLine("Writing file: {0}", filePath);

            const int queueSize = 10000;

            var blueRaja = new BlueRajaPriorityQueueBenchmark(queueSize);
            var deathBy1000Cuts = new Db1KCutsPriorityQueueBenchmark(queueSize);

            const int operationsPerRun = 10000000;
            const int seedCount = 10;
            const int seedItemCount = 100; // The number of items to put on queue when length == 0.
            const int runsPerSeed = 5;
            int seed = 248628474;

            Console.WriteLine();
            Console.WriteLine("Running benchmark...");
            Console.WriteLine("SeedCount = {0}, RunsPerSeed = {1}, OperationsPerRun = {2:n0}", seedCount, runsPerSeed, operationsPerRun);
            Console.WriteLine();

            var fileContents = new StringBuilder();

            fileContents.AppendLine("Priority Queue Benchmark Scores");
            fileContents.AppendLine("===============================");
            fileContents.AppendLine();

            var statsBuilder = new StringBuilder();

            var startTime = DateTime.Now;

            double blueRajaTotalMilliseconds = 0;
            double db1KCutsTotalMilliseconds = 0;

            for (int seedNumber = 1; seedNumber <= seedCount; seedNumber++)
            {
                double blueRajaSeedMilliseconds = 0;
                double db1KCutsSeedMilliseconds = 0;

                Console.WriteLine("Seed number: {0} ({1})", seedNumber, seed);
                for (int run = 1; run <= runsPerSeed; run++)
                {
                    Console.Write("{0}{1}", run != 1 ? ", " : "", run);

                    var runTimeBlueRaja = blueRaja.RunBenchmark(seed, seedItemCount, operationsPerRun);
                    blueRajaSeedMilliseconds += runTimeBlueRaja.TotalMilliseconds;

                    var runTimeDb1KCuts = deathBy1000Cuts.RunBenchmark(seed, seedItemCount, operationsPerRun);
                    db1KCutsSeedMilliseconds += runTimeDb1KCuts.TotalMilliseconds;
                }
                Console.WriteLine();

                seed += 5;

                blueRajaTotalMilliseconds += blueRajaSeedMilliseconds;
                db1KCutsTotalMilliseconds += db1KCutsSeedMilliseconds;

                TimeSpan blueRajaAverage = TimeSpan.FromMilliseconds(blueRajaSeedMilliseconds / runsPerSeed);
                TimeSpan db1KCutsAverage = TimeSpan.FromMilliseconds(db1KCutsSeedMilliseconds / runsPerSeed);

                Console.WriteLine("BlueRaja: AverageTime = {0}", blueRajaAverage);
                Console.WriteLine("DeathBy1000Cuts: AverageTime = {0}", db1KCutsAverage);
                Console.WriteLine();

                statsBuilder.AppendLine("###Seed number : " + seedNumber + " (Seed = " + seed + ")");
                statsBuilder.AppendLine("\r\n| Implementation  | Average Time |");
                statsBuilder.AppendLine("|:----------------|-------------:|");
                statsBuilder.AppendFormat("| BlueRaja | {0} \r\n", blueRajaAverage);
                statsBuilder.AppendFormat("| DeathBy1000Cuts | {0} \r\n\r\n", db1KCutsAverage);
            }

            TimeSpan db1KCutsOverallAverage = TimeSpan.FromMilliseconds(db1KCutsTotalMilliseconds / (seedCount * runsPerSeed));
            TimeSpan blueRajaOverallAverage = TimeSpan.FromMilliseconds(blueRajaTotalMilliseconds / (seedCount * runsPerSeed));

            Console.WriteLine("BlueRaja: AverageTime = {0}", blueRajaOverallAverage);
            Console.WriteLine("DeathBy1000Cuts: AverageTime = {0}", db1KCutsOverallAverage);

            var endTime = DateTime.Now;
            var runDuration = endTime - startTime;

            fileContents.AppendLine("###Run started: " + startTime + ", ended: " + endTime + "<br>");
            fileContents.AppendLine("###Duration: " + runDuration);
            fileContents.AppendLine();

            fileContents.AppendLine("**Number of seeded runs: " + seedCount + "**<br>");
            fileContents.AppendLine("**Runs per seed: " + runsPerSeed + "**<br>");
            fileContents.AppendLine("**Operations per run: " + operationsPerRun.ToString("N0") + "**<br>");
            fileContents.AppendLine();

            fileContents.AppendLine("##Total run count: " + (seedItemCount * runsPerSeed));
            fileContents.AppendLine("* **BlueRaja: " + blueRajaOverallAverage + "**");
            fileContents.AppendLine("* **DeathBy1000Cuts: " + db1KCutsOverallAverage + "**");

            fileContents.Append(statsBuilder);

            File.WriteAllText(filePath, fileContents.ToString());
        }
    }
}
