<?php
namespace XF\Criteria;
class Thread extends AbstractCriteria
{
    /**
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    public function isMatchedThread(\XF\Entity\Thread $thread)
    {
        if (!$this->criteria)
        {
            return $this->matchOnEmpty;
        }
        
        foreach ($this->criteria AS $criterion)
        {
            $rule = $criterion['rule'];
            $data = $criterion['data'];
            
            $specialResult = $this->isSpecialMatchedThread($rule, $data, $thread);
            if ($specialResult === false)
            {
                return false;
            }
            else if ($specialResult === true)
            {
                continue;
            }
            
            $method = '_matchThread' . \XF\Util\Php::camelCase($rule);
            if (method_exists($this, $method))
            {
                $result = $this->$method($data, $thread);
                if (!$result)
                {
                    return false;
                }
            }
            else
            {
                if (!$this->isUnknownMatchedThread($rule, $data, $thread))
                {
                    return false;
                }
            }
        }
        
        return true;
    }
    
    /**
     * @param $rule
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool|null
     */
    protected function isSpecialMatchedThread($rule, array $data, \XF\Entity\Thread $thread)
    {
        // custom user fields
        if (preg_match('/^thread_field_(.+)$/', $rule, $matches))
        {
            /** @var \XF\CustomField\Set|null $cFS */
            $cFS = $thread->thread_id ? $thread->custom_fields : null;
            
            $fieldId = $matches[1];
            
            if (!$cFS || !isset($cFS->{$fieldId}))
            {
                return false;
            }
            
            $value = $cFS->{$fieldId};
            
            // text fields - check that data exists within the text value
            if (isset($data['text']))
            {
                if (stripos($value, $data['text']) === false)
                {
                    return false;
                }
            }
            // choice fields - check that data is in the choice array
            else if (isset($data['choices']))
            {
                // multi-choice
                if (is_array($value))
                {
                    if (!array_intersect($value, $data['choices']))
                    {
                        return false;
                    }
                }
                // single choice
                else
                {
                    if (!in_array($value, $data['choices']))
                    {
                        return false;
                    }
                }
            }
            
            return true;
        }
        
        return null;
    }
    
    /**
     * @param $rule
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function isUnknownMatchedThread($rule, array $data, \XF\Entity\Thread $thread)
    {
        $eventReturnValue = false;
        $this->app->fire('criteria_thread', [$rule, $data, $thread, &$eventReturnValue]);
        
        return $eventReturnValue;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadForum(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->node_id && in_array($thread->node_id, $data['forum_ids']));
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadPrefix(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->prefix_id && in_array($thread->prefix_id, $data['prefix_ids']));
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadReplyCount(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->reply_count && $thread->reply_count >= $data['messages']);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadReplyCountMaximum(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->reply_count <= $data['messages']);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadViewCount(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->view_count && $thread->view_count >= $data['amount']);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadViewCountMaximum(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->view_count <= $data['amount']);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadDiscussionState(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->discussion_state && $thread->discussion_state == $data['state']);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadIsOpen(array $data, \XF\Entity\Thread $thread)
    {
        return (bool)$thread->discussion_open;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadNoOpen(array $data, \XF\Entity\Thread $thread)
    {
        return $thread->discussion_open ? false : true;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadIsSticky(array $data, \XF\Entity\Thread $thread)
    {
        return (bool)$thread->sticky;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadNoSticky(array $data, \XF\Entity\Thread $thread)
    {
        return $thread->sticky ? false : true;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterIsGuest(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->user_id == 0);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterIsMember(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->user_id > 0);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterIsModerator(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->User)
        {
            return false;
        }
        
        return (bool)$thread->User->is_moderator;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterIsAdmin(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->User)
        {
            return false;
        }
        
        return (bool)$thread->User->is_admin;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterTime(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->post_date)
        {
            return false;
        }
        $threadAge = floor((time() - $thread->post_date) / 86400);
        if ($threadAge < $data['days'])
        {
            return false;
        }
        
        return true;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterLikeCount(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->first_post_likes && $thread->first_post_likes >= $data['likes']);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterUsername(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->username)
        {
            return false;
        }
        
        $names = preg_split('/\s*,\s*/', utf8_strtolower($data['names']), -1, PREG_SPLIT_NO_EMPTY);
        return in_array(utf8_strtolower($thread->username), $names);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterUsernameSearch(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->username)
        {
            return false;
        }
        
        if ($this->findNeedle($data['needles'], $thread->username) === false)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyIsGuest(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->last_post_user_id == 0);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyIsMember(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->last_post_user_id > 0);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyIsStarter(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->last_post_user_id == $thread->user_id);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyIsModerator(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->LastPoster)
        {
            return false;
        }
        
        return (bool)$thread->LastPoster->is_moderator;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyIsAdmin(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->LastPoster)
        {
            return false;
        }
        
        return (bool)$thread->LastPoster->is_admin;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyTime(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->last_post_date)
        {
            return false;
        }
        $lastReplyAge = floor((time() - $thread->last_post_date) / 86400);
        if ($lastReplyAge < $data['days'])
        {
            return false;
        }
        
        return true;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyUsername(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->last_post_username)
        {
            return false;
        }
        
        $names = preg_split('/\s*,\s*/', utf8_strtolower($data['names']), -1, PREG_SPLIT_NO_EMPTY);
        return in_array(utf8_strtolower($thread->last_post_username), $names);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyUsernameSearch(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->last_post_username)
        {
            return false;
        }
        
        if ($this->findNeedle($data['needles'], $thread->last_post_username) === false)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    
    
    /**
     * @return array
     */
    public function getExtraTemplateData()
    {
        $templateData = parent::getExtraTemplateData();
        
        /** @var \XF\Repository\Node $nodeRepo */
        $nodeRepo = $this->app->repository('XF:Node');
        $nodes = $nodeRepo->createNodeTree($nodeRepo->getFullNodeList());
        
        /** @var \XF\Repository\ThreadPrefix $prefixRepo */
        $prefixRepo = \XF::repository('XF:ThreadPrefix');
        $availablePrefixes = $prefixRepo->findPrefixesForList()->fetch()->pluckNamed('title', 'prefix_id');
        $prefixListData = $prefixRepo->getPrefixListData();
        
        $templateData = array_merge($templateData, [
            'nodeTree' => $nodes,
            
            'availablePrefixes' => $availablePrefixes,
            
            'prefixGroups' => $prefixListData['prefixGroups'],
            'prefixesGrouped' => $prefixListData['prefixesGrouped']
        ]);
        
        return $templateData;
    }
}