}                                               //END (CalcStats)

        /// <summary>
        /// Add game data to Top if needed (by preset - max 5 player records and by 3BV - max 10 player records)
        /// </summary>
        /// <param name="index">Index of the current preset</param>
        /// <param name="now">CUrrent date and time</param>
        /// <param name="gameTime">Current game time</param>
        /// <param name="level3BV">Difficulty level by 3BV</param>
        /// <param name="askPN">Handler to the method that asks for a player name</param>
        /// <returns>Fastest game time from the Top table</returns>
        private uint AddToTop(int index, DateTime now, uint gameTime, uint level3BV, AskPlayerName askPN)
        {
            //first of all we'll check whether we have to add to StatsBy3BV
            int topLength = (StatsBy3BV == null) ?                      //if statsby3bv is not created by now
                            0 :                                         //set toplenght to zero
                            StatsBy3BV.Length;                          //otherwise set toplength to the length of statsby3bv
            bool   HaveToAdd  = false;                                  //flag that is true when we have to add to top
            string playerName = null;                                   //playerName is not specified yet

            if (topLength >= 10)                                        //if topLength is 10 records or more (we will limit top by 10 records)
            {
                if (StatsBy3BV[topLength - 1].Level3BV < level3BV)      //if current difficulty level is more than the minimal one in top
                {
                    HaveToAdd = true;                                   //we have to add it
                }
                else if (StatsBy3BV[topLength - 1].Level3BV > level3BV) //if current difficulty level is less than the minimal one in top
                {
                    HaveToAdd = false;                                  //we mustn't add it
                }
                else if (StatsBy3BV[topLength - 1].GameTime > gameTime) //if they are equal and current game time is less than added to the top
                {
                    HaveToAdd = true;                                   //we have to add it
                }
            }                                                           //ENDIF (top is 10 or more records)
            else                                                        //if top has less than 10 records
            {
                HaveToAdd = true;                                       //we have to add current game to the top
            }
            if (HaveToAdd)                                              //if we have to add to the top
            {
                playerName = askPN();                                   //ask for player name
                Array.Resize(ref StatsBy3BV, ++topLength);              //get memory for the new record in the top
                //add a new record to the top
                StatsBy3BV[topLength - 1].GameTime = gameTime;          //game duration
                StatsBy3BV[topLength - 1].Name     = playerName;        //player name
                StatsBy3BV[topLength - 1].WinTime  = now;               //win date and time
                StatsBy3BV[topLength - 1].Level3BV = level3BV;          //difficulty level
                switch (index)                                          //switch between presets using the specified index
                {
                case 0:                                                 //Newbie
                    StatsBy3BV[topLength - 1].Preset =
                        MinesSettings.Preset.Newbie;                    //records preset is Newbie
                    break;

                case 1:                                                                             //Advanced
                    StatsBy3BV[topLength - 1].Preset =
                        MinesSettings.Preset.Advanced;                                              //records preset is Advanced
                    break;

                case 2:                                                                             //Professional
                    StatsBy3BV[topLength - 1].Preset =
                        MinesSettings.Preset.Professional;                                          //records preset is Professional
                    break;

                default:                                                         //any other undex value will become a Custom
                    StatsBy3BV[topLength - 1].Preset =
                        MinesSettings.Preset.Custom;                             //record preset is Custom
                    break;
                }                                                                //ENDSWITCH (preset)
                Array.Sort(StatsBy3BV, new WinnerInfo().CompareByLevel3BV);      //sort top descending by 3bv and then ascending by game duration
                Array.Resize(ref StatsBy3BV, (topLength > 10 ? 10 : topLength)); //if top length is more than 10 records cut its length to 10
                                                                                 //  this will cut records that are last in the top
            }                                                                    //ENDIF (have to add to top)
            if (index < 0 || index > 2)                                          //if preset is not newbie, advanced or professional
            {
                return(StatsBy3BV[0].GameTime);                                  //return game duration from the first record of the top
            }
            //now we'll check whether we have to add to StatsByPreset
            topLength = (StatsByPreset[index].Top == null) ?                              //if stats by preset top has records
                        0 :                                                               //set topLength to zero
                        StatsByPreset[index].Top.Length;                                  //otherwise set it to length of the top
            HaveToAdd = false;                                                            //set have-to-add flag to false
            if (topLength >= 5)                                                           //if top length is 5 or more (we'll limit its length by 5)
            {
                if (StatsByPreset[index].Top[topLength - 1].GameTime > gameTime)          //if current game duration is less than the last record in the top
                {
                    HaveToAdd = true;                                                     //we have to add a new record
                }
            }                                                                             //ENDIF (top length is 5 or more)
            else                                                                          //if top length is less than 5
            {
                HaveToAdd = true;                                                         //we have to add a new record
            }
            if (HaveToAdd)                                                                //if we have to add a new record to top
            {
                Array.Resize(ref StatsByPreset[index].Top, ++topLength);                  //get memory for the new record
                StatsByPreset[index].Top[topLength - 1].GameTime = gameTime;              //save game duration
                StatsByPreset[index].Top[topLength - 1].Name     = (playerName == null) ? //if player name is not specified yet
                                                                   askPN() :              //ask for player name
                                                                   playerName;            //otherwise use already specified name
                StatsByPreset[index].Top[topLength - 1].WinTime  = now;                   //save date and time of win
                StatsByPreset[index].Top[topLength - 1].Level3BV = level3BV;              //save difficulty level
                switch (index)                                                            //switch between presets
                {
                case 0:                                                                   //Newbie
                    StatsByPreset[0].Top[topLength - 1].Preset =
                        MinesSettings.Preset.Newbie;                                      //save preset as Newbie
                    break;

                case 1:                                                                             //Advanced
                    StatsByPreset[1].Top[topLength - 1].Preset =
                        MinesSettings.Preset.Advanced;                                              //save preset as Advanced
                    break;

                case 2:                                                                      //Professional
                    StatsByPreset[2].Top[topLength - 1].Preset =
                        MinesSettings.Preset.Professional;                                   //save preset as Professional
                    break;
                }                                                                            //ENDSWITCH (preset)
                Array.Sort(StatsByPreset[index].Top, new WinnerInfo().CompareByGameTime);    //sort top list acsending by game duration
                Array.Resize(ref StatsByPreset[index].Top, (topLength > 5 ? 5 : topLength)); //if top length is more than 5 records cut its length to 5 records
                                                                                             //  this will cut records that are last in the top
            }                                                                                //ENDIF (have to add to top)
            return(StatsByPreset[index].Top[0].GameTime);                                    //return game duration from the first record of the top
        }                                                                                    //END (AddToTop)
        }                     //END (getInstance)

        /// <summary>
        /// Calculate stats for the current game
        /// </summary>
        /// <param name="me">Engine of the current game</param>
        /// <param name="ms">Settings of the current game</param>
        /// <param name="askPN">Handler of the method that asks for a player name</param>
        public void CalcStats(MinesEngine me, MinesSettings ms, uint gameTime, AskPlayerName askPN)
        {
            DateTime curTime = DateTime.Now;                                //current date and time
            int      index   = -1;                                          //index of the current preset in the stats array

            if (me.CurrentGameState.State != MinesEngine.GameState.Loose && //if game is not lost
                me.CurrentGameState.State != MinesEngine.GameState.Win)     //AND game is not won
            {
                return;                                                     //do nothing and just return
            }
            uint level3BV = me.Level3BV;                                    //get difficulty level of the game from the engine

            switch (ms.CurrentPreset)                                       //switch between game presets
            {
            case MinesSettings.Preset.Newbie: index = 0; break;             //for Newbie index is zero

            case MinesSettings.Preset.Advanced: index = 1; break;           //for Advanced index is 1

            case MinesSettings.Preset.Professional: index = 2; break;       //for Professional index is 2

            case MinesSettings.Preset.Custom:                               //for Custom we will not add stats by preset
                                                                            //  but we will try to add a record to the top by difficulty level
                if (me.CurrentGameState.State == MinesEngine.GameState.Win) //if game is won
                {
                    AddToTop(3, curTime, gameTime, level3BV, askPN);        //try to add record to top list
                }
                return;                                                     //return

            default: return;                                                //if somehow preset in game settings is invalid do nothing and return
            }                                                               //ENDSWITCH (preset)
            StatsByPreset[index].TotalGames++;                              //increase total games played for the current preset
            if (me.CurrentGameState.State == MinesEngine.GameState.Win)     //if game is won
            {
                if (gameTime > StatsByPreset[index].LongestGameTime)        //if current game duration is more than the saved in stats one
                {
                    StatsByPreset[index].LongestGameTime = gameTime;        //save current game duration
                }
                StatsByPreset[index].WinGames++;                            //increase won games counter
                StatsByPreset[index].WinPercent =
                    StatsByPreset[index].WinGames /
                    (double)StatsByPreset[index].TotalGames *
                    100.0;                                                          //calculate the new win-percentage
                StatsByPreset[index].WinStreak++;                                   //increase win streak counter
                if (StatsByPreset[index].LooseStreak >
                    StatsByPreset[index].MaxLooseStreak)                            //if current loose streak is longer than the saved one
                {
                    StatsByPreset[index].MaxLooseStreak =
                        StatsByPreset[index].LooseStreak;                //save the current loose streak as the maximal
                }
                StatsByPreset[index].LooseStreak     = 0;                //reset current loose streak
                StatsByPreset[index].FastestGameTime =
                    AddToTop(index, curTime, gameTime, level3BV, askPN); //try to add current game to top
            }                                                            //ENDIF (game is won)
            else                                                         //if game is LOST
            {
                if (StatsByPreset[index].WinStreak >
                    StatsByPreset[index].MaxWinStreak)                              //if current win streak is longer than the saved one
                {
                    StatsByPreset[index].MaxWinStreak =
                        StatsByPreset[index].WinStreak; //save current win streak as the maximal
                }
                StatsByPreset[index].WinStreak = 0;     //reset current win streak
                StatsByPreset[index].LooseStreak++;     //increase the loose streak counter
            }                                           //ENDELSE (game is lost)
        }                                               //END (CalcStats)