/// Author : Maxime Rohmer
/// Date : 01/06/2023
/// File : OcrImageTests.cs
/// Brief : Class that is here to test the working principle of the OCR. Its not really unit test because we dont test a single class
/// Version : Alpha 1.0

using Microsoft.VisualStudio.TestTools.UnitTesting;
using TrackTrends;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Drawing;

namespace TrackTrends.Tests
{
    [TestClass()]
    public class OcrImageTests
    {
        /// <summary>
        /// Checks that the OCR on LapTimes is working.
        /// </summary>
        [TestMethod()]
        public void LapTimeOCR_Test()
        {
            string directory = @"./../../TestImages/LapTimes/";
            foreach (string file in Directory.GetFiles(directory))
            {
                Bitmap image = (Bitmap)Image.FromFile(file);
                DriverLapTimeWindow lapTimeWindow = new DriverLapTimeWindow(image, new Rectangle(0, 0, image.Width, image.Height), true);
                string[] paths = file.Split('/');
                string fileName = paths[paths.Length - 1];
                fileName = fileName.Replace(".png", "");

                int timeMS = (int)lapTimeWindow.DecodePng();
                string time = Reader.ConvertMsToTime(timeMS);

                string[] checkDigits = fileName.Split('_');
                string[] digitsToCheck = time.Split(':');

                //The ConvertMSToTime will always return three chars so we need to make the checkDigits be also three chars
                while (checkDigits.Length != 3)
                    checkDigits = new[] { "0" }.Concat(checkDigits).ToArray();

                for (int i = 0; i < checkDigits.Length; i++)
                {
                    Assert.AreEqual(checkDigits[i], digitsToCheck[i]);
                }
            }
        }
        /// <summary>
        /// Checks that the Driver Position is well detected using the OCR
        /// </summary>
        [TestMethod()]
        public void PositionOCR_Test()
        {
            string directory = @"./../../TestImages/Positions/";
            foreach (string file in Directory.GetFiles(directory))
            {
                Bitmap image = (Bitmap)Image.FromFile(file);
                DriverPositionWindow posWindow = new DriverPositionWindow(image, new Rectangle(0, 0, image.Width, image.Height), true);
                string[] paths = file.Split('/');
                string fileName = paths[paths.Length - 1];
                fileName = fileName.Replace(".png", "");

                int foundPos = (int)posWindow.DecodePng();

                Assert.AreEqual(Convert.ToInt32(fileName), foundPos);
            }
        }
        /// <summary>
        /// Checks that the tyres are correctly recognized using OCR
        /// </summary>
        [TestMethod()]
        public void TyresOCR_Test()
        {
            string directory = @"./../../TestImages/Tyres/";
            foreach (string file in Directory.GetFiles(directory))
            {
                Bitmap image = (Bitmap)Image.FromFile(file);
                DriverTyresWindow tyreWindow = new DriverTyresWindow(image, new Rectangle(0, 0, image.Width, image.Height), true);
                string[] paths = file.Split('/');
                string fileName = paths[paths.Length - 1];
                fileName = fileName.Replace(".png", "");

                string[] fileInfos = fileName.Split('_');
                string expectedType = fileInfos[0];
                int expectedLap = Convert.ToInt32(fileInfos[1]);

                Tyre foundTyre = (Tyre)tyreWindow.DecodePng();

                switch (foundTyre.Coumpound)
                {
                    case Tyre.Type.Soft:
                        Assert.AreEqual("SOFT",expectedType.ToUpper());
                        break;
                    case Tyre.Type.Inter:
                        Assert.AreEqual("INTER", expectedType.ToUpper());
                        break;
                    case Tyre.Type.Hard:
                        Assert.AreEqual("HARD", expectedType.ToUpper());
                        break;
                    case Tyre.Type.Wet:
                        Assert.AreEqual("WET", expectedType.ToUpper());
                        break;
                    case Tyre.Type.Medium:
                        Assert.AreEqual("MEDIUM", expectedType.ToUpper());
                        break;
                }
                Assert.AreEqual(expectedLap,foundTyre.NumberOfLaps);
            }
        }
        /// <summary>
        /// Checks that the Gap to the leader is well decoded from the image using the OCR
        /// </summary>
        [TestMethod()]
        public void GapToLeaderOCR_Test()
        {
            string directory = @"./../../TestImages/Gaps/";
            foreach (string file in Directory.GetFiles(directory))
            {
                Bitmap image = (Bitmap)Image.FromFile(file);
                DriverGapToLeaderWindow gapsWindow = new DriverGapToLeaderWindow(image, new Rectangle(0, 0, image.Width, image.Height), true);
                string[] paths = file.Split('/');
                string fileName = paths[paths.Length - 1];
                fileName = fileName.Replace(".png", "");

                int timeMS = (int)gapsWindow.DecodePng();
                string time = Reader.ConvertMsToTime(timeMS);

                string[] checkDigits = fileName.Split('_');
                string[] digitsToCheck = time.Split(':');

                if (time == "0:00:000")
                {
                    Assert.AreEqual(0, Convert.ToInt32(checkDigits[0]));
                }
                else
                {
                    //The ConvertMSToTime will always return three chars so we need to make the checkDigits be also three chars
                    while (checkDigits.Length != 3)
                        checkDigits = new[] { "0" }.Concat(checkDigits).ToArray();

                    for (int i = 0; i < checkDigits.Length; i++)
                    {
                        //We need to convert to int first because sometimes we have "08" and "8" and in string its not the same but in int it is
                        Assert.AreEqual(Convert.ToInt32(checkDigits[i]), Convert.ToInt32(digitsToCheck[i]));
                    }
                }
            }
        }
        /// <summary>
        /// Checks that the DRS window is well recognized as open of closed
        /// </summary>
        [TestMethod()]
        public void DRS_OCR_Test()
        {
            string directory = @"./../../TestImages/DRS/";
            DirectoryInfo directoryInfo = new DirectoryInfo(directory);
            Bitmap falseExemple = (Bitmap)Image.FromFile(directory + "False.png");
            Bitmap trueExemple = (Bitmap)Image.FromFile(directory + "True.png");

            DriverDrsWindow falseDRS = new DriverDrsWindow(falseExemple, new Rectangle(0, 0, falseExemple.Width, falseExemple.Height), true);
            DriverDrsWindow trueDRS = new DriverDrsWindow(trueExemple, new Rectangle(0, 0, trueExemple.Width, trueExemple.Height), true);

            bool falseResult = (bool)falseDRS.DecodePng();
            bool trueResult = (bool)trueDRS.DecodePng();

            Assert.IsFalse(falseResult);
            Assert.IsTrue(trueResult);
        }
        /// <summary>
        /// Checks that the driver names are recognized correctly
        /// </summary>
        [TestMethod()]
        public void DriverNameOCR_Test()
        {
            string directory = @"./../../TestImages/Names/";
            foreach (string file in Directory.GetFiles(directory))
            {
                Bitmap image = (Bitmap)Image.FromFile(file);
                DriverNameWindow nameWindow = new DriverNameWindow(image, new Rectangle(0, 0, image.Width, image.Height), true);
                string[] paths = file.Split('/');
                string fileName = paths[paths.Length - 1];
                fileName = fileName.Replace(".png", "");

                List<string> driverList = new List<String>();

                driverList.Add("Albon");
                driverList.Add("Alonso");
                driverList.Add("Bottas");
                driverList.Add("De Vries");
                driverList.Add("Gasly");
                driverList.Add("Hamilton");
                driverList.Add("Hulkenberg");
                driverList.Add("Leclerc");
                driverList.Add("Magnussen");
                driverList.Add("Norris");
                driverList.Add("Ocon");
                driverList.Add("Perez");
                driverList.Add("Piastri");
                driverList.Add("Russel");
                driverList.Add("Sainz");
                driverList.Add("Sargeant");
                driverList.Add("Stroll");
                driverList.Add("Tsunoda");
                driverList.Add("Verstappen");
                driverList.Add("Zhou");

                string foundName = (string)nameWindow.DecodePng(driverList);
                //We only compare without the case because it does not really matter
                //We remove the '_' from the file name for cases like "De Vries" wich obviously would be "De_Vries.png" as filename
                fileName = fileName.Replace('_', ' ');

                Assert.AreEqual(fileName.ToUpper(),foundName.ToUpper());
            }
        }
        /// <summary>
        /// Checks that the Sectors are correctly decoded using the OCR
        /// </summary>
        [TestMethod()]
        public void SectorOCR_Test()
        {
            string directory = @"./../../TestImages/Sectors/";
            foreach (string file in Directory.GetFiles(directory))
            {
                Bitmap image = (Bitmap)Image.FromFile(file);
                DriverSectorWindow sectorsWindow = new DriverSectorWindow(image, new Rectangle(0, 0, image.Width, image.Height), 1, true);
                string[] paths = file.Split('/');
                string fileName = paths[paths.Length - 1];
                fileName = fileName.Replace(".png", "");

                int timeMS = (int)sectorsWindow.DecodePng();
                string time = Reader.ConvertMsToTime(timeMS);

                string[] checkDigits = fileName.Split('_');
                string[] digitsToCheck = time.Split(':');

                if (time == "0:00:000")
                {
                    Assert.AreEqual(0, Convert.ToInt32(checkDigits[0]));
                }
                else
                {
                    //The ConvertMSToTime will always return three chars so we need to make the checkDigits be also three chars
                    while (checkDigits.Length != 3)
                        checkDigits = new[] { "0" }.Concat(checkDigits).ToArray();

                    for (int i = 0; i < checkDigits.Length; i++)
                    {
                        //We need to convert to int first because sometimes we have "08" and "8" and in string its not the same but in int it is
                        Assert.AreEqual(Convert.ToInt32(checkDigits[i]), Convert.ToInt32(digitsToCheck[i]));
                    }
                }
            }
        }
    }
}