using System;
using System.IO;
using System.Media;
using System.Drawing;
using System.Threading;
using System.Collections;
using System.Windows.Forms;
using System.Drawing.Imaging;

namespace Puzzle
{
    public partial class Puzzle : Form
    {

        #region "Global Variables"

        Random r;
        private MIDI music;                  //MIDI
        private bool numbers;
        private int RowCount = 4;
        private int ColumnCount = 4;
        private string[] imgName;
        private Thread ThreadTime = null;
        private Label[] label = new Label[16];
        private Label lastPict = new Label();
        private int[,] gridValue, checkValue;
        string[] pictArr = new string[16];
        ArrayList genList;                   // Liste für die Zufallszahlen
        int Num, num;                        // für Random/genRandomVal-Methoden
        static int x, y;                     // für 0 val 
        static int z;                        // für label[i]. 
        static int min = 0;                  // GameClock-Methode
        public static int keyCount = 0;             // Zählung der Züge
        public static string gameStatus;
        static int cnt;                      // Progressbar - Zählvariable 
        public Random change = new Random(); // MIDI

        # endregion

        #region "Constructors"

        public Puzzle()
        {                      
            genList = new ArrayList(16);
            r = new Random();
            InitializeComponent();
            Initialize();
            this.music = new MIDI(change);
            this.PanelPreview.BackColor = Properties.Settings.Default.MyOwnColor;  
        }
        

        public Puzzle(bool numbers)
        {                 
            this.numbers = numbers;
            genList = new ArrayList(16);
            r = new Random();
            InitializeComponent();
            Initialize();
            this.music = new MIDI(change);
            this.PanelPreview.BackColor = Properties.Settings.Default.MyOwnColor;  
        }

        # endregion

        #region "Private Methods"        

        private void Puzzle_Load(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
            createLabel();
            ThreadTime = new Thread(new ThreadStart(GameClock));
            ThreadTime.IsBackground = true;
            ThreadTime.Start();
        }
               
        private void KeyControl(object sender, KeyEventArgs e)  // 
        {
            switch (e.KeyCode)
            {
                case Keys.Left:
                    {
                        moveLeft();
                    }
                    break;

                case Keys.Right:
                    {
                        moveRight();
                    }
                    break;

                case Keys.Up:
                    {
                        moveUp();
                    }
                    break;

                case Keys.Down:
                    {
                        moveDown();
                    }
                    break;
            }

            if (check())
            {             
                progressBar1.Value = progressBar1.Maximum;
                ThreadTime.Abort();
                labelLastPict.Visible = true;  // wenn Puzzle richtig gelöst, dann  letztes Blockbild hinzufügen
                labelLastPict.Image = Image.FromFile((imgName[15]).ToString());
                gameStatus = string.Format("Du hast das Puzzle in {0} Zügen gelöst.", keyCount);
                SoundPlayer player = new SoundPlayer(Properties.Resources.Sieg);
                player.Play(); 
                MessageBox.Show(gameStatus, "Glückwunsch!");              
                Application.Exit();
            }
            progressBar1.Minimum = 0;
            progressBar1.Maximum = 15;
            progressBar1.Value = cnt;
        }       
        
        private void swap(int a, int b)
        {
            int swapValue;
            swapValue = gridValue[x, y];
            gridValue[x, y] = gridValue[a, b];
            gridValue[a, b] = swapValue;
        }
               
        private void moveLeft()
        {

            if ((y + 1) > 3) return;
            this.label[z].BorderStyle = BorderStyle.None;
            this.label[z].Visible = true;
            this.label[z].Image = Image.FromFile((pictArr[gridValue[x, y + 1]]).ToString());

            if (numbers)
            {
                this.label[z].Text = gridValue[x, y + 1].ToString(); // Bild_Nummer einblenden
            }

            swap(x, y + 1);
            y = y + 1;
            z = z + 1;

            this.label[z].BorderStyle = BorderStyle.None;
            this.label[z].Visible = false;
            this.label[z].Image = Image.FromFile((pictArr[gridValue[x, y]]).ToString());

            if (numbers)
            {
                this.label[z].Text = gridValue[x, y].ToString(); // Bild_Nummer einblenden
            }
            keyCount++;

        }
           
