using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

/*
 * Autor        : Pablu
 * Email        : pablu23@gmx.de
 * Erstelldatum : 25.06.2020
 * Last change  : 25.06.2020
 * GitHub       : https://github.com/Pablu23/16x16Converter
 * 
 * TODO         : Add comments, bug fixes. Add Background removal. Finish Project.
 * 
 */

namespace ConvertTo16x16
{
    class Count
    {
        public int Argb { get; set; }
        public Point Position { get; set; }
        public int Anzahl { get; set; }

        public Count(int Anzahl)
        {
            this.Anzahl = Anzahl;
        }

        public Count(int Argb, Point Position, int Anzahl)
        {
            this.Argb = Argb;
            this.Position = Position;
            this.Anzahl = Anzahl;
        }

    }

    class Settings
    {
        public string FileDir { get; set; }
        public int PixelAnzahl { get; set; }
        public bool RmBackground { get; set; }
        public Color BackgroundCol { get; set; }
    }

    class Program
    {

        public static Settings settings = new Settings();

        static void mainMenu()
        {
            while (true)
            {
                Console.WriteLine("[S]tart");
                Console.WriteLine("S[e]ttings");
                Console.WriteLine("E[n]d");

                string input = Console.ReadLine();

                switch (input.ToLower())
                {
                    case "s":
                        if (settings == null || settings.FileDir == null || settings.PixelAnzahl < 16)
                        {
                            Console.WriteLine("You have to edit some Settings before continuing.");
                            Console.ReadKey(true);
                            break;
                        }
                        Console.Clear();
                        Start();
                        break;
                    case "e":
                        Console.Clear();
                        Settings();
                        break;
                    case "n":
                        Environment.Exit(0);
                        break;

                    default:
                        Console.WriteLine("Input not accepted");
                        Console.ReadKey(true);
                        Console.Clear();
                        break;

                }

                Console.Clear();

            }
        }

        static void Main(string[] args)
        {
            LoadJson();
            mainMenu();
        }

        public static void Settings()
        {
            Console.Write("Geben sie den Pfad an : ");
            if (settings.FileDir != null) {
                Console.WriteLine($"\nPfad : {settings.FileDir}");
                Console.SetCursorPosition(25, Console.CursorTop - 2);
            }
            settings.FileDir = Console.ReadLine();
            Console.Write("\nGeben sie an Wieviele Pixel sie wollen (Empfohlen: 16 | 32) : ");
            if (settings.PixelAnzahl > 15)
            {
                Console.WriteLine($"\nPixel Anzahl : {settings.PixelAnzahl}");
                Console.SetCursorPosition(62, Console.CursorTop - 2);
            }
            settings.PixelAnzahl = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine("\nGeben sie an Ob eine Hintergrundfarbe ignoriert werden soll : ");
            Console.WriteLine("[T]rue");
            Console.WriteLine("[F]alse");
            if (settings.PixelAnzahl > 15)
            {
                Console.WriteLine($"Remove Background : {settings.RmBackground}");
                Console.WriteLine($"Color : {settings.BackgroundCol}");
                Console.SetCursorPosition(63, Console.CursorTop - 5);
            }
            
            string input = Console.ReadLine();
            switch (input.ToLower())
            {
                case "t":
                    settings.RmBackground = true;
                    Console.WriteLine("Which Color should be removed");
                    Console.Write("Red : ");
                    int red = Convert.ToInt32(Console.ReadLine());
                    Console.Write("Green : ");
                    int green = Convert.ToInt32(Console.ReadLine());
                    Console.Write("Blue : ");
                    int blue = Convert.ToInt32(Console.ReadLine());

                    if (red > 255 || green > 255 || blue > 255)
                    {
                        Console.WriteLine("Input not accepted");
                        Console.ReadKey(true);
                        Console.Clear();
                        break;
                    }

                    settings.BackgroundCol = Color.FromArgb(red, green, blue);
                    break;

                case "f":
                    settings.RmBackground = false;
                    break;

                default:
                    Console.WriteLine("Input not accepted");
                    Console.ReadKey(true);
                    Console.Clear();
                    break;
            }

            SaveJson();
        }

        public static void LoadJson()
        {
            try
            {
                using (StreamReader r = new StreamReader(@"C:\Users\zamk\Documents\MyProjects\16x16\settings.json"))
                {
                    settings = JsonConvert.DeserializeObject<Settings>(r.ReadToEnd());
                }
            }
            catch (Exception e)
            {
                return;
            }

            using (StreamReader r = new StreamReader(@"C:\Users\zamk\Documents\MyProjects\16x16\settings.json"))
            {
                JsonConvert.DeserializeObject<Settings>(r.ReadToEnd());
            }

        }

        public static void SaveJson()
        {
            string jsonString = JsonConvert.SerializeObject(settings, Formatting.Indented);
            File.WriteAllText(@"C:\Users\zamk\Documents\MyProjects\16x16\settings.json", jsonString);
        }


        public static void Start()
        {
            Console.Write("Geben sie den Bildnamen an: ");
            string bildName = Console.ReadLine();

            Bitmap bmp = new Bitmap($@"{settings.FileDir}\{bildName}");
            Bitmap outcome = new Bitmap(settings.PixelAnzahl, settings.PixelAnzahl);
            int Width = bmp.Width / settings.PixelAnzahl;
            int Height = bmp.Height / settings.PixelAnzahl;

            int counter = 0;

            Console.Write("Berechnen... ");
            using (var progress = new ProgressBar())
            {
                for (int i = 0; i < settings.PixelAnzahl; i++)
                {
                    for (int j = 0; j < settings.PixelAnzahl; j++)
                    {

                        List<Count> Argb = new List<Count>();

                        for (int x = Convert.ToInt32(Math.Ceiling((double)Width * i)); x < Math.Ceiling((double)Width * (i + 1)); x++)
                        {
                            for (int y = Convert.ToInt32(Math.Ceiling((double)Height * j)); y < Math.Ceiling((double)Height * (j + 1)); y++)
                            {

                                bool Exists = false;

                                foreach (var item in Argb)
                                {
                                    if (bmp.GetPixel(x, y).ToArgb() == item.Argb) //Zu switch case umbauen
                                    {
                                        Exists = true;
                                        item.Anzahl += 1;
                                    }
                                }

                                if (!Exists)
                                {
                                    Argb.Add(new Count(bmp.GetPixel(x, y).ToArgb(), new Point(x, y), 1));
                                }
                                counter++;

                                double report = Convert.ToDouble(counter) / Convert.ToDouble(settings.PixelAnzahl * settings.PixelAnzahl * Width * Height);

                                progress.Report(report);
                            }
                        }

                        Count BiggestItem = new Count(0);

                        foreach (var item in Argb)
                        {
                            if (item.Anzahl > BiggestItem.Anzahl)
                            {
                                BiggestItem = item;
                            }
                        }

                        outcome.SetPixel(i, j, Color.FromArgb(BiggestItem.Argb));

                    }



                }
            }
            outcome.Save($@"{settings.FileDir}\16x16{bildName}");

        }

    }
}
