using MathNet.Numerics;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ResultAnalyzer
{
    class Program
    {
        static void Main(string[] args)
        {
            double majorityClassPercentage = double.Parse(args[0]);
            int majorityClassAsString = (int)Math.Round(majorityClassPercentage * 100);

            List<string> preqConsistency = new List<string>() { "", "Prequential AUC Consistency (" + majorityClassAsString + "% majority class)", "n, d, AUC(a) < AUC(b) & preqAUC(a) < preqAUC(b), AUC(a) < AUC(b) & preqAUC(a) > preqAUC(b), C" };
            List<string> blockConsistency = new List<string>() { "", "Block AUC Consistency (" + majorityClassAsString + "% majority class)", "n, d, AUC(a) < AUC(b) & blockAUC(a) < blockAUC(b), AUC(a) < AUC(b) & blockAUC(a) > blockAUC(b), C" };
            List<string> preqDiscriminancy = new List<string>() { "", "Prequential AUC Discriminancy (" + majorityClassAsString + "% majority class)", "n, d, AUC(a) < AUC(b) & preqAUC(a) = preqAUC(b), AUC(a) = AUC(b) & preqAUC(a) < preqAUC(b), D" };
            List<string> blockDiscriminancy = new List<string>() { "", "Block AUC Discriminancy (" + majorityClassAsString + "% majority class)", "n, d, AUC(a) < AUC(b) & blockAUC(a) = blockAUC(b), AUC(a) = AUC(b) & blockAUC(a) < blockAUC(b), D" };
            List<string> preqIndifference = new List<string>() { "", "Prequential AUC Indifference (" + majorityClassAsString + "% majority class)", "n, d, AUC(a) = AUC(b) & preqAUC(a) = preqAUC(b) & a!= b, a != b, E" };
            List<string> blockIndifference = new List<string>() { "", "Block AUC Indifference (" + majorityClassAsString + "% majority class)", "n, d, AUC(a) = AUC(b) & blockAUC(a) = blockAUC(b) & a!= b, a != b, E" };

            var preqDiffMatrices = new Dictionary<int, Dictionary<int, Dictionary<double, long>>>();
            var blockDiffMatrices = new Dictionary<int, Dictionary<int, Dictionary<double, long>>>();

            foreach (var file in Directory.GetFiles("..\\..\\..\\..\\Results", "results_i" + majorityClassAsString + "*"))
            {
                using (TextReader reader = File.OpenText(file))
                {
                    string line;
                    string[] columns;
                    string[] fileName = file.Split('_');

                    int datasetSize = int.Parse(fileName[2].Substring(1));
                    int windowSize = int.Parse(fileName[3].Substring(1));

                    if (!preqDiffMatrices.ContainsKey(datasetSize))
                    {
                        preqDiffMatrices.Add(datasetSize, new Dictionary<int, Dictionary<double, long>>());
                        blockDiffMatrices.Add(datasetSize, new Dictionary<int, Dictionary<double, long>>());
                    }

                    preqDiffMatrices[datasetSize].Add(windowSize, new Dictionary<double, long>());
                    blockDiffMatrices[datasetSize].Add(windowSize, new Dictionary<double, long>());

                    double aucA, preqAucA, blockAucA, aucB, preqAucB, blockAucB;
                    long count, totalCount = 0;

                    long preqC = 0, blockC = 0, preqD = 0, blockD = 0, preqE = 0, blockE = 0, preqCNot = 0, blockCNot = 0, preqDNot = 0, blockDNot = 0;
                    double preqDiff, blockDiff;

                    long equalRankingsCount = (long)(Combinatorics.Combinations(datasetSize, (int)Math.Round(datasetSize*majorityClassPercentage))*Combinatorics.Permutations(datasetSize));

                    reader.ReadLine();

                    while ((line = reader.ReadLine()) != null)
                    {
                        columns = line.Split(',');
                        aucA = double.Parse(columns[0]);
                        preqAucA = double.Parse(columns[1]);
                        blockAucA = double.Parse(columns[2]);
                        aucB = double.Parse(columns[3]);
                        preqAucB = double.Parse(columns[4]);
                        blockAucB = double.Parse(columns[5]);
                        count = long.Parse(columns[6]);
                        totalCount += count;

                        //// Consistency
                        if (aucA < aucB && preqAucA < preqAucB)
                        {
                            preqC += count;
                        }

                        if (aucA < aucB && preqAucA > preqAucB)
                        {
                            preqCNot += count;
                        }

                        if (aucA < aucB && blockAucA < blockAucB)
                        {
                            blockC += count;
                        }

                        if (aucA < aucB && blockAucA > blockAucB)
                        {
                            blockCNot += count;
                        }

                        //// Discriminancy
                        if (aucA < aucB && preqAucA == preqAucB)
                        {
                            preqD += count;
                        }

                        if (aucA == aucB && preqAucA < preqAucB)
                        {
                            preqDNot += count;
                        }

                        if (aucA < aucB && blockAucA == blockAucB)
                        {
                            blockD += count;
                        }

                        if (aucA == aucB && blockAucA < blockAucB)
                        {
                            blockDNot += count;
                        }

                        //// Indifference
                        if (aucA == aucB && preqAucA == preqAucB)
                        {
                            preqE += count;
                        }

                        if (aucA == aucB && blockAucA == blockAucB)
                        {
                            blockE += count;
                        }

                        //// Difference
                        preqDiff = preqAucA - aucA;
                        blockDiff = blockAucA - aucA;

                        if (!preqDiffMatrices[datasetSize][windowSize].ContainsKey(preqDiff))
                        {
                            preqDiffMatrices[datasetSize][windowSize].Add(preqDiff, count);
                        }
                        else
                        {
                            preqDiffMatrices[datasetSize][windowSize][preqDiff] += count;
                        }

                        if (!blockDiffMatrices[datasetSize][windowSize].ContainsKey(blockDiff))
                        {
                            blockDiffMatrices[datasetSize][windowSize].Add(blockDiff, count);
                        }
                        else
                        {
                            blockDiffMatrices[datasetSize][windowSize][blockDiff] += count;
                        }
                    }

                    preqConsistency.Add(string.Join(",", datasetSize, windowSize, preqC, preqCNot, (double)preqC / (double)(preqC + preqCNot)));
                    blockConsistency.Add(string.Join(",", datasetSize, windowSize, blockC, blockCNot, (double)blockC / (double)(blockC + blockCNot)));

                    preqDiscriminancy.Add(string.Join(",", datasetSize, windowSize, preqD, preqDNot, preqDNot != 0 ? ((double)preqD / (double)preqDNot).ToString() : "Inf"));
                    blockDiscriminancy.Add(string.Join(",", datasetSize, windowSize, blockD, blockDNot, blockDNot != 0 ? ((double)blockD / (double)blockDNot).ToString() : "Inf"));

                    preqIndifference.Add(string.Join(",", datasetSize, windowSize, preqE - equalRankingsCount, totalCount - equalRankingsCount, (double)(preqE - equalRankingsCount) / (double)(totalCount - equalRankingsCount)));
                    blockIndifference.Add(string.Join(",", datasetSize, windowSize, blockE - equalRankingsCount, totalCount - equalRankingsCount, (double)(blockE - equalRankingsCount) / (double)(totalCount - equalRankingsCount)));
                }
            }

            WriteResultSummaryToFile(majorityClassAsString, preqConsistency, blockConsistency, preqDiscriminancy, blockDiscriminancy, preqIndifference, blockIndifference);

            foreach (var nDictionary in preqDiffMatrices)
            {
                WriteDiffFile("preq_diff_", majorityClassAsString, nDictionary);
            }

            foreach (var nDictionary in blockDiffMatrices)
            {
                WriteDiffFile("block_diff_", majorityClassAsString, nDictionary);
            }
        }

        private static KeyValuePair<int, Dictionary<int, Dictionary<double, long>>> WriteDiffFile(string filePrefix, int majorityClassAsString, KeyValuePair<int, Dictionary<int, Dictionary<double, long>>> nDictionary)
        {
            using (StreamWriter outputFile = new StreamWriter(new BufferedStream(new FileStream(filePrefix + nDictionary.Key + "_i" + majorityClassAsString + ".csv", FileMode.Create))))
            {
                outputFile.WriteLine("# X: Diff, Z:Count, Y:Window");

                foreach (var dDictionary in nDictionary.Value)
                {
                    foreach (var countDictionary in dDictionary.Value)
                    {
                        outputFile.WriteLine(string.Join("\t", countDictionary.Key, countDictionary.Value, dDictionary.Key));
                    }

                    outputFile.WriteLine();
                }
            }
            return nDictionary;
        }

        private static void WriteResultSummaryToFile(int majorityClassAsString, List<string> preqConsistency, List<string> blockConsistency, List<string> preqDiscriminancy, List<string> blockDiscriminancy, List<string> preqIndifference, List<string> blockIndifference)
        {
            using (StreamWriter outputFile = new StreamWriter(new BufferedStream(new FileStream("compiled_results_i" + majorityClassAsString + ".csv", FileMode.Create))))
            {
                foreach (var line in preqConsistency)
                {
                    outputFile.WriteLine(line);
                }

                foreach (var line in blockConsistency)
                {
                    outputFile.WriteLine(line);
                }

                foreach (var line in preqDiscriminancy)
                {
                    outputFile.WriteLine(line);
                }

                foreach (var line in blockDiscriminancy)
                {
                    outputFile.WriteLine(line);
                }

                foreach (var line in preqIndifference)
                {
                    outputFile.WriteLine(line);
                }

                foreach (var line in blockIndifference)
                {
                    outputFile.WriteLine(line);
                }
            }
        }
    }
}
