<?php
    class ModEss_ControllerPublic_ModEss extends XenForo_ControllerPublic_Abstract
    {
        /**
         * Pre-dispatch, ensure visitor is a moderator.
         */
        protected function _preDispatch($action)
        {
            $visitor = XenForo_Visitor::getInstance();
            
            if (!$visitor['is_moderator'])
            {
                throw $this->getNoPermissionResponseException();
            }
        }
        
        protected function _requireCanManageTags()
        {
            if (!$this->_getModEssHelper()->_canManageTags())
            {
                throw $this->getNoPermissionResponseException();
            }
            
            return true;
        }
        
        protected function _canBan(XenForo_Visitor $visitor, $user = array())
        {
            if (!$visitor->hasPermission('general', 'modess_banUsers') && !$visitor->hasAdminPermission('ban'))
            {
                return false;
            }
            if (empty($user))
            {
                return true;
            }
            if (isset($user['is_admin']) && $user['is_admin'])
            {
                return false;
            }
            if (isset($user['is_moderator']) && $user['is_moderator'])
            {
                return false;
            }
            if (isset($user['user_id']) && $visitor->getUserId() === $user['user_id'])
            {
                return false;
            }
            return true;
        }
        protected function _requireCanIpSearch()
        {
            if (!$this->_getModEssHelper()->canIpSearch(XenForo_Visitor::getInstance()))
            {
                throw $this->getNoPermissionResponseException();
            }
            
            return true;
        }
        protected function _requireCanViewBannedUsers()
        {
            if (!$this->_getModEssHelper()->canViewBannedUsers(XenForo_Visitor::getInstance()))
            {
                throw $this->getNoPermissionResponseException();
            }
            
            return true;
        }
        public function actionIndex()
        {
            $checkModLog = $this->actionModLog();
            if ($checkModLog instanceof XenForo_ControllerResponse_Reroute)
            {
                if ($this->_canBan(XenForo_Visitor::getInstance()))
                {
                    return $this->actionBannedUsers();
                }
                if ($this->_getModEssHelper()->_canManageTags())
                {
                    return $this->actionTags();
                }
                
                return $this->actionIpSearch();
            }
            return $checkModLog;
        }
        
        public function actionStartDiscussion()
        {
            $logId = $this->_input->filterSingle('log_id', XenForo_Input::UINT);
            $options = XenForo_Application::getOptions();
            
            if ($options->modess_action_discussion_node > 0)
            {
                $visitor = XenForo_Visitor::getInstance()->toArray();
                $entry = $this->getModelFromCache('XenForo_Model_Log')->getModeratorLogById($logId);
                if ($entry)
                {
                    
                    if ($entry['modess_discussion_id'] > 0)
                    {
                        
                        return $this->responseRedirect(
                                                       XenForo_ControllerResponse_Redirect::SUCCESS,
                                                       XenForo_Link::buildPublicLink('threads', array('thread_id' => $entry['modess_discussion_id']))
                                                       );
                    }
                    
                    $entry = $this->getModelFromCache('XenForo_Model_Log')->prepareModeratorLogEntry($entry);
                    $writer = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread');
                    $writer->bulkSet(array(
                                           'user_id' => $visitor['user_id'],
                                           'username' => $visitor['username'],
                                           'title' => strip_tags($entry['actionText']),
                                           'prefix_id' => 0,
                                           'discussion_type' => 'modess_action_discussion',
                                           'node_id' => $options->modess_action_discussion_node
                                           ));
                    $postWriter = $writer->getFirstMessageDw();
                    
                    $postWriter->set('message', $logId);
                    $writer->save();
                    $thread = $writer->getMergedData();
                    
                    $dw = XenForo_DataWriter::create('XenForo_DataWriter_ModeratorLog');
                    $dw->setExistingData($entry['moderator_log_id']);
                    $dw->set('modess_discussion_id', $thread['thread_id']);
                    $dw->save();
                    
                    return $this->responseRedirect(
                                                   XenForo_ControllerResponse_Redirect::SUCCESS,
                                                   XenForo_Link::buildPublicLink('threads', $thread),
                                                   new XenForo_Phrase('modess_the_discussion_for_this_action_has_been_opened')
                                                   );
                }
                else
                {
                    return $this->responseError(new XenForo_Phrase('modess_invalid_moderator_log_entry'));
                }
            }
            else
            {
                return $this->responseError(new XenForo_Phrase('modess_no_moderator_action_discussion_forum_has_been_enabled'));
            }
        }
        
        public function actionLiftBan()
        {
            if (!$this->_canBan(XenForo_Visitor::getInstance()))
            {
                throw $this->getNoPermissionResponseException();
            }
            
            if ($this->isConfirmedPost())
            {
                $userId = $this->_input->filterSingle('user_id', XenForo_Input::UINT);
                
                $user = $this->getModelFromCache('XenForo_Model_User')->getUserById($userId);
                
                if (!$this->_canBan(XenForo_Visitor::getInstance(), $user))
                {
                    throw $this->getNoPermissionResponseException();
                }
                
                if ($this->getModelFromCache('XenForo_Model_User')->liftBan($userId))
                {
                    
                }
                
                return $this->responseRedirect(
                                               XenForo_ControllerResponse_Redirect::SUCCESS,
                                               XenForo_Link::buildPublicLink('members', $user),
                                               new XenForo_Phrase('you_have_successfully_lifted_the_ban_of_user_x', array('username' => $user['username']))
                                               );
            }
            else // show confirm dialog
            {
                $userId = $this->_input->filterSingle('user_id', XenForo_Input::UINT);
                $bannedUser = $this->_getBanningModel()->getBannedUserById($userId);
                if (!$bannedUser)
                {
                    return $this->responseError(new XenForo_Phrase('requested_user_not_found'), 404);
                }
                
                $viewParams = array(
                                    'bannedUser' => $bannedUser
                                    );
                return $this->responseView('ModEss_ViewPublic_Banning_User_Lift', 'modess_ban_user_lift', $viewParams);
            }
        }
        
        /**
         * Displays a form to ban a user.
         *
         * @return XenForo_ControllerResponse_Abstract
         */
        public function actionBanUser()
        {
            if ($user_id = $this->_input->filterSingle('user_id', XenForo_Input::UINT))
            {
                $user = $this->_getUserModel()->getUserById($user_id);
                if ($bannedUser = $this->_getBanningModel()->getBannedUserById($user_id))
                {
                    
                }
                else
                {
                    
                }
                
                if (!$this->_canBan(XenForo_Visitor::getInstance(), $user))
                {
                    throw $this->getNoPermissionResponseException();
                }
            }
            
            if (!isset($bannedUser) || empty($bannedUser))
            {
                $bannedUser = array(
                                    'end_date' => 0,
                                    #'user_id' => (!empty($user['user_id'])) ? $user['user_id'] : 0,
                                    'username' => (!empty($user['username'])) ? $user['username'] : ''
                                    );
            }
            
            return $this->_getUserBanAddEditResponse($bannedUser);
        }
        /**
         * Bans a user or updates an existing ban.
         *
         * @return XenForo_ControllerResponse_Abstract
         */
        /**
         * Gets the user ban add/edit controller response.
         *
         * @param array $bannedUser
         *
         * @return XenForo_ControllerResponse_Abstract
         */
        protected function _getUserBanAddEditResponse(array $bannedUser)
        {
            $viewParams = array(
                                'bannedUser' => $bannedUser,
                                );
            
            return $this->_getWrapper(
                                      'users', 'ban-user',
                                      $this->responseView('XenForo_ViewAdmin_Banning_User_Edit', 'modess_ban_user_edit', $viewParams)
                                      );
        }
        public function actionSaveUserBan()
        {
            $this->_assertPostOnly();
            
            $input = $this->_input->filter(array(
                                                 'user_id' => XenForo_Input::UINT,
                                                 'username' => XenForo_Input::STRING,
                                                 'ban_length' => XenForo_Input::STRING,
                                                 'end_date' => XenForo_Input::DATE_TIME,
                                                 'user_reason' => XenForo_Input::STRING
                                                 ));
            
            $userModel = $this->getModelFromCache('XenForo_Model_User');
            
            $existing = ($input['user_id'] != 0);
            if (!$existing)
            {
                $user = $userModel->getUserByName($input['username']);
                if (!$user)
                {
                    return $this->responseError(new XenForo_Phrase('requested_user_not_found'));
                }
                
                if (!$this->_canBan(XenForo_Visitor::getInstance(), $user))
                {
                    throw $this->getNoPermissionResponseException();
                }
                
                $input['user_id'] = $user['user_id'];
            }
            
            if ($input['ban_length'] == 'permanent')
            {
                $input['end_date'] = 0;
            }
            
            if (!$userModel->ban($input['user_id'], $input['end_date'], $input['user_reason'], $existing, $errorKey))
            {
                return $this->responseError(new XenForo_Phrase($errorKey));
            }
            return $this->responseRedirect(
                                           XenForo_ControllerResponse_Redirect::SUCCESS,
                                           XenForo_Link::buildPublicLink('members', $user),
                                           new XenForo_Phrase('you_have_successfully_banned_user_x', array('username' => $user['username']))
                                           );
        }
        
        public function actionBannedUsers()
        {
            if (!$this->_requireCanViewBannedUsers(XenForo_Visitor::getInstance()))
            {
                return $this->getNoPermissionResponseException();
            }
            
            $page = $this->_input->filterSingle('page', XenForo_Input::UINT);
            $perPage = 10;
            
            $conditions = array();
            
            $filter = $this->_input->filterSingle('_filter', XenForo_Input::ARRAY_SIMPLE);
            if ($filter && isset($filter['value']))
            {
                $conditions['username'] = array($filter['value'], empty($filter['prefix']) ? 'lr' : 'r');
                $filterView = true;
            }
            else
            {
                $filterView = false;
            }
            
            $banningModel = $this->_getBanningModel();
            
            $totalBanned = $banningModel->countBannedUsers($conditions);
            
            $viewParams = array(
                                'bannedUsers' => $banningModel->getBannedUsers($conditions, array('page' => $page, 'perPage' => $perPage)),
                                
                                'totalBanned' => $totalBanned,
                                'page' => $page,
                                'perPage' => $perPage,
                                
                                'filterView' => $filterView,
                                'filterMore' => ($filterView && $totalBanned > $perPage)
                                );
            
            return $this->_getWrapper(
                                      'users', 'banned-users',
                                      $this->responseView('XenForo_ViewPublic_Base', 'modess_ban_user_list', $viewParams)
                                      );
        }
        
        /**
         * Display all logs created since last time log was checked, or custom search
         * @return XenForo_ViewPublic_Base
         */
        public function actionModLog()
        {
            $visitor = XenForo_Visitor::getInstance();
            if (!$visitor['is_moderator'] || !$visitor->hasPermission('general', 'canViewModLogCounts'))
            {
                return $this->responseNoPermission();
            }
            
            $modEssModel = $this->_getModEssModel();
            $logCounts = $modEssModel->getModLogCounts();
            
            if (!isset($logCounts[$visitor['user_id']]))
                return $this->responseNoPermission();
            
            $sessionLogCounts = $logCounts[$visitor['user_id']];
            
            if (!$sessionLogCounts['isActive'])
                return $this->responseNoPermission();
            
            $numDays = $desiredActions = $requestedType = $requestedAction = $requestedUser = $fromDate = $totalCount = null;
            $customSearch = false;
            $entries = array();
            $pageEntries = array();
            $pageNavParams = array();
            $searchParams = array(
                                  'num_days' => 1,
                                  'requested_type' => 'all',
                                  'requested_action' => 'all'
                                  );
            
            $options = XenForo_Application::get('options');
            $logModel = $this->_getLogModel();
            $perPage = $options->modess_mod_log_per_page;
            $page = max(1, $this->_input->filterSingle('page', XenForo_Input::UINT));
            
            // if Thread Ban is installed then add those actions
            $addOns = XenForo_Application::get('addOns'); // $this->_getDataRegistryModel()->get('addOns');
            if (isset($addOns['ThreadBan']))
                $doIncludeThreadBans = 1;
            else
                $doIncludeThreadBans = 0;
            
            // if Resource Manager is installed then add those actions
            if (isset($addOns['XenResource']) && $visitor->hasPermission('resource', 'view'))
                $doIncludeResources = 1;
            else
                $doIncludeResources = 0;
            
            $doIncludeWarnings = $options->modess_log_warnings['modlog'] && $visitor->hasPermission('general', 'viewWarning') ? 1 : 0;
            
            $specificActions = $modEssModel->getModLogActionsForTemplate($doIncludeThreadBans, $doIncludeResources, $doIncludeWarnings);
            $searchId = $this->_input->filterSingle('sid', XenForo_Input::UINT);
            
            if ($searchId)
            {
                $search = $modEssModel->getModLogSearchById($searchId);
                
                if (!empty($search)	&& $search['user_id'] == $visitor['user_id'])
                {
                    $searchParams = json_decode($search['search_params'], true);
                    if (!empty($searchParams))
                    {
                        if (isset($searchParams['desired_actions']))
                            $desiredActions = $searchParams['desired_actions'];
                        else
                            $desiredActions = array();
                        
                        $numDays = $searchParams['num_days'];
                        if ($numDays)
                            $customSearch = true;
                        
                        $requestedType = $searchParams['requested_type'];
                        $requestedAction = $searchParams['requested_action'];
                        $requestedUser = $searchParams['requested_user'];
                        $fromDate = $searchParams['from_date'];
                    }
                    
                    $pageNavParams['sid'] = $search['search_id'];
                    $entryIds = json_decode($search['search_results'], true);
                    $totalCount = $search['result_count'];
                    $numPages = ceil($totalCount / $perPage);
                    if ($page > $numPages)
                        $page = $numPages;
                    
                    // grab the ones for the current page
                    $from = ($page - 1) * $perPage;
                    $pageEntries = array_slice($entryIds, $from, $perPage, true);
                    if (!empty($pageEntries))
                        $pageEntries = $logModel->getModLogEntriesByIds($pageEntries, false); // false for skipping the weedout check
                    
                    if ($requestedAction == 'specific')
                    {
                        foreach ($specificActions AS $key => &$value)
                        {
                            if (isset($desiredActions[$key]))
                            {
                                $value['checked'] = 1;
                                $searchParams['desired_actions'][$key] = 1;
                            }
                        }
                    }
                }
            }
            else
            {
                if (!isset($numDays))
                    $numDays = $this->_input->filterSingle('num_days', XenForo_Input::UINT);
                if ($numDays)
                    $customSearch = true;
                
                $fetchOptions = array();
                $timeNow = XenForo_Application::$time;
                
                if ($customSearch)
                {
                    $fetchActions = array();
                    $fromDate = $timeNow - ($numDays * 86400);
                    
                    if (!isset($requestedType))
                        $requestedType = $this->_input->filterSingle('requested_type', XenForo_Input::STRING); // all, thread, post, profile_post, threadban
                    if (!$requestedType)
                        $requestedType = 'all';
                    
                    if (!isset($requestedAction))
                        $requestedAction = $this->_input->filterSingle('requested_action', XenForo_Input::STRING); // all, specific
                    if (!$requestedAction)
                        $requestedAction = 'all';
                    
                    if ($requestedAction == 'specific')
                    {
                        if (!isset($desiredActions))
                            $desiredActions = $this->_input->filterSingle('desired_actions', XenForo_Input::ARRAY_SIMPLE);
                        
                        if (empty($desiredActions)) // if none were un-checked then skip and fetch all
                        {
                            $requestedAction = 'all';
                        }
                        else
                        {
                            $typeActions = $modEssModel->getModLogActionsForTemplate($doIncludeThreadBans, $doIncludeResources, $doIncludeWarnings, $requestedType);
                            
                            if (count($typeActions) != count($desiredActions)) // if all were checked then skip specific actions and fetch all
                            {
                                foreach ($typeActions AS $key => $value)
                                {
                                    if (isset($desiredActions[$key]))
                                    {
                                        if ($value['type'] == 'all')
                                        {
                                            if (empty($requestedType) || $requestedType == 'all')
                                            {
                                                $fetchActions['post'][] = $key;
                                                $fetchActions['profile_post'][] = $key;
                                                $fetchActions['thread'][] = $key;
                                                $fetchActions['resource'][] = $key;
                                                $fetchActions['resource_update'][] = $key;
                                                $fetchActions['modess'][] = $key;
                                            }
                                            else if ($requestedType == 'resource')
                                            {
                                                $fetchActions['resource'][] = $key;
                                                $fetchActions['resource_update'][] = $key;
                                            }
                                            else
                                            {
                                                $fetchActions[$requestedType][] = $key;
                                            }
                                        }
                                        else if ($value['type'] == 'post_thread')
                                        {
                                            if (empty($requestedType) || $requestedType == 'all')
                                            {
                                                $fetchActions['post'][] = $key;
                                                $fetchActions['thread'][] = $key;
                                            }
                                            else
                                            {
                                                $fetchActions[$requestedType][] = $key;
                                            }
                                        }
                                        else if ($value['type'] == 'threadban')
                                        {
                                            if ($doIncludeThreadBans)
                                                $fetchActions['thread'][] = $key;
                                            else
                                                continue;
                                        }
                                        else if ($value['type'] == 'resource')
                                        {
                                            if ($doIncludeResources)
                                            {
                                                if ($key == 'resource_edit' || $key == 'resource_update_edit')
                                                {
                                                    $realKey = 'edit';
                                                }
                                                else if ($key == 'resource_reassign')
                                                {
                                                    $realKey = 'reassign';
                                                }
                                                else if ($key == 'resource_feature')
                                                {
                                                    $realKey = 'feature';
                                                }
                                                else if ($key == 'resource_unfeature')
                                                {
                                                    $realKey = 'unfeature';
                                                }
                                                else
                                                {
                                                    $realKey = $key;
                                                }
                                                
                                                $fetchActions['resource'][] = $realKey;
                                            }
                                            else
                                                continue;
                                        }
                                        else if ($value['type'] == 'modess')
                                        {
                                            if ($key == 'warn' && $doIncludeWarnings)
                                            {
                                                // we count all actions under 'warn'
                                                $fetchActions['modess'][] = 'warn';
                                                $fetchActions['modess'][] = 'warn_update';
                                                $fetchActions['modess'][] = 'warn_delete';
                                            }
                                            else
                                                continue;
                                        }
                                        else
                                        {
                                            $fetchActions[$value['type']][] = $key;
                                        }
                                        
                                        $specificActions[$key]['checked'] = 1;
                                        $searchParams['desired_actions'][$key] = 1;
                                    }
                                }
                            }
                        }
                    }
                    
                    $skipActions = array();
                    
                    if ($requestedType != 'all')
                    {
                        if ($requestedType == 'threadban')
                            $fetchOptions['content_type'] = 'thread';
                        else
                            $fetchOptions['content_type'] = $requestedType;
                        
                        if ($doIncludeThreadBans)
                        {
                            if (!isset($fetchActions['thread']))
                            {
                                if ($requestedType == 'threadban')
                                {
                                    // if no specific action selected, add all threadban actions
                                    // since threadban uses the thread type we must include those explicitly
                                    $fetchActions['thread'][] = 'threadban';
                                    $fetchActions['thread'][] = 'threadban_edit';
                                    $fetchActions['thread'][] = 'threadbanlift_cron';
                                    $fetchActions['thread'][] = 'threadbanlift';
                                }
                                else if ($requestedType == 'thread')
                                {
                                    // since threadban uses the thread type we must exclude those from a thread type search
                                    $skipActions['include']['thread'][] = 'threadban';
                                    $skipActions['include']['thread'][] = 'threadban_edit';
                                    $skipActions['include']['thread'][] = 'threadbanlift_cron';
                                    $skipActions['include']['thread'][] = 'threadbanlift';
                                }
                            }
                        }
                    }
                    
                    if ($requestedType == 'thread' || $requestedType == 'all')
                    {
                        // if AVForums_ModCheckpoint is installed then do not fetch the 'posts_checked' entries as they are not needed
                        if (isset($addOns['AVForums_ModCheckpoint']))
                        {
                            $skipActions['include']['thread'][] = 'posts_checked';
                            $skipActions['include']['thread'][] = 'bulk_posts_checked';
                        }
                    }
                    
                    if (!$doIncludeResources)
                    {
                        unset($fetchActions['resource'], $fetchActions['resource_update']);
                    }
                    
                    if (!$doIncludeWarnings)
                    {
                        unset($fetchActions['modess']);
                        /*
                         // currently the 'modess' type only includes warning stuff but if other actions are added then use the following
                         if (isset($fetchActions['modess']))
                         {
                         foreach ($fetchActions['modess'] AS $key => $value)
                         {
                         if ($value == 'warn' || $value == 'warn_update' || $value == 'warn_delete')
                         unset($fetchActions['modess'][$key]);
                         }
                         
                         if (empty($fetchActions['modess']))
                         unset($fetchActions['modess']);
                         }
                         */
                        
                        // this user cannot view warnings but they are still saved in the log
                        // therefore we must skip the action as default is to fetch all log types
                        if (empty($fetchActions) && $options->modess_log_warnings['dolog'])
                        {
                            $skipActions['exclude']['modess'] = array();
                            //$skipActions['exclude']['modess'][] = 'warn';
                            //$skipActions['exclude']['modess'][] = 'warn_update';
                            //$skipActions['exclude']['modess'][] = 'warn_delete';
                        }
                    }
                    
                    if (!isset($requestedUser))
                    {
                        $requestedUser = $this->_input->filterSingle('requested_user', XenForo_Input::STRING); // all, exclude self, mod name
                    }
                    
                    if (!empty($requestedUser) && $requestedUser != 'all')
                    {
                        if ($requestedUser == 'all_but_self')
                            $fetchOptions['exclude_user_ids'] = array($visitor['user_id']);
                        else
                            $fetchOptions['include_user_ids'] = array(intval($requestedUser));
                    }
                    
                    if (!empty($fetchActions))
                    {
                        $fetchOptions['actions'] = $fetchActions;
                    }
                    
                    if (!empty($skipActions))
                    {
                        $fetchOptions['skip_actions'] = $skipActions;
                    }
                    
                    // get only logs from forums where the user has permission to view the thread log
                    $entries = $logModel->getViewableModLogEntries($fromDate, $fetchOptions);
                }
                else // not custom search
                {
                    $sessionLogDisabled = false; // whether to skip fetching entries since last check and thus only have custom searches
                    $fromDate = $sessionLogCounts['lastViewDate']; // fetch all since last log view
                    $preferences = $modEssModel->getModEssPreferencesByUserId($visitor['user_id']);
                    if (!empty($preferences))
                    {
                        $desiredType = $preferences['action_type'];
                        if ($desiredType == 'none')
                        {
                            $sessionLogDisabled = true; // user does not want to be notified of new entries
                        }
                    }
                    
                    // get only logs from forums where the user has permission to view the thread log
                    if (!$sessionLogDisabled)
                    {
                        $entryIds = $sessionLogCounts['logIds'];
                        if ($entryIds)
                        {
                            $entryIds = explode(',', $entryIds);
                            $entries = $logModel->getModLogEntriesByIds($entryIds);
                        }
                    }
                }
                
                if (!empty($entries))
                {
                    $totalCount = count($entries); // count after unviewables were weeded out
                    $numPages = ceil($totalCount / $perPage);
                    if ($page > $numPages)
                        $page = $numPages;
                    
                    // grab the ones for the current page
                    $from = ($page - 1) * $perPage;
                    $pageEntries = array_slice($entries, $from, $perPage, true);
                    
                    // if multiple pages then save results
                    if (($totalCount / $perPage) > 1)
                    {
                        $searchParams['num_days'] = $numDays;
                        $searchParams['from_date'] = $fromDate;
                        $searchParams['requested_type'] = $requestedType;
                        $searchParams['requested_action'] = $requestedAction;
                        $searchParams['requested_user'] = $requestedUser;
                        $searchParams['from_date'] = $fromDate;
                        //(array $resultIds, array $params, $userId = null, $searchDate = null)
                        $search = $modEssModel->insertModLogSearch(array_keys($entries), $searchParams);
                        $pageNavParams['sid'] = $search['search_id'];
                    }
                }
                else
                {
                    $totalCount = 0;
                    $page = 1;
                }
                
                if (!$customSearch)
                {
                    // update session count
                    $sessionLogCounts = array('total' => 0, 'lastViewDate' => $timeNow, 'logIds' => '', 'isActive' => true);
                    XenForo_Application::get('session')->set('modLogCounts', $sessionLogCounts);
                    
                    // update registry count
                    $logCounts[$visitor['user_id']] = $sessionLogCounts;
                    $this->_getDataRegistryModel()->set('modLogCounts', $logCounts);
                }
            }
            
            // process the logs
            if (!empty($pageEntries))
            {
                $pageEntries = $logModel->addLinksToModLogEntries($pageEntries); // add content links
                $pageEntries = $logModel->prepareModeratorLogEntries($pageEntries); // prepare logs
            }
            
            // limit entries to the last X days
            $maxDays = $options->modess_mod_log_search_max_days;
            if ($maxDays < 1)
                $maxDays = 1;
            
            // an array of max available days for the template's num_days
            $maxDaysArray = array();
            $i = 1;
            while ($i <= $maxDays)
            {
                $maxDaysArray[$i] = $i;
                $i++;
            }
            
            $viewParams = array(
                                'logEntries' => $pageEntries,
                                'totalCount' => $totalCount,
                                'lastViewDate' => $fromDate,
                                'page' => $page,
                                'perPage' => $perPage,
                                'canViewIp' => ($options->modess_mod_log_show_ips && $visitor->hasPermission('general', 'viewIps')),
                                'customSearch' => $customSearch,
                                'maxDays' => $maxDays,
                                'maxDaysArray' => $maxDaysArray,
                                'specificActions' => $specificActions,
                                'doIncludeThreadBans' => $doIncludeThreadBans,
                                'doIncludeResources' => $doIncludeResources,
                                'doIncludeWarnings' => $doIncludeWarnings,
                                'mods' => $modEssModel->getSessionModLogModerators()
                                );
            
            if ($customSearch)
            {
                $viewParams['requestedType'] = $requestedType;
                $viewParams['requestedAction'] = $requestedAction;
                $viewParams['requestedUser'] = $requestedUser;
                $viewParams['numDays'] = $numDays;
            }
            
            if (empty($pageEntries))
            {
                $viewParams['linkPreferences'] = XenForo_Link::buildPublicLink('account/preferences');
                $viewParams['linkLast24Hours'] = XenForo_Link::buildPublicLink('modess/modLog', '', array('num_days' => 1));
            }
            
            $viewParams['pageNavParams'] = $pageNavParams;
            
            return $this->_getWrapper(
                                      'logs', 'modess',
                                      $this->responseView('XenForo_ViewPublic_Base', 'modess_session_mod_log', $viewParams)
                                      );
        }
        
        public function actionIpSearch()
        {
            $this->_requireCanIpSearch();
            
            if ($this->_request->isPost())
            {
                $ip = $this->_input->filterSingle('ip', XenForo_Input::STRING);
                
                $fetchOptions = array(
                                      'join' => XenForo_Model_User::FETCH_USER_PROFILE
                                      );
                
                $ipDetails = XenForo_Helper_Ip::parseIpRangeString($ip);
                if (!$ipDetails)
                {
                    return $this->_getWrapper(
                                              'users', 'ip-search',
                                              $this->responseView('XenForo_ViewPublic_Base', 'modess_users_ip_search', array(
                                                                                                                             'message' => new XenForo_Phrase('please_enter_valid_ip_or_ip_range')
                                                                                                                             ))
                                              );
                }
                else if ($ipDetails['isRange'])
                {
                    $users = $this->_getUserModel()->getUsersByIpRange(
                                                                       $ipDetails['startRange'], $ipDetails['endRange'], $fetchOptions
                                                                       );
                }
                else
                {
                    $users = $this->_getUserModel()->getUsersByIp(
                                                                  $ip, $fetchOptions
                                                                  );
                }
                
                if ($users)
                {
                    $viewParams = array(
                                        'users' => $users,
                                        'ip' => $ip,
                                        'ipPrintable' => $ipDetails['printable']
                                        );
                    
                    return $this->_getWrapper(
                                              'users', 'ip-search',
                                              $this->responseView('XenForo_ViewPublic_Users_IpUsers', 'modess_users_ip_users', $viewParams)
                                              );
                }
                else
                {
                    $viewParams = array(
                                        'message' => new XenForo_Phrase('no_users_logged_at_ip')
                                        );
                    
                    return $this->_getWrapper(
                                              'users', 'ip-search',
                                              $this->responseView('XenForo_ViewPublic_Users_IpUsers', 'modess_users_ip_search', $viewParams)
                                              );
                }
            }
            else
            {
                return $this->_getWrapper(
                                          'users', 'ip-search',
                                          $this->responseView('XenForo_ViewPublic_Base', 'modess_users_ip_search', array())
                                          );
            }
        }
        
        public function actionTags()
        {
            $this->_requireCanManageTags();
            
            $page = max(1, $this->_input->filterSingle('page', XenForo_Input::UINT));
            $perPage = 50;
            
            $tagModel = $this->_getTagModel();
            
            $containing = $this->_input->filterSingle('containing', XenForo_Input::STRING);
            $order = $this->_input->filterSingle('order', XenForo_Input::STRING);
            
            $total = $tagModel->countTagList($containing);
            $this->canonicalizePageNumber($page, $perPage, $total, 'tags');
            
            $tags = $tagModel->getTagList($containing, array(
                                                             'order' => $order,
                                                             'page' => $page,
                                                             'perPage' => $perPage
                                                             ));
            
            $viewParams = array(
                                'tags' => $tags,
                                'page' => $page,
                                'perPage' => $perPage,
                                'total' => $total,
                                'containing' => $containing,
                                'order' => $order
                                );
            return $this->_getWrapper(
                                      'tags', 'list',
                                      $this->responseView('XenForo_ViewPublic_Tag_List', 'modess_tag_list', $viewParams)
                                      );
        }
        
        protected function _getTagAddEditResponse(array $tag)
        {
            $viewParams = array(
                                'tag' => $tag
                                );
            return $this->_getWrapper(
                                      'tags', 'list',
                                      $this->responseView('XenForo_ViewPublic_Tag_Edit', 'modess_tag_edit', $viewParams
                                                          )
                                      );
        }
        
        public function actionAddTag()
        {
            $this->_requireCanManageTags();
            return $this->_getTagAddEditResponse(array(
                                                       'tag' => '',
                                                       'tag_url' => '',
                                                       'permanent' => 1
                                                       ));
        }
        
        public function actionEditTag()
        {
            $this->_requireCanManageTags();
            $tagId = $this->_input->filterSingle('tag_id', XenForo_Input::UINT);
            $tag = $this->_getTagOrError($tagId);
            
            return $this->_getTagAddEditResponse($tag);
        }
        
        public function actionSaveTag()
        {
            $this->_requireCanManageTags();
            
            $this->_assertPostOnly();
            
            $tagId = $this->_input->filterSingle('tag_id', XenForo_Input::UINT);
            $dwData = $this->_input->filter(array(
                                                  'tag' => XenForo_Input::STRING,
                                                  'tag_url' => XenForo_Input::STRING,
                                                  'permanent' => XenForo_Input::BOOLEAN
                                                  ));
            
            $dw = XenForo_DataWriter::create('XenForo_DataWriter_Tag');
            if ($tagId)
            {
                $dw->setExistingData($tagId);
            }
            $dw->bulkSet($dwData);
            $dw->save();
            
            return $this->responseRedirect(
                                           XenForo_ControllerResponse_Redirect::SUCCESS,
                                           XenForo_Link::buildPublicLink('modess/tags')
                                           );
        }
        
        public function actionDeleteTag()
        {
            $this->_requireCanManageTags();
            if ($this->isConfirmedPost())
            {
                return $this->_deleteData(
                                          'XenForo_DataWriter_Tag', 'tag_id',
                                          XenForo_Link::buildPublicLink('modess/tags')
                                          );
            }
            else
            {
                $tagId = $this->_input->filterSingle('tag_id', XenForo_Input::UINT);
                $tag = $this->_getTagOrError($tagId);
                
                $viewParams = array(
                                    'tag' => $tag
                                    );
                
                return $this->responseView('XenForo_ViewAdmin_Tag_Delete', 'modess_tag_delete', $viewParams);
            }
        }
        
        public function actionMergeTag()
        {
            $this->_requireCanManageTags();
            $tagId = $this->_input->filterSingle('tag_id', XenForo_Input::UINT);
            $tag = $this->_getTagOrError($tagId);
            
            if ($this->isConfirmedPost())
            {
                $targetName = $this->_input->filterSingle('target', XenForo_Input::STRING);
                $targetTag = $this->_getTagModel()->getTag($targetName);
                if (!$targetTag)
                {
                    return $this->responseError(new XenForo_Phrase('requested_tag_not_found'));
                }
                
                if ($targetTag['tag_id'] == $tag['tag_id'])
                {
                    return $this->responseError(new XenForo_Phrase('you_may_not_merge_tag_with_itself'));
                }
                
                $this->_getTagModel()->mergeTags($tag['tag_id'], $targetTag['tag_id']);
                
                return $this->responseRedirect(
                                               XenForo_ControllerResponse_Redirect::SUCCESS,
                                               XenForo_Link::buildPublicLink('modess/tags')
                                               );
            }
            else
            {
                $viewParams = array(
                                    'tag' => $tag
                                    );
                
                return $this->responseView('XenForo_ViewAdmin_Tag_Merge', 'modess_tag_merge', $viewParams);
            }
        }
        
        public function actionThreadsReplyBans()
        {
            /*
             * per forum
             * per user
             */
            
            $order = 'ban_date';
            $direction = 'desc';
            
            $page = $this->_input->filterSingle('page', XenForo_Input::UINT);
            $perPage = 25;
            
            $username = $this->_input->filterSingle('username', XenForo_Input::STRING);
            if ($username)
            {
                $user = $this->getModelFromCache('XenForo_Model_User')->getUserByName($username);
            }
            else
            {
                $user = null;
            }
            
            $nodeId = $this->_input->filterSingle('node_id', XenForo_Input::UINT);
            if ($nodeId)
            {
                $node = $this->_getNodeModel()->getNodeById($nodeId);
            }
            else
            {
                $node = null;
            }
            
            $linkParams = array();
            $conditions = array();
            $fetchOptions = array(
                                  'perPage' => $perPage,
                                  'page' => $page,
                                  'join' => XenForo_Model_Thread::FETCH_REPLY_BAN_FORUM,
                                  
                                  'order' => $order,
                                  'direction' => $direction
                                  );
            
            if ($user)
            {
                $conditions['user_id'] = $user['user_id'];
                $linkParams['username'] = $user['username'];
            }
            
            if ($node)
            {
                $conditions['node_id'] = $node['node_id'];
                $linkParams['node_id'] = $node['node_id'];
            }
            
            $threadModel = $this->_getThreadModel();
            
            // count reply bans
            $totalBans = $threadModel->countThreadReplyBans($conditions);
            
            // display reply bans
            $bans = $threadModel->getThreadReplyBans($conditions, $fetchOptions);
            
            $viewParams = array(
                                'bans' => $bans,
                                'totalBans' => $totalBans,
                                
                                'node' => $node,
                                
                                'nodes' => $this->_getNodeModel()->getNodeOptionsArray(
                                                                                       $this->_getNodeModel()->getPossibleParentNodes(null), $nodeId, true
                                                                                       ),
                                'user' => $user,
                                
                                'linkParams' => $linkParams,
                                'page' => $page,
                                'perPage' => $perPage,
                                );
            
            return $this->_getWrapper(
                                      'threads', 'reply-bans',
                                      $this->responseView('XenForo_ViewAdmin_Thread_ReplyBans', 'modess_thread_reply_ban_list', $viewParams)
                                      );
        }
        
        public function actionThreadsReplyBansDelete()
        {
            $threadId = $this->_input->filterSingle('thread_id', XenForo_Input::UINT);
            $userId = $this->_input->filterSingle('user_id', XenForo_Input::UINT);
            
            $thread = $this->_getThreadModel()->getThreadById($threadId);
            $user = $this->getModelFromCache('XenForo_Model_User')->getUserById($userId);
            
            if (!$thread || !$user)
            {
                return $this->responseError(new XenForo_Phrase('requested_page_not_found'));
            }
            
            $ftpHelper = $this->getHelper('ForumThreadPost');
            list($thread, $forum) = $ftpHelper->assertThreadValidAndViewable($threadId);
            
            $threadModel = $this->_getThreadModel();
            if (!$threadModel->canReplyBanUserFromThread($user, $thread, $forum, $errorPhraseKey))
            {
                throw $this->getErrorOrNoPermissionResponseException($errorPhraseKey);
            }
            
            if ($this->isConfirmedPost())
            {
                $this->_getThreadModel()->deleteThreadReplyBan($thread, $user);
                
                return $this->responseRedirect(
                                               XenForo_ControllerResponse_Redirect::SUCCESS,
                                               XenForo_Link::buildPublicLink('modess/threads/reply-bans')
                                               );
            }
            else
            {
                $viewParams = array(
                                    'thread' => $thread,
                                    'user' => $user
                                    );
                return $this->responseView('XenForo_ViewAdmin_Thread_ReplyBansDelete', 'modess_thread_reply_ban_delete', $viewParams);
            }
        }
        
        /**
         * Gets the modess pages wrapper.
         *
         * @param string $selectedGroup
         * @param string $selectedLink
         * @param XenForo_ControllerResponse_View $subView
         *
         * @return XenForo_ControllerResponse_View
         */
        protected function _getWrapper($selectedGroup, $selectedLink, XenForo_ControllerResponse_View $subView)
        {
            return $this->_getModEssHelper()->getWrapper($selectedGroup, $selectedLink, $subView);
        }
        
        /* @return ModEss_ControllerHelper_Modess */
        protected function _getModEssHelper()
        {
            return $this->getHelper('ModEss_ControllerHelper_Modess');
        }
        
        /**
         * Session activity details.
         * @see XenForo_Controller::getSessionActivityDetailsForList()
         */
        public static function getSessionActivityDetailsForList(array $activities)
        {
            return new XenForo_Phrase('performing_moderation_duties');
        }
        
        /**
         * @param integer $tagId
         *
         * @return array
         */
        protected function _getTagOrError($tagId)
        {
            $tag = $this->_getTagModel()->getTagById($tagId);
            if (!$tag)
            {
                throw $this->responseException($this->responseError(new XenForo_Phrase('requested_tag_not_found'), 404));
            }
            
            return $tag;
        }
        
        /**
         * @return  XenForo_Model_Tag
         */
        protected function _getTagModel()
        {
            return $this->getModelFromCache('XenForo_Model_Tag');
        }
        
        /**
         * @return XenForo_Model_DataRegistry
         */
        protected function _getDataRegistryModel()
        {
            return $this->getModelFromCache('XenForo_Model_DataRegistry');
        }
        
        /**
         * @return XenForo_Model_Thread
         */
        protected function _getThreadModel()
        {
            return $this->getModelFromCache('XenForo_Model_Thread');
        }
        
        /**
         * @return XenForo_Model_Log
         */
        protected function _getLogModel()
        {
            return $this->getModelFromCache('XenForo_Model_Log');
        }
        
        /**
         * @return ModEss_Model_ModEss
         */
        protected function _getModEssModel()
        {
            return $this->getModelFromCache('ModEss_Model_ModEss');
        }
        
        /**
         * @return XenForo_Model_AddOn
         */
        protected function _getAddOnModel()
        {
            return $this->getModelFromCache('XenForo_Model_AddOn');
        }
        
        /**
         * @return XenForo_Model_Banning
         */
        protected function _getBanningModel()
        {
            return $this->getModelFromCache('XenForo_Model_Banning');
        }
        
        /**
         * @return XenForo_Model_User
         */
        protected function _getUserModel()
        {
            return $this->getModelFromCache('XenForo_Model_User');
        }
        /**
         * @return XenForo_Model_Ip
         */
        protected function _getIpModel()
        {
            return $this->getModelFromCache('XenForo_Model_Ip');
        }
        /**
         * @return XenForo_Model_Node
         */
        protected function _getNodeModel()
        {
            return $this->getModelFromCache('XenForo_Model_Node');
        }
    }