<?php

class Andy_SimilarThreads_ControllerPublic_Thread extends XFCP_Andy_SimilarThreads_ControllerPublic_Thread
{	
	public function actionIndex()
	{
		//########################################
		// show similar threads in thread view
		//########################################
				
		// get parent	
		$parent = parent::actionIndex();
		
		// return parent action if this is a redirect or other non View response	 
		if (!$parent instanceof XenForo_ControllerResponse_View)
		{
			return $parent;
		}
		
		// check for user group permission
		if (!XenForo_Visitor::getInstance()->hasPermission('similarThreadsGroupID', 'similarThreadsID'))
		{
			return $parent;
		}		
		
		// get options from Admin CP -> Options -> Similar Threads -> Show Below First Post    
		$showBelowFirstPost = XenForo_Application::get('options')->similarThreadsShowBelowFirstPost;	
			
		// get options from Admin CP -> Options -> Similar Threads -> Show Below Quick Reply    
		$showBelowQuickReply = XenForo_Application::get('options')->similarThreadsShowBelowQuickReply;			
	
		// return if options not set
		if (!$showBelowFirstPost AND !$showBelowQuickReply)
		{ 	
			return $parent;
		}
		
		//########################################
		// return if forum is excluded
		//########################################		
		
		// get currentNodeId
		$currentNodeId = $parent->params['thread']['node_id'];
		
		// get userId
		$visitor = XenForo_Visitor::getInstance();
        $userId = $visitor['user_id'];				
		
		// get options from Admin CP -> Options -> Similar Threads -> Exclude Forums  
		$excludeForums = XenForo_Application::get('options')->similarThreadsExcludeForums;
   
		// if excludeForums
		if ($excludeForums != '')
		{
			// remove trailing comma if there is one
			$excludeForums = rtrim($excludeForums, ',');
							
			// put into array
			$excludeForumsArray = explode(',', $excludeForums); 	 
			  
			// check for excluded forums
			if (in_array($currentNodeId, $excludeForumsArray))
			{
				// return parent
				return $parent;
			}
		}
		
		//########################################
		// "View threads by others" permission
		//########################################		
		
		$nodeId = $parent->params['thread']['node_id'];				
		$nodePermissions = XenForo_Visitor::getInstance()->getNodePermissions($nodeId);
		$viewOthers = XenForo_Permission::hasContentPermission($nodePermissions, 'viewOthers');
		
		//########################################
		// search type
		//########################################
		
		// get options from Admin CP -> Options -> Similar Threads -> Enhanced Search  
		$enhancedSearch = XenForo_Application::get('options')->similarThreadsEnhancedSearch;
		
		//########################################
		// enhanced search
		//########################################							
			
		// if enhanced search
		if ($enhancedSearch)
		{
			// declare variables
			$searchWords = array();
			$similarThreads = '';
			$threadIds = array();		
			
			// get currentThreadId
			$currentThreadId = $parent->params['thread']['thread_id'];
			
			// get thread title
			$threadTitle = $parent->params['thread']['title'];
			
			// replace double quote
			$threadTitle = str_replace('"', "", $threadTitle);
			
			// replace backslash
			$threadTitle = str_replace('\\', "", $threadTitle);
			
			// replace first 32 ascii characters and DEL	
			$threadTitle = preg_replace('/[\x00-\x1F\x7F]/', '', $threadTitle);									
					
			// get options from Admin CP -> Options -> Similar Threads -> Same Forum  
			$sameForum = XenForo_Application::get('options')->similarThreadsSameForum;
			
			// get options from Admin CP -> Options -> Similar Threads -> Maximum Results  
			$maximumResults = XenForo_Application::get('options')->similarThreadsMaximumResults; 							

			// get ElasticSearch options	
			$esServerOption = XenForo_Application::get('options')->elasticSearchServer;
			
			// get ElasticSearch host	
			$esHost = $esServerOption['host'];			
			
			// get ElasticSearch port number
			$esPort = $esServerOption['port'];
			
			// get ElasticSearch index name
			$indexName = XenES_Api::getInstance()->getIndex();
			
			//########################################
			// viewable nodes
			//########################################
			
			// define variable;
			$whereclause1 = '';			
						
			// get viewableNodes
			$viewableNodes = $this->getModelFromCache('XenForo_Model_Node')->getViewableNodeList();
			
			if ($viewableNodes)
			{
				// get nodeIds
				foreach ($viewableNodes as $node)
				{
					$nodeIds[] = $node['node_id'];
				}
			
				// create whereclause
				$whereclause1 = '"' . implode('", "', $nodeIds);
				$whereclause1 = $whereclause1 . '"';
			}
	
			//########################################
			// exclude forums
			//########################################
			
			// define variables;
			unset($nodeIds);
			$whereclause2 = '';
			
			if ($excludeForums != '')
			{
				// remove trailing comma
				$excludeForumsArray = rtrim($excludeForums, ',');				
				
				$nodeIds = explode(',', $excludeForumsArray);		
				
				// create whereclause
				$whereclause2 = '"' . implode('", "', $nodeIds);
				$whereclause2 = $whereclause2 . '"';
			}

			// results for all forums
			if ($sameForum == 0)
			{
				// define data_string
				$data_string = '{
					"from" : 0, "size" : "' . $maximumResults . '",
					"query": {
						"filtered": {
							"query": {
								"match" : {
									"thread.title" : {
										"query" : "' . $threadTitle . '",
										"operator": "or"
									}
								}
							},
							"filter": {
								"bool" : {
									"must" : [
										{
											"terms" : {"thread.node" : [' . $whereclause1 . ']}
										}
									],
									"must_not" : [
										{
											"term" : {"thread.discussion_id" : "' . $currentThreadId . '"}
										}, 
										{ 
											"terms" : {"thread.node" : [' . $whereclause2 . ']}
										}										
									],
									"should" : []
								}
							}
						}
					}
				}';
			}			

			// results for current forums
			if ($sameForum == 1 AND $viewOthers == 1)
			{
				// define data_string
				$data_string = '{
					"from" : 0, "size" : "' . $maximumResults . '",
					"query": {
						"filtered": {
							"query": {
								"match" : {
									"thread.title" : {
										"query" : "' . $threadTitle . '",
										"operator": "or"
									}
								}
							},
							"filter": {
								"bool" : {
									"must" : {
										"term": {
											"thread.node" : "' . $currentNodeId . '"
										}
									},
									"must_not" : {
										"term": {
											"thread.discussion_id" : "' . $currentThreadId . '"
										}
									}
								}
							}
						}
					}
				}';
			}
			
