using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Text;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace DirectXEksempel06
{
    class Model
    {
        private Engine theEngine; // Associeret Engine
        private UI theUI; // Associeret UI
        private Brick[,] bricks;
        private Point mouseLocation = new Point(0, 0);
        private char mouseButton;
        private int x;  // Tabellens dimensioner
        private int y;
        private int fundet;
        private int rest;
        private int legal;
        private bool slut;

        public Point MouseLocation
        {
            set { mouseLocation = value; }
            get { return mouseLocation; }
        }

        public char MouseButton
        {
            set { mouseButton = value; }
            get { return mouseButton; }
        }

        public int Rest
        {
            set { rest = value; }
            get { return rest; }
        }

        public int Legal
        {
            set { legal = value; }
            get { return legal; }
        }

        public Model(int antalX, int antalY, Engine anEngine, UI aUI)
        {
            theEngine = anEngine;
            theUI = aUI;
            MouseButton = ' ';
            x = antalX;
            y = antalY;
            Color color = Color.Black;
            // Tabel initialiseres med tomme Bricks
            bricks = new Brick[x, y];
            for (int i = 0; i < x; i++)
                for (int j = 0; j < y; j++)
                {
                    bricks[i, j] = new Brick(theEngine.GetDevice(),
                        new Vector3(i + 1, j + 1, 0), color);
                }
            Udfyld();
            Legal = Lovlige(); // Antal lovlige træk
            theUI.legal.Text = "  " + Legal; // Opdatér UI
        }

        public void Udfyld()
        {
            slut = false;
            Color color = new Color();
            Rest = x * y;
            theUI.remains.Text = "  " + Rest; // Opdatér UI
            // Tabel med Bricks i tilfældige farver
            Random rnd = new Random();
            for (int i = 0; i < x; i++)
                for (int j = 0; j < y; j++)
                {
                    int c = rnd.Next(5);
                    switch (c)
                    {
                        case 0:
                            color = Color.Red;
                            break;
                        case 1:
                            color = Color.Blue;
                            break;
                        case 2:
                            color = Color.Yellow;
                            break;
                        case 3:
                            color = Color.Green;
                            break;
                        case 4:
                            color = Color.DarkOrange;
                            break;
                        case 5:
                            color = Color.Cyan;
                            break;
                    }
                    bricks[i, j].Colour = color;
                }
        }

        public void Render()
        {
            for (int i = 0; i < x; i++)
                for (int j = 0; j < y; j++)
                {
                    bricks[i, j].Render(theEngine.GetDevice());
                }
        }

        private void NulstilMarker()
        {
            for (int i = 0; i < x; i++)
                for (int j = 0; j < y; j++)
                {   // Nulstilling af markør i aktive Bricks
                    bricks[i, j].Marker = 0;
                }
        }

        public void UpdateModel()
        {
            Vector3 nearVector;
            Vector3 farVector;
            Vector3 lower;
            Vector3 upper;

            NulstilMarker();
            for (int i = 0; i < x; i++)
                for (int j = 0; j < y; j++)
                {
                    nearVector = new Vector3(MouseLocation.X, MouseLocation.Y, 0);
                    farVector = new Vector3(MouseLocation.X, MouseLocation.Y, 1);
                    // Create ray.
                    nearVector.Unproject(theEngine.GetDevice().Viewport,
                            theEngine.GetDevice().Transform.Projection,
                            theEngine.GetDevice().Transform.View,
                            Matrix.Translation(bricks[i, j].Position)
                            * Matrix.Scaling(0.5f, 0.5f, 0.5f));
                    farVector.Unproject(theEngine.GetDevice().Viewport,
                            theEngine.GetDevice().Transform.Projection,
                            theEngine.GetDevice().Transform.View,
                            Matrix.Translation(bricks[i, j].Position)
                            * Matrix.Scaling(0.5f, 0.5f, 0.5f));
                    farVector.Subtract(nearVector);
                    // Perform intersection test for the bounding box and ray.
                    lower = bricks[i, j].Position - new Vector3(0.5f, 0.5f, 0.5f);
                    upper = bricks[i, j].Position + new Vector3(0.5f, 0.5f, 0.5f);
                    if (Geometry.BoxBoundProbe(lower, upper, nearVector, farVector))
                    {
                        // En Brick er udpeget - kan den bruges?
                        fundet = 0;
                        Marking(bricks, i, j, bricks[i, j].Colour);
                        if (fundet > 1 && bricks[i, j].Colour != Color.Black)
                            Rest -= fundet;
                        theUI.remains.Text = "  " + Rest; // Opdatér UI
                    }
                }
            if (fundet > 1)
            { // Slet alle markerede
                for (int i = x - 1; i > -1; i--)
                    for (int j = y - 1; j > -1; j--)
                    {
                        if (bricks[i, j].Marker == 9)
                        { // Ryk resten af søjlen ned
                            for (int n = j; n < y - 1; n++)
                                bricks[i, n].Colour = bricks[i, n + 1].Colour;
                            bricks[i, y - 1].Colour = Color.Black;
                        }
                }
                // Slet tomme søjler
                for (int a = x - 1; a > - 1; a--)
                {
                    if (bricks[a, 0].Colour == Color.Black)
                    {
                        for (int i = a; i < x - 1; i++)
                            for (int j = 0; j < y; j++)
                                bricks[i, j].Colour = bricks[i + 1, j].Colour;
                        for (int j = 0; j < y; j++)
                            bricks[x - 1, j].Colour = Color.Black;
                    }
                }
                Legal = Lovlige(); // Antal lovlige træk
                theUI.legal.Text = "  " + Legal; // Opdatér UI
                if (Legal == 0) slut = true;
            }
        }

        public void TestSlut()
        {
            if (!slut) return;
            if (Legal == 0 & Rest < 10)
                MessageBox.Show("Godt gået");
            if (Legal == 0)
            {
                MessageBoxButtons buttons = MessageBoxButtons.YesNo;
                DialogResult result;
                result = MessageBox.Show("Start forfra?", "Ikke flere lovlige træk", buttons,
                    MessageBoxIcon.Question, MessageBoxDefaultButton.Button1,
                    MessageBoxOptions.RightAlign);
                if (result == DialogResult.Yes)
                {
                    Udfyld();
                    Legal = Lovlige(); // Antal lovlige træk
                    theUI.legal.Text = "  " + Legal; // Opdatér UI
                }
                else Application.Exit();
            }
        }

        private int Lovlige()
        {
            int antal = 0;
            for (int i = 0; i < x; i++)
                for (int j = 0; j < y; j++)
                    if (bricks[i, j].Colour != Color.Black)
                    {
                        // Check alle ikke sorte brikker med Marking
                        NulstilMarker();
                        fundet = 0;
                        Marking(bricks, i, j, bricks[i, j].Colour);
                        if (fundet > 1)
                            antal++;
                    }
            return antal;
        }
        
        public void Marking(Brick[,] bricks, int i, int j, Color c)
        {
            if (bricks[i,j].Marker == 1 | 
                bricks[i,j].Marker == 9) return; // Allerede besøgt
            if (bricks[i, j].Colour == c)
            {
                bricks[i, j].Marker = 9; // Skal slettes
                fundet++;
                // Nu testes naboer
                if (i > 0)
                    Marking(bricks, i - 1, j, c); // Venstre nabo
                if (i < x - 1)
                    Marking(bricks, i + 1, j, c); // Højre nabo
                if (j > 0)
                    Marking(bricks, i, j - 1, c); // Underbo
                if (j < y - 1)
                    Marking(bricks, i, j + 1, c); // Overbo
            }
            else
                bricks[i, j].Marker = 1; // Er testet
        }
    }
}
