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

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

        private static 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é)",
                "Rétrécissement de l'image",
                "Désactiver le multithreading",
                "Sauvegarder"
        };

        public static long elapsedTime;
        public static string lastOperationMessage;
        public static string fileInfos;

        /// <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();
            Thread waitingThread = new Thread(new ThreadStart(WaitingScreen));

            Stopwatch sw = new Stopwatch();
            sw.Start();

            waitingThread.Start();
            MyImage image = new MyImage(path);
            waitingThread.Abort();
            
            sw.Stop();
            Console.Clear();

            elapsedTime = sw.ElapsedMilliseconds;
            lastOperationMessage = "Image chargée en " + elapsedTime + "ms";
            fileInfos = image.ToString();

            return 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()
        {
            Console.Clear();
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(lastOperationMessage);
            Console.WriteLine();
            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine(fileInfos);
            Console.ForegroundColor = ConsoleColor.White;

            int choosenItem = 0;

            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;
            Stopwatch sw = new Stopwatch();
            Console.Clear();

            sw.Start();
            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);

                sw.Restart();
                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.Shrink)
            {
                bool retry = false;
                int input;

                do
                {
                    if (retry) Console.WriteLine("Saisie incorrecte");
                    Console.WriteLine("Veuillez saisir le facteur de rétrécissement souhaité");

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

                sw.Restart();
                output = img.Shrink(input);
            }
            else if(ope == Operation.SwitchMultiThreading)
            {
                Program.MULTITHREADING = !Program.MULTITHREADING;
                if (Program.MULTITHREADING)
                {
                    lastOperationMessage = "Multithreading activé avec succès";
                    menuItems[(int)ope] = "Désactiver le multithreading";
                }
                else
                {
                    lastOperationMessage = "Multithreading désactivé avec succès";
                    menuItems[(int)ope] = "Activer le multithreading";
                }
                elapsedTime = 0;
                return img;
            }
            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));

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

            sw.Stop();
            elapsedTime = sw.ElapsedMilliseconds;
            lastOperationMessage = String.Format("Opération {0}, effectuée avec succès en {1}ms", ope, elapsedTime);
            fileInfos = (output != null) ? output.ToString() : "";

            return output;
        }

        /// <summary>
        /// Ecran d'attente
        /// </summary>
        public static void WaitingScreen()
        {
            Console.Write("Traitement de l'image en cours");
            while(true)
            {
                Console.Write(".");
                Thread.Sleep(250);
            }
        }
    }
}