			// results for current forums
			if ($sameForum == 1 AND $viewOthers == '')
			{
				// define data_string
				$data_string = '{
					"from" : 0, "size" : "' . $maximumResults . '",
					"query": {
						"filtered": {
							"query": {
								"match" : {
									"thread.title" : {
										"query" : "' . $threadTitle . '",
										"operator": "or"
									}
								}
							},
							"filter": {
								"bool" : {
									"must" : {
										"term": {
											"thread.node" : "' . $currentNodeId . '",
											"thread.user" : "' . $userId . '"
										}																			
									},
									"must_not" : {
										"term": {
											"thread.discussion_id" : "' . $currentThreadId . '"
										}
									}
								}
							}
						}
					}
				}';
			}				
			
			$ch = curl_init($esHost . ':' . $esPort . '/' . $indexName . '/_search?pretty=true');
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
			
			curl_setopt($ch, CURLOPT_HTTPHEADER, array(                                                                          
			'Content-Type: application/json',                                                                                
			'Content-Length: ' . strlen($data_string))                                                                       
			); 
			 
			curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string );
			curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
			
			$results = curl_exec($ch);	
			
			// check for results
			$pos1 = stripos($results, '"total" :');			
		
			// return if no "total"
			if (!is_numeric($pos1))
			{ 	
				return $parent;
			}			
		
			// check for results
			$pos1 = stripos($results, '"total" : 0');			
		
			// return if total is 0
			if (is_numeric($pos1))
			{ 	
				return $parent;
			}					
			
			// parse json results
			$data = json_decode($results);
			
			// get threadIds
			foreach ($data->hits->hits as $var) 
			{
				$threadIds[] = $var->_id;
			}
			
			// run query if we have a threadIds
			if ($threadIds)
			{
				// run query in model    
				$similarThreads = $this->getModelFromCache('Andy_SimilarThreads_Model')->getThreadsEnhancedSearch($threadIds);
			}
		}
		
		//########################################
		// standard search
		//########################################				
	
		// if not enhanced search
		if (!$enhancedSearch)
		{		
			// declare variables
			$searchWords = array();
			$similarThreads = array();
			$searchWord1 = '';
			$searchWord2 = '';
			$viewParams = array();
			
			// get currentThreadId
			$currentThreadId = $parent->params['thread']['thread_id'];			
						
			// get thread title
			$threadTitle = $parent->params['thread']['title']; 			
			
			// get options from Admin CP -> Options -> Similar Threads -> Remove Punctuations
			$removePunctuations = XenForo_Application::get('options')->removePunctuations;
			
			// put into array
			$removePunctuationsArray = explode(' ', $removePunctuations);			
			
			// remove punctuations			
			$threadTitle = str_replace($removePunctuationsArray, '', $threadTitle);

			// get options from Admin CP -> Options -> Similar Threads -> Multibyte
			$multibyte = XenForo_Application::get('options')->similarThreadsMultibyte;
			
			if ($multibyte == 0)
			{
				// put into array
				$threadTitleArray = explode(' ', $threadTitle);
			}
			
			if ($multibyte == 1)
			{			
				// put into array
				$threadTitleArray = mb_split(' ', $threadTitle);
			}
			
			// get options from Admin CP -> Options -> Similar Threads -> Common Words    
			$commonWords = XenForo_Application::get('options')->similarThreadsCommonWords; 
			
			// create commonWordsArray
			$commonWordsArray = explode(' ', $commonWords);
			
			// get options from Admin CP -> Options -> Similar Threads -> Miniumum Common Word Length    
			$minimumCommonWordLength = XenForo_Application::get('options')->similarThreadsMinimumCommonWordLength;								
			
			// remove any common words from array
			foreach ($threadTitleArray as $var)
			{
				if ($multibyte == 0)
				{
					if (!in_array(strtolower($var), $commonWordsArray))
					{					
						if (strlen($var) >= $minimumCommonWordLength)
						{
							$searchWords[] = $var;
						}
					}
				}

				if ($multibyte == 1)
				{
					if (!in_array(mb_strtolower($var), $commonWordsArray))
					{					
						if (mb_strlen($var) >= $minimumCommonWordLength)
						{
							$searchWords[] = $var;
						}
					}
				}
			}
			
			$count = count($searchWords);
			
			// only continue if we have a search word
			if ($count > 0)
			{				
				// get first search word
				$searchWord1 = $searchWords[0];
				
				if ($count > 1)
				{	
					// get second search word
					$searchWord2 = $searchWords[1];	
				}			
			}					
			
			// run query if we have a search word
			if ($searchWord1 != '')
			{
				// run query in model    
				$similarThreads = $this->getModelFromCache('Andy_SimilarThreads_Model')->getThreads($searchWord1,$searchWord2,$currentNodeId,$currentThreadId,$viewOthers);    
			}
		}
			
		//########################################
		// prepare viewParams
		//########################################
		
		// get discussionPreviewLength	
		$discussionPreviewLength = XenForo_Application::get('options')->discussionPreviewLength;		
		
		// declare variables
		$similarThreadsNew = array();
		$i = 0;
 		
		// add to multidimensional array
		foreach ($similarThreads as $k => $v)
		{ 
			// prepare array
			$forumArray = array('forum' => array(
				'node_id' => $v['node_id'],
				'title' => $v['nodeTitle']
			));	
			
			// prepare array
			$lastPostInfoArray = array('lastPostInfo' => array(
				'user_id' => $v['last_post_user_id'],
				'username' => $v['last_post_username']
			));	
			
			// prepare hasPreview
			if ($discussionPreviewLength)
			{
				// prepare array
				$hasPreviewArray = array('hasPreview' => true);
			}
			else
			{
				// prepare array
				$hasPreviewArray = array('hasPreview' => false);
			}
			
			// censor title
			$similarThreads[$i]['title'] = XenForo_Helper_String::censorString($v['title']);
			
			// merge arrays
			$similarThreadsNew[] = array_merge($similarThreads[$i], $forumArray, $lastPostInfoArray, $hasPreviewArray);				
			
			$i = $i + 1;	
		}
		
		// rename variable
		$similarThreads = $similarThreadsNew;	
	
		// prepare viewParams
		if ($parent instanceOf XenForo_ControllerResponse_View)
		{
			$viewParams = array(
				'similarThreads' => $similarThreads
			);
			
			// add viewParams to parent params
			$parent->params += $viewParams;
		}

		// return parent
		return $parent;	
	}
}