/// Author : Maxime Rohmer
/// Date : 09/06/2023
/// File : DriverTyresWindow.cs
/// Brief : Window containing infos about a driver's tyre
/// Version : Beta 1.0

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace TrackTrends
{
    public class DriverTyresWindow:Window
    {
        private static Random rnd = new Random();
        //Those are the colors I found but you can change them if they change in the future like in 2019
        public static Color SOFT_TYRE_COLOR = Color.FromArgb(0xff, 0x00, 0x00);
        public static Color MEDIUM_TYRE_COLOR = Color.FromArgb(0xf5, 0xbf, 0x00);
        public static Color HARD_TYRE_COLOR = Color.FromArgb(0xa4, 0xa5, 0xa8);
        public static Color INTER_TYRE_COLOR = Color.FromArgb(0x00, 0xa4, 0x2e);
        public static Color WET_TYRE_COLOR = Color.FromArgb(0x27, 0x60, 0xa6);
        public static Color EMPTY_COLOR = Color.FromArgb(0x20, 0x20, 0x20);

        public DriverTyresWindow(Bitmap image, Rectangle bounds, bool generateEngine = true) : base(image, bounds,generateEngine)
        {
            Name = "Tyres";
        }
        /// <summary>
        /// This will decode the content of the image
        /// </summary>
        /// <returns>And object containing what was on the image</returns>
        public override object DecodePng()
        {
            return GetTyreInfos();
        }
        /// <summary>
        /// Method that will decode whats on the image and return the tyre infos it could manage to recover
        /// </summary>
        /// <returns>A tyre object containing tyre infos</returns>
        private Tyre GetTyreInfos()
        {
            //DEBUG
            //WindowImage.Save("./Tyre/raw_"+rnd.Next(0,99999)+".png");

            Bitmap tyreZone = GetSmallBitmapFromBigOne(WindowImage, FindTyreZone());
            Tyre.Type type = Tyre.Type.Undefined;
            type = GetTyreTypeFromColor(OcrImage.GetAvgColorFromBitmap(tyreZone));
            int laps = -1;

            string number = GetStringFromPng(tyreZone, Engine, "0123456789", OcrImage.WindowType.Tyre);
            try
            {
                laps = Convert.ToInt32(number);
            }
            catch
            {
                //We could not convert the number so its a letter so its 0 laps old
                laps = 0;
            }

            //71 is the most laps an f1 race is ever going to have (mexico) so any more would be considered as bad (and remember you cant go trough a full race without making at least one pitstop)
            if (laps > 75)
                laps = 0;

            return new Tyre(type, laps);
        }
        /// <summary>
        /// Finds where the important part of the image is
        /// </summary>
        /// <returns>A rectangle containing position and dimensions of the important part of the image</returns>
        private Rectangle FindTyreZone()
        {
            Bitmap bmp = WindowImage;
            int currentPosition = bmp.Width;
            int height = bmp.Height / 2;
            Color limitColor = Color.FromArgb(0x50, 0x50, 0x50);
            Color currentColor = Color.FromArgb(0, 0, 0);
                                                                                                 //25F
            Size newWindowSize = new Size(bmp.Height - Convert.ToInt32((float)bmp.Height / 100f * 25f), bmp.Height - Convert.ToInt32((float)bmp.Height / 100f * 35f)); 

            while (currentColor.R <= limitColor.R && currentColor.G <= limitColor.G && currentColor.B <= limitColor.B && currentPosition > 0)
            {
                currentPosition--;
                currentColor = bmp.GetPixel(currentPosition, height);
            }

            //Its here to let the new window include a little bit of the right 
            int CorrectedX = currentPosition - (newWindowSize.Width) + Convert.ToInt32((float)newWindowSize.Width / 100f * 10f);
            int CorrectedY = Convert.ToInt32((float)newWindowSize.Height / 100f * 35f);
            if (CorrectedX <= 0)
                return new Rectangle(0, 0, newWindowSize.Width, newWindowSize.Height);

            return new Rectangle(CorrectedX, CorrectedY, newWindowSize.Width, newWindowSize.Height);
        }
        //This method has been created with the help of chatGPT
        /// <summary>
        /// Methods that compares a list of colors to see wich is the closest from the input color and decide wich tyre type it is
        /// </summary>
        /// <param name="inputColor">The color that you found</param>
        /// <returns>The tyre type</returns>
        public Tyre.Type GetTyreTypeFromColor(Color inputColor)
        {
            Tyre.Type type = Tyre.Type.Undefined;
            List<Color> colors = new List<Color>();
            //dont forget that if for some reason someday F1 adds a new Tyre type you will need to add it in the constants but also here in the list
            //You will also need to add it below in the Tyre object's enum and add an if in the end of this method
            colors.Add(SOFT_TYRE_COLOR);
            colors.Add(MEDIUM_TYRE_COLOR);
            colors.Add(HARD_TYRE_COLOR);
            colors.Add(INTER_TYRE_COLOR);
            colors.Add(WET_TYRE_COLOR);
            colors.Add(EMPTY_COLOR);

            Color closestColor = colors[0];
            int closestDistance = int.MaxValue;
            foreach (Color color in colors)
            {
                int distance = Math.Abs(color.R - inputColor.R) + Math.Abs(color.G - inputColor.G) + Math.Abs(color.B - inputColor.B);
                if (distance < closestDistance)
                {
                    closestColor = color;
                    closestDistance = distance;
                }
            }

            //We cant use a switch as the colors cant be constants ...
            if (closestColor == SOFT_TYRE_COLOR)
                type = Tyre.Type.Soft;
            if (closestColor == MEDIUM_TYRE_COLOR)
                type = Tyre.Type.Medium;
            if (closestColor == HARD_TYRE_COLOR)
                type = Tyre.Type.Hard;
            if (closestColor == INTER_TYRE_COLOR)
                type = Tyre.Type.Inter;
            if (closestColor == WET_TYRE_COLOR)
                type = Tyre.Type.Wet;
            if (closestColor == EMPTY_COLOR)
                return Tyre.Type.Undefined;

            return type;
        }
    }
}
