using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Threading;

namespace S04_Projet
{
    public class Display
    {
        /// <summary>
        /// Liste des opérations possibles
        /// </summary>
        public enum Operation
        {
            Rotate90,
            Rotate180,
            Rotate270,
            GrayScaleLinear,
            GrayScaleLuminosity,
            Save
        }

        /// <summary>
        /// Charge l'image 
        /// </summary>
        /// <returns>Retourne l'objet contenant l'image chargée</returns>
        public static MyImage LoadImage()
        {
            string path;
            bool validPath = false;
            byte[] file = new byte[0];
            do
            {
                Console.WriteLine("Veuillez saisir le nom du fichier à traiter :");
                path = Console.ReadLine();
                try
                {
                    file = File.ReadAllBytes(path);
                }
                catch (Exception e)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("Une erreur est survenue : " + e.Message);
                    Console.ForegroundColor = ConsoleColor.White;
                }
                if (file.Length != 0) validPath = true;
            } while (!validPath);

            Console.Clear();
            MyImageThread myImageThread = new MyImageThread(file);
            Thread imageThread = new Thread(new ThreadStart(myImageThread.ThreadLoop));

            imageThread.Start();

            Console.Write("Traitement en cours de l'image.");
            while (imageThread.IsAlive)
            {
                Thread.Sleep(250);
                Console.Write(".");
            }
            Console.Clear();

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Image chargée en {0}ms\n", myImageThread.loadTime);
            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine(myImageThread.image.toString());
            Console.ForegroundColor = ConsoleColor.White;

            return myImageThread.image;
        }

        /// <summary>
        /// Demande quelles opérations l'on souhaite effectuer sur l'image
        /// </summary>
        /// <returns>Retourne le type d'opération souhaitée</returns>
        public static Operation AskForOperation()
        {
            int choosenItem = 0;
            string[] menuItems = new string[]
            {
                "Rotation à 90°",
                "Rotation à 180°",
                "Rotation à 270°",
                "Passage à une image en nuances de gris (linéairement)",
                "Passage à une image en nuances de gris (luminosité)",
                "Sauvegarder"
            };

            for (int i = 0; i < menuItems.Length; i++)
            {
                Console.WriteLine(((choosenItem == i) ? ">> " : "   ") + menuItems[i]);
            }


            ConsoleKeyInfo key;

            do
            {
                key = Console.ReadKey();
                Console.SetCursorPosition(0, 9 + choosenItem);
                Console.Write("  ");
                if(key.Key == ConsoleKey.DownArrow)
                {
                    choosenItem++;
                    if (choosenItem == menuItems.Length) choosenItem = 0;
                }
                else if(key.Key == ConsoleKey.UpArrow)
                {
                    choosenItem--;
                    if (choosenItem == -1) choosenItem = menuItems.Length - 1;
                }
                Console.SetCursorPosition(0, 9 + choosenItem);
                Console.Write(">>");
            } while (key.Key != ConsoleKey.Escape && key.Key != ConsoleKey.Enter);

            if (key.Key == ConsoleKey.Escape) Environment.Exit(0);

            return (Operation)choosenItem;
        }

        /// <summary>
        /// Effectue l'opération demandée sur l'image passée en paramètres
        /// </summary>
        /// <param name="ope">Opération désirée</param>
        /// <param name="img">Image sur laquelle effectuer l'opération</param>
        /// <returns>Image avec l'opération effectuée dessus</returns>
        public static MyImage PerformOperation(Operation ope, MyImage img)
        {
            MyImage output = null;
            Console.Clear();

            if (ope == Operation.Rotate90) output = img.Rotate90();
            else if (ope == Operation.Rotate180) output = img.Rotate180();
            else if (ope == Operation.Rotate270) output = img.Rotate270();
            else if(ope == Operation.GrayScaleLinear || ope == Operation.GrayScaleLuminosity)
            {
                bool retry = false;
                int input;

                do
                {
                    if (retry) Console.WriteLine("Saisie incorrecte");
                    Console.WriteLine("Veuillez saisir le nombre de nuances de gris désirées (entre 2 et 255)");

                    retry = !int.TryParse(Console.ReadLine(), out input);
                } while (retry && input >= 2 && input <= 255);

                if (ope == Operation.GrayScaleLinear) output = img.ToGrayScale((byte)input, MyImage.grayFilterType.LINEAR);
                else if (ope == Operation.GrayScaleLuminosity) output = img.ToGrayScale((byte)input, MyImage.grayFilterType.LUMINOSITY);
            }
            else if(ope == Operation.Save)
            {
                string path;
                bool anotherTry = false;

                do
                {
                    if (anotherTry) Console.WriteLine("Le format du chemin est incorrect");
                    Console.WriteLine("Veuillez saisir le nom du fichier en sortie");
                    path = Console.ReadLine();
                    if (!path.EndsWith(".bmp")) path += ".bmp";
                } while (anotherTry = !Uri.IsWellFormedUriString(path, UriKind.RelativeOrAbsolute));

                img.Save(path);
            }
            else
            {
                throw new Exception("Opération non reconnue");
            }

            return output;
        }
    }
}
