using System;
using System.Text;

namespace Boggle
{
    public class BoggleBoard
    {
        private readonly Tile[,] _Tiles;
        /// <summary>
        /// A 2D array containing all the tles in the board.
        /// This is a read only propert
        /// </summary>
        public Tile[,] Tiles
        {
            get
            {
                return _Tiles;
            }
        }

        private readonly int _SideLength;
        /// <summary>
        /// Number of tiles in one side of the square board.
        /// This is a read only property.
        /// </summary>
        public int SideLength
        {
            get
            {
                return _SideLength;
            }
        }

        /// <summary>
        /// BoggleBoard constructor.
        /// </summary>
        /// <param name="sideLength">Number of TILES that make up the side of the board.</param>
        /// <param name="letters">String containing alphabets in row first order.</param>
        public BoggleBoard(int sideLength, string letters)
        {
            if (sideLength < Constants.MIN_SIDE_LENGTH)
            {
                throw new ArgumentException(string.Format("Length of side of board has to be greater than or equal to {0}", Constants.MIN_SIDE_LENGTH));
            }

            int numTiles = sideLength * sideLength;

            if (letters.Length != numTiles)
            {
                throw new ArgumentException(string.Format("Board's initialization string contains {0} characters. {1} characters were expected. 'Q' tranlates to 'QU' internally and only 'Q' needs to be mentioned.", letters.Length, numTiles));
            }
            _SideLength = sideLength;
            _Tiles = new Tile[_SideLength, _SideLength];

            //row-first addition = manner in which humans read.
            string alphabet;
            for (int i = 0; i < sideLength; i++)
            {
                for (int j = 0; j < sideLength; j++)
                {
                    alphabet = letters.Substring(i * sideLength + j, 1);
                    //the special condition
                    if (alphabet == "Q")
                        alphabet += "U";
                    _Tiles[j, i] = new Tile(j, i, alphabet);
                }
            }
        }

        /// <summary>
        /// Copy constructor.
        /// </summary>
        /// <param name="orignalBoard">Board to copy.</param>
        public BoggleBoard(BoggleBoard orignalBoard)
        {
            _SideLength = orignalBoard._SideLength;
            _Tiles = new Tile[_SideLength, _SideLength];
            for (int i = 0; i < _SideLength; i++)
            {
                for (int j = 0; j < _SideLength; j++)
                {
                    _Tiles[i, j] = new Tile(i, j, orignalBoard.Tiles[i, j].Alphabet);
                }
            }
        }

        /// <summary>
        /// Indexer to allow more natural access to tiles in the board.
        /// </summary>
        /// <param name="x">X co-ordinate of the tile in the board.</param>
        /// <param name="y">Y co-ordinate of the tile in the board.</param>
        /// <returns>Tile at x, y co-ordinate.</returns>
        public Tile this[int x, int y]
        {
            get
            {
                return _Tiles[x, y];
            }
        }

        /// <summary>
        /// Prints out the board on console.
        /// </summary>
        public void Print()
        {
            int horizontalLength = _SideLength * 4 + 1;
            StringBuilder line = new StringBuilder(horizontalLength);
            string horizontalSeparator = string.Empty;
            for (int i = 0; i < horizontalLength; i++)
            {
                horizontalSeparator += "\u2550";
            }

            for (int i = 0; i < _SideLength; i++)
            {
                Console.WriteLine(horizontalSeparator);
                line.Clear();
                line.Append("\u2551");
                for (int j = 0; j < _SideLength; j++)
                {
                    line.AppendFormat(" {0} \u2551", _Tiles[j, i].Alphabet);
                }
                Console.WriteLine(line);
            }
            Console.WriteLine(horizontalSeparator);
        }
    }
}