        private void moveRight()
        {

            if ((y - 1) < 0) return;
            this.label[z].BorderStyle = BorderStyle.None;
            this.label[z].Visible = true;
            this.label[z].Image = Image.FromFile((pictArr[gridValue[x, y - 1]]).ToString());

            if (numbers)
            {
                this.label[z].Text = gridValue[x, y - 1].ToString(); // Bild_Nummer einblenden
            }

            swap(x, y - 1);
            y = y - 1;
            z = z - 1;

            this.label[z].BorderStyle = BorderStyle.None;
            this.label[z].Visible = false;
            this.label[z].Image = Image.FromFile((pictArr[gridValue[x, y]]).ToString());

            if (numbers)
            {
                this.label[z].Text = gridValue[x, y].ToString();     // Bild_Nummer einblenden
            }
            keyCount++;
        }
             
        private void moveUp()
        {

            if ((x + 1) > 3) return;
            this.label[z].BorderStyle = BorderStyle.None;
            this.label[z].Visible = true;
            this.label[z].Image = Image.FromFile((pictArr[gridValue[x + 1, y]]).ToString());

            if (numbers)
            {
                this.label[z].Text = gridValue[x + 1, y].ToString();   // Bild_Nummer einblenden
            }

            swap(x + 1, y);
            x = x + 1;
            z = z + 4;

            this.label[z].BorderStyle = BorderStyle.None;
            this.label[z].Visible = false;
            this.label[z].Image = Image.FromFile((pictArr[gridValue[x, y]]).ToString());

            if (numbers)
            {
                this.label[z].Text = gridValue[x, y].ToString();  // Bild_Nummer einblenden
            }
            keyCount++;

        }
               
        private void moveDown()
        {

            if ((x - 1) < 0) return;
            this.label[z].BorderStyle = BorderStyle.None;
            this.label[z].Visible = true;
            this.label[z].Image = Image.FromFile((pictArr[gridValue[x - 1, y]]).ToString());

            if (numbers)
            {
                this.label[z].Text = gridValue[x - 1, y].ToString();  // Bild_Nummer einblenden
            }

            swap(x - 1, y);
            x = x - 1;
            z = z - 4;

            this.label[z].BorderStyle = BorderStyle.None;
            this.label[z].Visible = false;
            this.label[z].Image = Image.FromFile((pictArr[gridValue[x, y]]).ToString());

            if (numbers)
            {
                this.label[z].Text = gridValue[x, y].ToString();  // Bild_Nummer einblenden
            }
            keyCount++;
        }
                
        private void GameClock()
        {
            string time;

            for (min = 0; min < 12; min++)
            {
                for (int sec = 0; sec < 60; sec++)
                {
                    time = string.Format("{0}:{1:00}", min, sec);
                    this.LabelTime.Text = time;
                    Thread.Sleep(1000);
                }
            }

            if (min == 12 & !check())
            {
                this.PanelPreview.BackColor = Color.Gray;
                this.Enabled = false;
                SoundPlayer player = new SoundPlayer(Properties.Resources.gameover);
                player.Play();
                MessageBox.Show(" Mit Sicherheit hast Du nächstes Mal mehr Erfolg!", "Game Over");
                Application.Exit();
            }
        }
             
