#define DEVELOPING

using System;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;

namespace Boggle
{
    public class Boggle
    {
        static void PrintWords(HashSet<WordOnBoard> words)
        {
            int score = 0;
            foreach (WordOnBoard word in words)
            {
                Console.Write("{0} [{1}], ", word.Word, word.Score);
                score += word.Score;
            }
            Console.WriteLine("\n\nTotal score for this board: {0}", score);
        }
        static void Main(string[] args)
        {
            Stopwatch st = new Stopwatch();
            BoggleList bl = new BoggleList();
            Console.WriteLine("Current directory: {0}", Directory.GetCurrentDirectory());
#if !DEVELOPING
            string input;
            bool isError = false;
#endif
            int boardSideLength = 3;
            int minWordLength = 4;

            char wordListInput = 'T';
            BoggleLists listToUseForLookup;
            
#if !DEVELOPING
            do
            {
                isError = false;
                Console.WriteLine("Please enter the word list that you wish to use [Z for Zingarelli, T for TWS or standard scrabble list]: ");
                input = Console.ReadLine();
                if (!char.TryParse(input, out wordListInput))
                {
                    Console.WriteLine("Invalid Input. Couldn't parse character");
                    isError = true;
                }
                wordListInput = char.ToUpper(wordListInput);
                if (wordListInput != 'T' && wordListInput != 'Z')
                {
                    Console.WriteLine("Please enter only T or Z.");
                    isError = true;
                }
            } while (isError);
#endif
            switch (wordListInput)
            {
                case 'T':
                    listToUseForLookup = BoggleLists.TWS;
                    break;

                case 'Z':
                    listToUseForLookup = BoggleLists.ZINGARELLI;
                    break;
                default:
                    throw new Exception("Unexpected!!");
            }

#if !DEVELOPING
            do
            {
                isError = false;
                Console.WriteLine("Please enter number of tiles that make up one side of the board: ");
                input = Console.ReadLine();
                if (!int.TryParse(input, out boardSideLength))
                {
                    Console.WriteLine("Invalid Input.");
                    isError = true;
                }
            } while (isError);

            do
            {
                isError = false;
                Console.WriteLine("Please enter number of ALPHABETS that should be there in shortest word: ");
                input = Console.ReadLine();
                if (!int.TryParse(input, out minWordLength))
                {
                    Console.WriteLine("Invalid Input.");
                    isError = true;
                }
            } while (isError);
#endif
            st.Start();
            bl.LoadList(listToUseForLookup, boardSideLength, minWordLength, Directory.GetCurrentDirectory());
            st.Stop();
            Console.WriteLine("Loaded list in {0} ms.", st.ElapsedMilliseconds);

            string boardString = "qwertyuio";
#if !DEVELOPING
            do
            {
                isError = false;
                Console.WriteLine("Please enter the characters on board in row first fashion ({0} expected characters): ", boardSideLength*boardSideLength);
                boardString = Console.ReadLine();
                if (boardString.Length != boardSideLength*boardSideLength)
                {
                    Console.WriteLine("Invalid Input. Q will be translated to QU internally. Please enter only Q if you want to enter the QU tile.");
                    isError = true;
                }
            } while (isError);
#endif
            boardString = boardString.ToUpper();

            BoggleBoard board = new BoggleBoard(boardSideLength, boardString);
            board.Print();
            BoggleSolver solution = new BoggleSolver(board, bl, minWordLength);
            st.Start();
            //HashSet<WordOnBoard> wordsUnThreaded = solution.GetWordsOnBoard(false);
            //st.Stop();
            //PrintWords(wordsUnThreaded);

            //Console.WriteLine("Got solution in {0} ms. Number of words (unthreaded): {1}", st.ElapsedMilliseconds, wordsUnThreaded.Count);
            //Console.WriteLine("Press any key to run in threaded mode.");
            //Console.ReadKey();
            st.Start();
            HashSet<WordOnBoard> wordsThreaded = solution.GetWordsOnBoard(true);
            //wordsThreaded.ExceptWith(wordsUnThreaded);
            st.Stop();
            st.Reset();
            PrintWords(wordsThreaded);
            Console.WriteLine("Got solution in {0} ms. Number of words (threaded): {1}.", st.ElapsedMilliseconds, wordsThreaded.Count);

            


            //if (wordsUnThreaded.Count > wordsThreaded.Count)
            //{
            //    wordsUnThreaded.ExceptWith(wordsThreaded);
            //    Console.WriteLine("Words in unthreaded collection that are not in threaded collection:");
            //    PrintWords(wordsUnThreaded);
            //}
            //if (wordsThreaded.Count > wordsUnThreaded.Count)
            //{
            //    wordsThreaded.ExceptWith(wordsUnThreaded);
            //    Console.WriteLine("Words in threaded collection that are not in unthreaded collection:");
            //    PrintWords(wordsThreaded);
            //}

            //wordsUnThreaded.RemoveWhere(WordsWithLowestScore);
            //Console.WriteLine("***Removed words with score 1.***");
            //PrintWords(wordsUnThreaded);
            Console.ReadKey();
        }

        private static bool WordsWithLowestScore(WordOnBoard word)
        {
            if (word.Score == Constants.MIN_SCORE)
            {
                return true;
            }

            return false;
        }
    }
}
