using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.CompilerServices;

namespace PuzzlePlayer_Namespace
{ 
    /* The binair board consist of 1 and 0
     * This means that the possible states a cell can be are: empty, one or zero
     * To specify this in an int[,] array we will use -1 for an empty space,
     * 0 for a space with a zero and 1 for a space with a one
     * The empty space is a constant defined in the abstract Board class
     */

    internal class Binary : Board
    {

        // constructor with baordSize parameter (default is set to 8 but can be changed)
        public Binary(int boardSize = 8)
        {
            // create a board with the specifide size
            boardState = new int[boardSize,boardSize];

            description = "Binary puzzle is played on any even-numbered square grid, with some cells initially containing black or white circles. The goal of the puzzle is to fill all cells such that:\r\n● More than two circles of the same color cannot be adjacent\r\n● Each row and column must contain an equal number of black and white circles\r\n● Each row and column cannot appear multiple times on the board";

            // clear the board (fill it in with -1)
            Clear();
        }

        public override void Draw (Graphics gr, Rectangle r) //draws board in rectangle R. warning: will stretch image unless FitBoard() is used for rectangle size
        {
            Size tilesize = new Size(r.Width / boardState.GetLength(0), r.Height / boardState.GetLength(1));
            Pen border = new Pen(Color.Black, 2);
            gr.FillRectangle(Brushes.Beige, r.X, r.Y, tilesize.Width*boardState.GetLength(0), tilesize.Height*boardState.GetLength(1));
            for (int i = 0; i < boardState.GetLength(0); i++)
            {
                for(int j = 0; j < boardState.GetLength(1); j++)
                {
                    gr.DrawRectangle(Pens.LightGray,
                        r.X+i* tilesize.Width,
                        r.Y+j* tilesize.Height,
                        tilesize.Width,
                        tilesize.Height);
                    if (boardState[i,j] == 0)
                    {
                        gr.FillEllipse(Brushes.White,
                            (int)(r.X + ((double)i + 0.125) * tilesize.Width),
                            (int)(r.Y + ((double)j + 0.125) * tilesize.Height),
                            tilesize.Width * 3 / 4,
                            tilesize.Height * 3 / 4);
                        gr.DrawEllipse(border,
                            (int)(r.X + ((double)i + 0.125) * tilesize.Width + border.Width/2),
                            (int)(r.Y + ((double)j + 0.125) * tilesize.Height + border.Width/2),
                            tilesize.Width * 3 / 4 - border.Width,
                            tilesize.Height * 3 / 4 - border.Width);
                    }
                    if (boardState[i, j] == 1)
                    {
                        gr.FillEllipse(Brushes.Black,
                            (int)(r.X + ((double)i + 0.125) * tilesize.Width),
                            (int)(r.Y + ((double)j + 0.125) * tilesize.Height),
                            tilesize.Width * 3 / 4,
                            tilesize.Height * 3 / 4);
                    }
                }
            }
        }

        private void Clear()
        {
            int size = boardState.GetLength(0);
            // fill the board with empty spaces (-1)
            for (int i = 0; i < size; i++)
            {
                for (int j = 0; j < size; j++)
                    boardState[i, j] = emptySpace;
            }
        }

        /* this static methode returns true if the board is valid in a few steps
        1: It checks if the size from boardToCheck is equal to the size from the boardState variable
        2: it loops though the board and checks if one of the spaces contains something other than a -1,0 or 1
        */
        public override bool IsBoardValid(int[,] boardToCheck)
        {
            // check if the size is NOT the same
            if(!(boardToCheck.GetLength(0) ==  boardState.GetLength(0) && boardToCheck.GetLength(1) == boardState.GetLength(1)))
                return false;
                

            // check if any of the spaces doesn't contain a -1,0 or 1
            for(int i = 0;i < boardToCheck.GetLength(0);i++)
            {
                for(int j = 0; j < boardToCheck.GetLength(1);j++)
                {
                    switch(boardToCheck[i,j])
                    {
                        case -1:
                        case 0:
                        case 1:
                            break;
                        default:
                            return false;
                    }
                }
            }

            return true;
        }

        public override void Generate()
        {
            throw new NotImplementedException();
        }

        protected override List<int[,]> GetSolveList(int[,] boardToSolve)
        {
            List<int[,]> result = new List<int[,]>();

            for (int i = 0; i < boardToSolve.GetLength(0); i++)
                for (int j = 0; j < boardToSolve.GetLength(1); j++)
                {
                    int[,] move = CheckMove(i, j, boardToSolve);
                    if (move != null)
                        result.Add(move);
                }



            return result;
        }

        private int[,] CheckMove(int x, int y, int[,] boardToSolve)
        {
            bool validForZero = false;
            bool validForOne = false;

            // empty check
            if (boardToSolve[x, y] != emptySpace)
                return null;

            // loop two times for checking 0 and 1
            for (int i = 0; i <= 1; i++)
            {
                bool valid = false;

                // middle check
                valid = MiddleCheck(x, y, boardToSolve, i);

                // side check

                // even 1 and 0 in one row and colum


            }

            return null;
        }

        // check if the space is surrounded on both sides by the same number. If it is, the checked space should be the opposite number
        private bool MiddleCheck(int x, int y, int[,] b, int checkFor)
        {
            int opposite;

            if (checkFor == 0)
                opposite = 1;
            else
                opposite = 0;

            // first check if x-1 and x+1 aren't out of bounds
            // after that do the check if the move is valid
            if(!(x-1 < 0 || x+1 > b.GetLength(0)))
                if (b[x - 1, y] == opposite && b[x + 1, y] == opposite)
                    return true;

            // same for y
            if (!(y - 1 < 0 || y + 1 > b.GetLength(1)))
                if (b[x, y - 1] == opposite && b[x, y + 1] == opposite)
                    return true;

            // return false if nothing was found
            return false;
        }

        private bool SideCheck(int x, int y, int[,] b, int checkFor)
        {
            int opposite;

            if (checkFor == 0)
                opposite = 1;
            else
                opposite = 0;

            if (!(x - 2 < 0 || x + 2 > b.GetLength(0)))
                if ((b[x-2,y] == opposite && b[x-1,y] == opposite) || (b[x + 2, y] == opposite && b[x + 1, y] == opposite))
                    return true;

            if (!(y - 2 < 0 || y + 2 > b.GetLength(1)))
                if ((b[x, y - 2] == opposite && b[x, y - 1] == opposite) || (b[x, y + 2] == opposite && b[x, y + 1] == opposite))
                    return true;

            return false;
        }

        public override void TileInput(Point p, int x)
        {
            if (x==0 || x==1) boardState[p.X, p.Y] = x;
        }
    }
}