private void _endVoting(IDbConnection connection, IHubContext <MainGameHub> hubContext = null,
                                bool notifyClients = true)
        {
            if (VotingInProgress)
            {
                throw new Exception(Error.TimeVotingIsNotOver);
            }
            if (_voteSate == VoteStates.EndedFinished)
            {
                throw new Exception(Error.VotingRunnerVoteIsFinishedBefore);
            }
            if (_voteSate == VoteStates.EndInProgress)
            {
                throw new Exception(Error.VotingRunnerEndInProgress);
            }
            try
            {
                _voteSate         = VoteStates.EndInProgress;
                _activeCandidates = null;
                List <IUserOfficerOut> officers = _endVotingDb(connection);

                if (officers == null || !officers.Any())
                {
                    _voteSate = VoteStates.EndedFinished;
                    return;
                }

                _rebuildWeekOfficers(officers);

                if (notifyClients)
                {
                    _notifyClientsOnVotingEnded(connection, hubContext);
                }
                _voteSate = VoteStates.EndedFinished;
            }
            catch (Exception e)
            {
                if (e.Message == VoteStates.EndedFinished.ToString())
                {
                    if (notifyClients)
                    {
                        _notifyClientsOnVotingEnded(connection, hubContext);
                    }
                    _voteSate = VoteStates.EndedFinished;
                }
                else
                {
                    _voteSate = VoteStates.EndedErrorInFinished;
                    throw;
                }
            }
        }
        private void _startVoting(IDbConnection connection, IHubContext <MainGameHub> hubContext = null,
                                  bool notifyClients = true)
        {
            if (!VotingInProgress)
            {
                throw new Exception(Error.IsNotVotePeriod);
            }
            if (_voteSate == VoteStates.StartedRunned)
            {
                throw new Exception(Error.VotingRunnerVoteIsFinishedBefore);
            }
            if (_voteSate == VoteStates.StartInProgress)
            {
                throw new Exception(Error.VotingRunnerStartInProgress);
            }
            List <CandidatOut> finalzers = null;

            try
            {
                _voteSate = VoteStates.StartInProgress;

                finalzers         = _startVotingDb(connection);
                _activeCandidates = new ActiveCandidates(finalzers);
                //_notyfyOnVoteEndedComplete
                if (notifyClients)
                {
                    _notifyClientsOnVoteStarted(hubContext);
                }
                _voteSate = VoteStates.StartedRunned;
            }
            catch (Exception e)
            {
                if (e.Message == VoteStates.StartedRunned.ToString())
                {
                    finalzers = _officerCandidatRepository.GetRegistredOfficerCandidatesByTopPvp(connection,
                                                                                                 MAX_CANDIDATES_COUNT);
                    _activeCandidates = new ActiveCandidates(finalzers);

                    if (notifyClients)
                    {
                        _notifyClientsOnVoteStarted(hubContext);
                    }
                    _voteSate = VoteStates.StartedRunned;
                }
                else
                {
                    _voteSate = VoteStates.StartedErrorInRun;
                    throw;
                }
            }
        }
 public void OnAppStop()
 {
     _voteSate = VoteStates.Undefined;
     if (_weekOfficersStorage != null)
     {
         _weekOfficersStorage.Clear();
         _weekOfficersStorage = null;
     }
     // ReSharper disable once RedundantCheckBeforeAssignment
     if (_activeCandidates == null)
     {
         return;
     }
     _activeCandidates.Dispose();
     _activeCandidates = null;
 }
        private List <IUserOfficerOut> _endVotingDb(IDbConnection connection)
        {
            var existOfficer  = _getFirstOfficer(connection);
            var startRegister = StartRegistrationTime;
            var endTime       = EndVoteTime;

            if (existOfficer?.dateEnd == endTime)
            {
                throw new NotImplementedException(VoteStates.EndedFinished.ToString());
            }


            var winners = _get_c_vote_get_top_finalized_officers(connection, 4).Select(i => new WinnerCandidat(i))
                          .ToList();

            if (winners.Count < 4)
            {
                var existIds      = winners.Select(i => i.UserId).ToList();
                var selectCount   = 4 - existIds.Count;
                var topCandidates = _officerCandidatRepository.GetRegistredOfficerCandidatesByTopPvp(connection, 0);
                if (!topCandidates.Any())
                {
                    _voteSate = VoteStates.EndedFinished;
                    return(null);
                }
                if (topCandidates.Count < 4)
                {
                    throw new NotImplementedException("topCandidates.Count < 4");
                }

                var selectedCandidates = topCandidates.Where(i => !existIds.Contains(i.UserId))
                                         .OrderByDescending(i => i.Voices)
                                         .ThenBy(i => i.Id)
                                         .Take(selectCount)
                                         .Select(i => new WinnerCandidat(i))
                                         .ToList();

                var newUserIds = selectedCandidates.Select(i => i.UserId).ToList();
                var sqlUserIds = newUserIds.Aggregate("", (current, i) => current + (i + ","));
                sqlUserIds = sqlUserIds.Substring(0, sqlUserIds.Length - 1);

                var userTableName         = _provider.GetTableName(nameof(user));
                var allianceUserTableName = _provider.GetTableName(nameof(alliance_user));
                var allianceTableName     = _provider.GetTableName(nameof(alliance));


                //Voices = i.count ?? 0;
                //UserAvatar = i.userAvatar;
                //UserId = i.userId;
                //UserName = i.userName;
                //UserPvpPoint = (int)i.userPvpPoint;
                //AllianceId = (int)i.allianceId;
                //AllianceLabel = i.allianceLabel;
                //AllianceName = i.allianceName;
                var sqlAdvancdData = @"SELECT " +
                                     @"u.avatarUrls as userAvatar, " +
                                     @"u.Id as userId, " +
                                     @"u.nickname as userName, " +
                                     @"u.pvpPoint as userPvpPoint, " +
                                     @"a.Id as allianceId, " +
                                     @"a.images as allianceLabel, " +
                                     @"a.name as allianceName " +
                                     $@"FROM {userTableName} AS u " +
                                     $@"LEFT JOIN {allianceUserTableName} AS au ON au.userId=u.Id " +
                                     $@"LEFT JOIN {allianceTableName} AS a ON a.Id=au.allianceId WHERE u.Id IN({sqlUserIds})";
                var advancdData = _provider.Text <dynamic>(connection, sqlAdvancdData).Select(i => new WinnerCandidat(i))
                                  .ToList();

                foreach (var adv in advancdData)
                {
                    var item = selectedCandidates.Single(i => i.UserId == adv.UserId);
                    item.AllianceId    = adv.AllianceId;
                    item.AllianceName  = adv.AllianceName;
                    item.AllianceLabel = adv.AllianceLabel;
                    item.UserAvatar    = adv.UserAvatar;
                }
                winners.AddRange(selectedCandidates);
            }
            var execDbo     = "EXEC [dbo].";
            var finalizeSql = "BEGIN TRAN end_voting BEGIN TRY " +
                              $"{execDbo}[c_vote_save_to_history]; " +
                              $"{execDbo}[c_vote_delete_all]; " +
                              $"{execDbo}[help_reset_index] '{nameof(c_vote)}',0; " +
                              $"{execDbo}[c_officer_save_to_history]; " +
                              $"{execDbo}[c_officer_delete_all]; " +
                              $"{execDbo}[help_reset_index] '{nameof(c_officer)}',0; " +
                              $"{execDbo}[c_vote_delete_all]; " +
                              $"{execDbo}[c_officer_candidat_save_to_history] 1; " +
                              $"{execDbo}[c_officer_candidat_delete_all]; " +
                              $"{execDbo}[help_reset_index] '{nameof(c_officer_candidat)}',0; " +
                              "COMMIT TRAN end_voting " +
                              "SELECT 1; " +
                              "END TRY " +
                              "BEGIN CATCH " +
                              "ROLLBACK TRANSACTION end_voting; " +
                              "THROW; " +
                              "END CATCH ";
            var result = _provider.Text <int>(connection, finalizeSql).FirstOrDefault();

            if (result != 1)
            {
                _voteSate = VoteStates.EndedErrorInFinished;
                throw new NotImplementedException(Error.VotingRunnerEndedErrorInFinished);
            }

            if (_weekOfficersStorage != null)
            {
                _weekOfficersStorage.Clear();
                _weekOfficersStorage = null;
            }

            return(_buildOfficers(connection, startRegister, winners));
        }
        private void _checkAndRunVoteState(IDbConnection connection, int countError = 0, bool notifyClients = true,
                                           Exception exception = null)
        {
            void Unlock()
            {
                _checkAndRunVoteStateLocked = false;
            }

            lock (_checkAndRunVoteStateLocker)
            {
                if (countError > MAX_LIMIT_TRY)
                {
                    Unlock();
                    throw new Exception(Error.VotingRunnerTryErrorMoreMaxLimit, exception);
                }
                if (_checkAndRunVoteStateLocked)
                {
                    Task.Delay(DELAY_BETWEEN_ERRORS).MakeSync();
                    countError++;
                    _checkAndRunVoteState(connection, countError, notifyClients);
                }
                else
                {
                    try
                    {
                        _checkAndRunVoteStateLocked = true;
                        var voteInProgress        = VotingInProgress;
                        var startRegistrationTime = StartRegistrationTime;


                        if (_voteSate == VoteStates.Undefined)
                        {
                            #region модуль не инициализированн  app initialized need  restore data

                            if (countError != 0)
                            {
                                throw new NotImplementedException("_voteSate == VoteStates.Undefined");
                            }
                            if (voteInProgress)
                            {
                                _undefinedStateInVotePeriod(connection, notifyClients, startRegistrationTime, countError);
                            }
                            else
                            {
                                _undefinedStateInRegistratedPeriod(connection, notifyClients, countError);
                            }

                            #endregion
                        }

                        else
                        {
                            #region Текущее время соответствует периоду голосования

                            if (voteInProgress)
                            {
                                #region Все ок

                                // ReSharper disable once ConvertIfStatementToSwitchStatement

                                if (_voteSate == VoteStates.StartedRunned)
                                {
                                    return;
                                }

                                #endregion

                                #region внешняя ошибка в периоде голосования необходимо дополнительное вмешательство для фиксации

                                if (_voteSate == VoteStates.StartedErrorInRun)
                                {
                                    throw new Exception(Error.VotingRunnerStartedErrorInRun);
                                }

                                #endregion

                                #region  это данные предыдущего состояния, переключаем на голосование

                                if (_voteSate == VoteStates.EndedFinished)
                                {
                                    _startVoting(connection, null, notifyClients);
                                }

                                #endregion

                                #region данные назначаются необходимо подождать результатов для определения

                                else if (_voteSate == VoteStates.StartInProgress)
                                {
                                    Unlock();
                                    _checkAndRunVoteState(connection, countError, exception: exception);

                                    // _startVoting(connection, null, notifyClients);
                                }

                                #endregion

                                #region неопределенное стосояние в периоде голосвания, не относится к обрабатываемым сценариям

                                else
                                {
                                    _voteSate = VoteStates.Undefined;
                                    throw new NotImplementedException(
                                              "неопределенное стосояние в периоде голосвания, не относится к обрабатываемым сценариям ");
                                }

                                #endregion
                            }

                            #endregion

                            #region  Текущее время соответствует периоду регистрации

                            else
                            {
                                #region все ok

                                // ReSharper disable once ConvertIfStatementToSwitchStatement
                                // ReSharper disable once RedundantJumpStatement
                                if (_voteSate == VoteStates.EndedFinished)
                                {
                                    return;
                                }

                                #endregion


                                #region  период голосования  не завершен, завершаем период

                                if (_voteSate == VoteStates.StartedRunned)
                                {
                                    _endVoting(connection, notifyClients: notifyClients);
                                }

                                #endregion

                                #region внешняя ошибка в периоде регистрации необходимо дополнительное вмешательство для фиксации

                                else if (_voteSate == VoteStates.EndedErrorInFinished)
                                {
                                    throw new Exception(Error.VotingRunnerEndedErrorInFinished);
                                }

                                #endregion

                                #region  модуль не инициализированн  app initialized need  restore data

                                #endregion

                                #region данные назначаются необходимо подождать результатов для определения

                                else if (_voteSate == VoteStates.EndInProgress)
                                {
                                    try
                                    {
                                        Unlock();
                                        _checkAndRunVoteState(connection, countError, notifyClients);
                                    }
                                    catch (Exception e)
                                    {
                                        if (_voteSate == VoteStates.StartInProgress)
                                        {
                                            Unlock();
                                            _checkAndRunVoteState(connection, countError, notifyClients, e);
                                        }
                                        else
                                        {
                                            throw;
                                        }
                                    }
                                }

                                #endregion

                                #region неопределенное стосояние в периоде регистрации, не относится к обрабатываемым сценариям

                                else
                                {
                                    _voteSate = VoteStates.Undefined;
                                    throw new NotImplementedException("неопределенное стосояние в периоде регистрации, не относится к обрабатываемым сценариям");
                                }

                                #endregion
                            }

                            #endregion
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        throw;
                    }
                    finally
                    {
                        Unlock();
                    }
                }
            }
        }
        private void _undefinedStateInRegistratedPeriod(IDbConnection connection, bool notifyClients, int countError)
        {
            _voteSate = VoteStates.EndInProgress;
            try
            {
                var firstOfficer = _getFirstOfficer(connection);
                // данных нет, база пуста это 1 й запуск, создаем  любых офицеров в обход голосования
                if (firstOfficer == null)
                {
                    var userTableName         = _provider.GetTableName(nameof(user));
                    var allianceUserTableName = _provider.GetTableName(nameof(alliance_user));
                    var allianceTableName     = _provider.GetTableName(nameof(alliance));

                    var sqlAdvancdData = @"SELECT  TOP 4 " +
                                         @"u.Id as userId, " +
                                         @"u.avatarUrls as userAvatar, " +
                                         @"u.nickname as userName, " +
                                         @"u.pvpPoint as userPvpPoint, " +
                                         @"a.Id as allianceId, " +
                                         @"a.name as allianceName, " +
                                         @"a.images as allianceLabel " +
                                         $@"FROM {userTableName} AS u " +
                                         $@"JOIN {allianceUserTableName} AS au ON au.userId=u.Id " +
                                         $@"JOIN {allianceTableName} AS a ON a.Id=au.allianceId " +
                                         @"WHERE u.isNpc=0 AND u.Id>1000 ";
                    var dataWinners = _provider.Text <dynamic>(connection, sqlAdvancdData);
                    var winners     = dataWinners.Select(i => new WinnerCandidat(i)).OrderByDescending(i => i.UserPvpPoint)
                                      .ToList();
                    if (winners.Count < 4)
                    {
                        throw new NotImplementedException("winners.Count < 4");
                    }


                    var candidates = winners.Select(i => new CandidatOut {
                        UserId = i.UserId
                    }).ToList();
                    foreach (var candidat in candidates)
                    {
                        _createAndSaveNewCandidate(connection, candidat, true);
                    }
                    var officers = _buildOfficers(connection, StartRegistrationTime, winners);
                    _rebuildWeekOfficers(officers);
                    _voteSate = VoteStates.EndedFinished;
                }
                //этот офицер из прошлой недели, новых назначений небыло, нужно завершить процедуру голосвания
                else if (firstOfficer.dateEnd <= StartRegistrationTime)
                {
                    //сбрасываем состояния чтобы небыло исключения
                    _voteSate = VoteStates.Undefined;
                    _endVoting(connection, null, notifyClients);
                }
                //эот обычный период не требующий дествий,взвращаем управление проверке данных с указанным состоянием
                else
                {
                    //заполняем кеш офицерами если его нет в инсте
                    GetOfficers(connection, true);
                    //снимаем блокировку для входа
                    _checkAndRunVoteStateLocked = false;
                    // состояние определено
                    _voteSate = VoteStates.EndedFinished;
                    // определить дальнейшие действия
                    _checkAndRunVoteState(connection, countError);
                    //todo  не верно, этот сценарий перезапишет и сресетит данные, а необходимо выгрузить данные в этом состоянии
                    //  _endVoting(null, c, notifyClients);
                }
            }
            catch (Exception e)
            {
                _voteSate = VoteStates.EndedErrorInFinished;
                Console.WriteLine(e);
                throw;
            }
        }
        private void _undefinedStateInVotePeriod(IDbConnection connection, bool notifyClients,
                                                 int startRegistrationTime, int countError)
        {
            var candidatTbName = _provider.GetTableName(nameof(c_officer_candidat));

            ;
            var maxCandidatSql = $"SELECT TOP 1 * FROM {candidatTbName} ORDER BY Id DESC";
            var maxCandidat    = _provider.Text <c_officer_candidat>(connection, maxCandidatSql).FirstOrDefault();

            if (countError > MAX_LIMIT_TRY)
            {
                throw new NotImplementedException(Error.VotingRunnerTryErrorMoreMaxLimit);
            }

            try
            {
                //todo это первый запуск приложения. зарегестрированных даннх нет  или никто не зарегестрировался
                if (maxCandidat == null)
                {
                    //  создать офицеров и кандидатов
                    _undefinedStateInRegistratedPeriod(connection, false, countError);
                    // сбросить состояние на текущее
                    _voteSate = VoteStates.StartInProgress;
                    // нжно перезапросить данные после обновления и  войти в другую ветку условия
                    _undefinedStateInVotePeriod(connection, notifyClients, startRegistrationTime, countError);
                }

                // данные верны, это текущий период необходимо восстановить данные текущего переиода и поднять кеши
                else if (maxCandidat.dateCreate >= startRegistrationTime)
                {
                    // этот кандидат прошол отбор в голосование. голосование  идет, заполняем кеш
                    if (maxCandidat.isFinalizer)
                    {
                        _fillActiveCandidatesFromDb(connection);
                        _voteSate = VoteStates.StartedRunned;
                        //   _endVoting(null,c);
                    }
                    // кандидат не проходил в голосование, проверить начиналась ли процедура голосования
                    else
                    {
                        //проверка начиналось ли голосование находится внутри, выбросит исключение
                        _startVoting(connection, null, notifyClients);
                    }
                }
                //это кандидаты прошлой недели, нужно проверить текущих офицеров, является ли кандидат офицером, и очистить прошлый период
                //maxCandidat.dateCreate < startRegistrationTime
                else
                {
                    // этот кандидат  проходил отбор он может быть а может и не быть офицером
                    //логика переносит кандидатов прошлой недели в кандидат хистори
                    if (maxCandidat.isFinalizer)
                    {
                        // стереть данные в кеше если есть для верного результата
                        if (_weekOfficersStorage != null && !_weekOfficersStorage.IsEmpty)
                        {
                            _weekOfficersStorage.Clear();
                            _weekOfficersStorage = null;
                        }
                        var officers = GetOfficers(connection, true);

                        if (officers == null || !officers.Any())
                        {
                            _voteSate = VoteStates.StartedErrorInRun;
                            throw new NotImplementedException("officers == null || !officers.Any()");
                        }
                        // незнаю что это значит,  что то сделать
                        _voteSate = VoteStates.StartedErrorInRun;
                        throw new NotImplementedException();
                        //_voteSate = VoteStates.StartedRunned;
                    }

                    /*прошлые выборы были не завершенны корректно.
                     * офицеры не назначены, процедура голосвания не начата данных для восстановления недостаточно,
                     * необходимо дополнительное вмешательство*/
                    throw new NotImplementedException(
                              "прошлые выборы были  завершенны не корректно. офицеры не назначены, процедура голосвания не начата");
                }
            }
            catch (Exception e)
            {
                _voteSate = VoteStates.StartedErrorInRun;
                Console.WriteLine(e);
                throw;
            }
        }