        private bool check()
        {
            cnt = -1;
            checkValue = new int[4, 4] {
                                        {1,  2,  3,  4},
                                        {5,  6,  7,  8},
                                        {9,  10, 11, 12},
                                        {13, 14, 15, 0},
                                     };

            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    cnt++;
                    if (gridValue[i, j] != checkValue[i, j])
                        return false;
                }
            }
            return true;
        }

        private void MenuItemNumbersOn_Click(object sender, EventArgs e)
        {
            if ((((ToolStripMenuItem)sender).Text) == "mit Nummern")
            {
                Puzzle resatrt = new Puzzle(true);
                this.Hide();
                if (resatrt.ShowDialog() == DialogResult.OK)
                {
                    this.Show();
                }
            }

        }

        private void MenuItemNumbersOff_Click(object sender, EventArgs e)
        {
            if ((((ToolStripMenuItem)sender).Text) == "ohne Nummern")
            {
                Puzzle resatrt = new Puzzle();
                this.Hide();
                if (resatrt.ShowDialog() == DialogResult.OK)
                {
                    this.Show();
                }
            }
        }

        private void MenuItemColors_Click(object sender, EventArgs e)
        {          
            ColorDialog colorChooser = new ColorDialog();
            DialogResult result;

            colorChooser.FullOpen = true;
            result = colorChooser.ShowDialog();

            if (result == DialogResult.Cancel)
                return;
            Properties.Settings.Default.MyOwnColor = colorChooser.Color;   
            this.PanelPreview.BackColor = colorChooser.Color;                                
                    
                       
        }

        private void MenuItemMusicOn_Click(object sender, EventArgs e)
        {
            this.music.Change(true);
        }

        private void MenuItemMusicOff_Click(object sender, EventArgs e)
        {
            this.music.Stop();
        }

        private void MenuItemExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void MenuItemPreviewPictureOn_Click(object sender, EventArgs e)
        {
            pictureBoxPreview.Visible = true;
            string[] path = Directory.GetFiles(Application.UserAppDataPath + @"\Images\TempPreview");
            pictureBoxPreview.Image = Image.FromFile(path[0]);
            ColorMatrix matrix = new ColorMatrix(new float[][]
            {
                    new float[] {.393f, .349f, .272f, 0, 0},
                    new float[] {.769f, .686f, .534f, 0, 0},
                    new float[] {.189f, .168f, .131f, 0, 0},
                    new float[] {0, 0, 0, 1, 0},
                    new float[] {0, 0, 0, 0, 1}                   
            });

            Image image = (Bitmap)pictureBoxPreview.Image.Clone();
            ImageAttributes attributes = new ImageAttributes();
            attributes.SetColorMatrix(matrix);
            Graphics graphics = Graphics.FromImage(image);
            graphics.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes);
            graphics.Dispose();
            pictureBoxPreview.Image = image;
        }

        private void MenuItemPreviewPictureOff_Click(object sender, EventArgs e)
        {
            pictureBoxPreview.Visible = false;
        }
      
        # endregion

        #region "Public Methods"
        
        public void Initialize()
        {
            gridValue = new int[4, 4] {                   // Label mit 4 Zeilen und 4 Spalten erzeugen
                                        {0, 0, 0, 0},
                                        {0, 0, 0, 0},
                                        {0, 0, 0, 0},
                                        {0, 0, 0, 0},
                                     };

            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    if ((i == 3) && (j == 3))
                    {
                        x = i;
                        y = j;
                    }
                    else
                    {
                        gridValue[i, j] = genRandomVal();
                    }
                }
            }

        }


        public static Color ToColor(string getColor)
        {
            Color color = Color.FromName(getColor);
            if (!color.IsKnownColor)
            {
                try
                {
                    // try to convert from hex format: aarrggbb
                    int iResult = Convert.ToInt32(getColor, 16);
                    color = Color.FromArgb(iResult >> 24 & 0xff, iResult >> 16 & 0xff, iResult >> 8 & 0xff, iResult & 0xff);
                }
                catch { }
            }
            return color;
        }



               
        public int Random()
        {
            Num = r.Next(1, 16);
            for (int k = 0; k < genList.Count; k++)
            {
                if (genList[k].Equals(Num))
                {
                    Random();
                }
            }

            return Num;
        }
              
        public int genRandomVal()
        {
            num = Random();
            genList.Add(num);
            return num;
        }
               
        public void createLabel()
        {
            int i = 0; int val;

            for (int j = 0; j < RowCount; j++)
                for (int k = 0; k < ColumnCount; k++)
                {
                    label[i] = new Label();
                    val = gridValue[j, k];

                    label[i].Font = new Font("microsoft sans serif", 14F, FontStyle.Bold, GraphicsUnit.Point, ((byte)(0)));
                    label[i].ForeColor = Color.Gainsboro;

                    label[i].Width = 150;
                    label[i].Height = 150;
                    label[i].Left = k * 150;
                    label[i].Top = j * 150;

                    label[i].Tag = 0;

                    label[i].TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
                    if (i != 15)
                    {
                        imgName = Directory.GetFiles(Application.UserAppDataPath + @"\Images\Temp");
                        pictArr[i] = imgName[i];

                        for (int img = 0; img < 15; img++)

                            pictArr[img + 1] = imgName[img];
                        label[i].Image = Image.FromFile((pictArr[val]).ToString());

                        if (numbers)
                        {
                            label[i].Text = val.ToString(); // Bild_Nummer einblenden
                        }
                    }
                    else
                    {

                        label[i].BorderStyle = BorderStyle.None;
                        label[i].Text = "";
                        label[i].Visible = false;
                        z = i;
                    }
                    this.PanelPreview.Controls.Add(label[i]);
                    i++;
                }
        }
        # endregion
    }
}     


     
 

