<?php
defined('WikyBlog') or die("Not an entry point...");

//	query class
//	BROWSE FUNCTION
//	DisplayDefault
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
//					QUERY CLASS
//


//--------------------------
//	CLASS QUERY
//--------------------------
//


	class query{
		var $owner;
		var $title;
		
		var $query;
		var $fields;
		var $field;
		var $rowLimit = 5;
		var $searchUrl;
		var $maxRows; // = 500;
		
		var $useTables = false;
		var $currLabel;
		var $browseString;
		var $numTables = 0;
		var $numFields = 0;
		var $spaces = array();
		
		var $joinAllTo = false; //could be set to $wbTables['all_files'] or $wbTables['all_search']
		var $selectFrom = false;
		var $allSelect = array('modified','posted','created','username','ip','keywords','flags');
		var $infoSelect = array('owner','uniqLink','dTitle');
		var $usesOwner;
		
		var $estQuery = false; //use estimation query to count the rows
		
		//for timeline
		var $day,$month,$year = false;
		
		
	
		//////////////////////////////////////////////////////////////////////////////
		//
		//	Query Functions
		//
		//
		
		///	ORDER-BY
			function orderBy(){
				
				
				if( empty($this->field) ){
					
					if( !empty($_GET['field']) && is_numeric($_GET['field']) ){
						
						$temp = array_keys($this->fields);
						if( isset($temp[(int)$_GET['field']]) ){
							$this->field = $temp[(int)$_GET['field']];
						}
						
					}elseif( empty($_GET['field']) ){
						reset($this->fields);
						$this->field = key($this->fields);
					}
					
				}
				if( empty($this->field) ){
					return;
				}
				$this->query .= ' ORDER BY '.$this->fields[$this->field];
				
				if( isset($_GET['ascending']) && $_GET['ascending'] == 'true' ){
					$this->query .= ' ASC ';
				}else{
					$this->query .= ' DESC ';
				}	
			}
		
		
		///	LIMIT
			function limit(){
				$_GET += array('offset'=>0);
				
				if( $_GET['offset'] < 0){
					$_GET['offset'] = 0;
				}else{
					$a = round($_GET['offset']/$this->rowLimit); //get an even number to fit with the rowLimit
					$_GET['offset'] = $a*$this->rowLimit;
				}
				
				if( !empty($_GET['offset']) ){
					$this->query .= ' LIMIT '.$this->rowLimit.' OFFSET '.(int)$_GET['offset'];
				}else{
					//$_GET['offset'] = 0;
					$this->query .= ' LIMIT '.$this->rowLimit.' OFFSET 0';
				}
			}
			
		///	queryAllFiles
			function queryAllFiles(){
				global $dbInfo,$langA,$wbTables;
				$unused = array();
				$comma = '';
				
				//uses owner
					if( in_array('owner',$this->infoSelect) ){
						$this->usesOwner = true;
					}else{
						$this->usesOwner = false;
					}
				
				
				
				//	join/select
					if( !$this->joinAllTo ){
						$this->joinAllTo =& $wbTables['all_files'];
						$this->selectFrom =& $wbTables['all_files'];
					}
				
				////	Select
					$this->query = 'SELECT ';
					$this->query .= '/* '.get_class($this).'->queryAllFiles */';
					if( !$this->estQuery ){
						$this->query .= ' SQL_CALC_FOUND_ROWS ';
					}
					
					$selectA = array();
					foreach($this->allSelect as $key => $value){
						if( is_numeric($key) ){
							$selectA[] = $this->joinAllTo.'.`'.$value.'` ';
						}else{
							$selectA[] = $key.' as `'.$value.'` ';
						}
					}
					$this->query .= implode(', ',$selectA);
					if( count($selectA) > 0){
						$comma = ',';
					}
					
					
					$selectA = array();
					foreach($dbInfo as $space => $info){
						if( !isset($info['dbTable']) ){
							continue;
						}
						$this->numTables++;
						
						//row selects
						if( is_array($this->useTables) && !isset($this->useTables[$space]) ){
							$unused[] = $space;
							foreach($this->infoSelect as $tempKey){
								$selectA[] = ' "" ';
							}
							
						}else{
						
							foreach($this->infoSelect as $tempKey){
								if($tempKey === 'dTitle'){
									$selectA[] = wbData::getDTitle($space);
								}else{
									$selectA[] = wbData::dbInfo($space,$tempKey);
								}
							}
						}
						$fromA[] = $info['dbTable'];
						$this->spaces[] = $space;
					}
					
					$this->numFields = count($selectA);
					if( $this->numFields > 0){
						$this->query .= $comma.implode(', ',$selectA);
						$comma = ',';
					}
					
				////	Which Space
					$this->query .= $comma.' CASE ';
					foreach($fromA as $i => $table){
						$this->query .= ' WHEN '.$table.'.`file_id` IS NOT NULL THEN "'.$i.'" ';
					}
					$this->query .= ' END AS `which_space` ';
				
				
				////	FROM
					$this->query .= ' FROM '.$this->selectFrom;
					
					if( count($fromA) === 1){
						$this->query .= ' INNER JOIN '.$fromA[0].' ON '.$from[0].'.`file_id` = '.$this->joinAllTo.'.`file_id` ';
					}else{
						foreach($fromA as $value){
							$this->query .= ' LEFT JOIN '.$value.' ON '.$value.'.`file_id` = '.$this->joinAllTo.'.`file_id` ';
						}
					}
					
				////	WHERE .. 
					$this->query .= ' WHERE 1 ';
					
					
				// Not using unused spaces
					if( count($unused) > 0 ){
						foreach($unused as $space){
							$this->query .= ' AND '.$dbInfo[$space]['dbTable'].'.`file_id` IS NULL ';
						}
					}
					
				//Avoid any file that doesn't have an entry in a content table
				// this doesn't really change the efficiency of the query..
					if( count($fromA) > 1){
						$temp = array();
						$this->query .= ' AND (';
						foreach($fromA as $value){
							$temp[] = ' ('.$value.'.`file_id`  IS NOT NULL ) ';
						}
						$this->query .= implode(' OR ',$temp);
						$this->query .= ' ) ';
					}
					
					
			}
			
			//Get The Values From a queryAllFiles type of request
			function queryAllResult(&$row){
				$newRow = array();
				
					$spaceIndex = (int)$row[count($row)-1];
					$numEach = count($this->infoSelect);
					$startIndex = count($this->allSelect)+($spaceIndex*$numEach);
					$newRow['space'] = $this->spaces[$spaceIndex];
					
				
					
					//rowLabels
					$i = 0;
					
					foreach($this->infoSelect as $tempKey){
						$newRow[$tempKey] =& $row[$startIndex+($i++)];
					}
					if( $this->usesOwner && empty($newRow['owner']) ){
						$newRow['owner'] = $GLOBALS['wbConfig']['pUser'];
					}
					
					
					$i=0;
					foreach($this->allSelect as $key => $value){
						if( is_numeric($key) ){
							$newRow[$value] =& $row[$i++];
						}else{
							$newRow[$value] =& $row[$i++];
						}
					}
				$row = $newRow;
			}
		
			
		//////////////////////////////////////////////////////////////////////////////
		//
		//	Link Functions
		//
		//
		
			//setLinks()
			//	must set $this->currLabel at least
			function setLinks(&$currentPageNum,&$rowsFound,&$tabLabel){
				global $page;
				
				$testCase = $rowsFound-(14*$this->rowLimit);
				if( $_GET['offset'] > $testCase ){
					//use actual max
					$maxIndex = $rowsFound/$this->rowLimit;
				}else{
					//max reduced by 7
					$maxIndex = ($rowsFound-(7*$this->rowLimit))/$this->rowLimit;
				}
				//set values for at least first page
				$maxIndex = max(1,ceil($maxIndex));
				
				$text='';
				$i = max(1,($currentPageNum - 2));
				$finishIndex = min(($i+4),$maxIndex);
				$finishIndex = max($finishIndex,$currentPageNum);
				
				while($i <= $finishIndex){
					if( $i == 1){
						$label = $tabLabel;
					}else{
						$label = $tabLabel.' ('.$i.')';
					}
					
					$newOffset = ($i-1) * $this->rowLimit;
					$contentUri = $page->regLink($label,browseLink2($this->searchUrl,$newOffset,$this->browseString));
					
					if($i == $currentPageNum){
						$this->currLabel = $label;
						$this->currUri = $contentUri;
					}
					
					$i++;
				}
				
				//Text links at the bottom of the search			
				$i = max(1,($currentPageNum - 7));
				$finishIndex = min(($i+13),$maxIndex);
				
				if( $i > 1){
					$text = ' '.browseLink2($this->searchUrl,0,$this->browseString,1);
					if( $i > 2 ){
						$text .= ' ... ';
					}
				}
				
				while($i <= $finishIndex){
					$newOffset = ($i-1) * $this->rowLimit;
					if($currentPageNum === $i){
						$text .= ' '.$i.' ';
					}else{
						$text .= ' '.browseLink2($this->searchUrl,$newOffset,$this->browseString,$i);
					}
					$i++;
				}
				
				if($i <= $maxIndex){
					$lastOffset = ($maxIndex-1) * $this->rowLimit;
					$text .= ' ... '.browseLink2($this->searchUrl,$lastOffset,$this->browseString,$maxIndex);
				}
				return $text.' ';
			}
		
			function browseString($overWrite=false){
				if( !is_array($_GET) ){
					return '';
				}
				$string = '';
				$sep = '';
				if( is_array($overWrite) ){
					$overWrite = array_merge($_GET, $overWrite); //later values overwrite!
				}else{
					$overWrite = $_GET;
				}
				if( isset($this->overWrite) && is_array($this->overWrite) ){
					$overWrite = array_merge($overWrite,$this->overWrite);
				}
				
				return arrayToBrowseString($overWrite);
			}
		
		
		//////////////////////////////////////////////////////////////////////////////
		//
		//	Display Functions	
		//
			function mysqlFetch(&$result){
				return mysql_fetch_row($result);
			}

			
			//0
			function displayNumbers(&$from,&$to,&$rowsFound,&$prev,&$next){
				echo '<div style="font-size:85%;text-align:right">&nbsp;';
				echo wbLang::text('RESULTS',$from,$to,$rowsFound);
				echo ' &nbsp; ';
				echo $prev.' &nbsp; '.$next;
				echo '</div>';
			}
			//1
			function displayEmpty(){
				global $langA;
				echo $langA['EMPTY_SET'];
				return false;
			}
			//2
			function displayPre(){ }
			//3
			function abbrevOutput(&$row){
				global $pageOwner,$langA;
				
				$this->queryAllResult($row);
				
				
				
				echo '<div><span class="title">';
				
				echo wbLinks::local($row['uniqLink'],toDisplay($row['dTitle']));
				
				if( isset($_GET['owner']) && $_GET['owner'] === 'false' ){
					echo ' &nbsp; <span class="sm"> (';
					echo wbLinks::user($row['owner']);
					echo ') </span>';
				}
				
				
				echo '</span>';
								
				echo '<span class="sm">';
				
				
					echo '<br/>';
					echo showKeywords($row['keywords'],$row['owner'],'<br/>');
					echo $langA['last_modified'].': '.dbFromDate($row['modified'],1);
					echo ' ... [ ';
					echo wbLinks::local($row['uniqLink'].'?cmd=edit',$langA['edit']);
					echo ' ]';
				
				echo '</span>';
				echo '<br/>&nbsp; </div>';
				return;
			}
			//4
			function displayPost(&$prev,&$pages,&$next,$listItems=null,$more=null){
				global $langA;
				//echo '<br/> <div style="border:1px solid #d4d0c8;padding:7px;" >';
				echo '<div class="WBsearchFooter" >';
				echo $prev.$pages.$next;
				
				if( !is_array($this->fields) ){
					if( !empty($listItems) ){
						echo '<ul>';
						echo $listItems;
						echo '</ul>';
					}else{
						echo '<br/>';
					}
					echo $more;
					echo '</div>';
					return;
				}
				
				echo '<ul>';
				echo '<li>';
				echo $langA['order_by'];
				echo ' &nbsp; ';
	
				$i = 0;
				foreach($this->fields as $key => $field){
					if( empty($field) ){
						continue;
					}
					
					$overWrite['field'] = $i;
					if( $key == $this->field ){
						echo '<b>'.$key.'</b> &nbsp; ';
					}else{
						echo wbLinks::local($this->searchUrl.'?'.$this->browseString($overWrite),$key);
						echo ' &nbsp; ';
					}
					$i++;
				}
				
				echo ' ::  &nbsp; ';
				
				unset($overWrite);
				if( isset($_GET['ascending']) && $_GET['ascending'] == 'true' ){
					$overWrite['ascending'] = 'false';
					echo wbLinks::local($this->searchUrl.'?'.$this->browseString($overWrite),$langA['descending']);
					echo ' '. $langA['or'].' <b>'.$langA['ascending'].'</b>';
				}else{
					$overWrite['ascending'] = 'true';
					echo '<b>'.$langA['descending'].'</b> '.$langA['or'].' ';
					echo wbLinks::local($this->searchUrl.'?'.$this->browseString($overWrite),$langA['ascending']);
				}
				echo '</li>';
				if( !empty($listItems) ){
					echo $listItems;
				}
				echo '</ul>';
				
				echo $more;
				
				echo '</div>';
			}
			
			function openBuffer(){
				ob_start();
			}
			
			function closeBuffer(){
				global $page;
				
				if( empty($page->contentB[$this->currUri]) ){
					$page->contentB[$this->currUri] = '';
				}
				$page->contentB[$this->currUri] .= wb::get_clean();
			}
			
			//this function just does the <td> that holds the timeline
			function timelineTD(&$modified){
				
				//Format For Display
				$unixTime = dbFromDate($modified,'unix');

				$month = date('ym',$unixTime);
				$day = date('ymj',$unixTime);
		
				////////	1)	format the timeline dates
					$dateTime = dbFromDate($modified,array('H',':','i'));
					if( $this->day !== $day){
						$dateTime = dbFromDate($modified,array('D',' ','j')).', '.$dateTime;
						if( $this->month !== $month ){
							$dateTime = '<div style="text-align:left"><b>'.dbFromDate($modified,array('Y',' ','M')).'</b></div> '.$dateTime;
						}
					}
					$this->month = $month;
					$this->day = $day;
				echo '<td class="historyTimeline"><div class="historyTime">';
				echo $dateTime;
				echo '</div></td>';
			}
			

			
		//////////////////////////////////////////////////////////////////////////////
		//
		//	Browse Function
		//
		//
		function browse($tabLabel){
			global $page,$dbObject,$langA;
			$this->limit();
			ksort($_GET);
			
			///////////////////////////////////////////////////////////////////////////////////
			//
			//		Output Variables
			//
			
				$previousLink = '';
				$nextLink = '';
				
				if( empty($this->searchUrl) ){
					$this->searchUrl = $_SERVER['REDIRECT_URL'];
					trigger_error('searchUrl not set');
				}elseif( strpos($this->searchUrl,'?') ){
					trigger_error('searchUrl is set with a query string alredy');
				}
				
				$this->browseString = $this->browseString();
				
				//PageNum
				if( empty($_GET['offset']) || $_GET['offset'] == 0){
					$currentPageNum = 1;
				}else{
					$currentPageNum = (int)(($_GET['offset'] / $this->rowLimit) +1);
				}
				
		
				
			///////////////////////////////////////////////////////////////////////////////////
			//
			//		Run the query
			//
				ob_start(); //in case there's an error
				$result = wbDB::runQuery($this->query);
				if( !$result ){
					$page->contentA['Query Error'] = wb::get_clean();
					return;
				}
				wb::get_clean();
				$actualRowsFound = mysql_num_rows($result);
			
			////////	NUMBER OF RESULTS
				$rowsFound = false;
				if( !$this->estQuery ){
					$rowsFound = $this->foundRows();
					
				}else{
					
					$rowsFound = $this->estimateRows();
				}
				
				//MaxRows
				if( isset($this->maxRows) && is_numeric($this->maxRows) ){
					$rowsFound = min($rowsFound,$this->maxRows);
				}else{
					$this->maxRows = $rowsFound;
				}
				
				
			///////////////////////////////////////////////////////////////////////////////////
			//
			//		Links
			//
			
				
				//PREVIOUS LINK
				$previousLink = $this->prevLink();
				
				//NEXT LINK
				$nextLink = $this->nextLink($rowsFound);
		
				$to = min($_GET['offset']+$this->rowLimit, $rowsFound);
				$from = min($_GET['offset']+1,$rowsFound);
				
				$this->openBuffer();
				$text = $this->setLinks($currentPageNum,$rowsFound,$tabLabel);
				$this->displayNumbers($from,$to,$rowsFound,$previousLink,$nextLink);
				
				
			///////////////////////////////////////////////////////////////////////////////////
			//
			//		Content
			//
		
				//IF NO DATA
				if($actualRowsFound == 0){
					if( !$this->displayEmpty() ){
						$this->closeBuffer();
						return;
					}
				}
		
				//DISPLAY
				$i=$from;
				$this->displayPre();

				$this->whileResult($result,$i,$actualRowsFound);
		
				$this->displayPost($previousLink,$text,$nextLink);
				$this->closeBuffer();
				
		}// END FUNCTION
		
		function whileResult(&$result,&$i,&$actualRowsFound){
			global $page;
			
			while( ($row = $this->mysqlFetch($result)) && ($i <= $this->maxRows)){
				$this->abbrevOutput($row,$i,$actualRowsFound);
				
				//set last-modified for each row
				if( is_array($row) && isset($row['modified'])){
					$page->setLastModified($row['modified']);
				}elseif( isset($row->modified) ){
					$page->setLastModified($row->modified);
				}
				$i++;
			}
		}
		
		function nextLink($rowsFound){
			global $langA;
			if( ($_GET['offset']+$this->rowLimit) < $rowsFound){
				return browseLink2($this->searchUrl,($_GET['offset'] + $this->rowLimit),$this->browseString,$langA['next']);
			}
			return $langA['next'];
		}
		
		function prevLink(){
			global $langA;
			if( isset($_GET['offset']) && $_GET['offset'] > 0){
				$previousOffset = $_GET['offset'] - $this->rowLimit;
				return browseLink2($this->searchUrl,$previousOffset,$this->browseString,$langA['previous']);
			}
			$_GET['offset'] = 0;
			return $langA['previous'];
		}
		
		function foundRows(){
			$query = 'SELECT FOUND_ROWS()';
			$result = wbDB::runQuery($query);
			$num = mysql_num_rows($result);
			if($num == 1){
				$row = mysql_fetch_assoc($result);
				return $row['FOUND_ROWS()'];
			}
			return false;
		}
		function estimateRows(){
			
			$result = wbDB::runQuery($this->estQuery);
			$row = mysql_fetch_assoc($result);
			return $row['count'];
		}
	}

	
	
//
//					QUERY CLASS
//
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//					addtnl functions
//



function browseLink2($href,$offset,$queryString,$text=false){
	global $wbLinkFormat,$page;
	
	$piece = '?';
	if(!empty($queryString)){
		$href .= '?'.$queryString;
		$piece = '&';
	}
	
	if((int)$offset !== 0){
		$href .= $piece.'offset='.$offset;
	}
	if( $text === false){
		return $href;
	}else{
		$href = str_replace('&','&amp;',$href);
		return '<a '.sprintf($wbLinkFormat,$href,$page->revType,'').'>'.$text.'</a>';
	}
}	


//
//					BrowseSearch
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//					Widely Used Functions
//
function arrayToBrowseString(&$array,$prefix=false){

	$string = '';
	$sep = '';
	foreach($array as $key => $value){
		if( $value === false){ //should be NULL instead of false
			continue;
		}
		switch($key){
			case 'label':
			case 'wb':
			case 'offset':
				//these have special meaning to this software
			continue 2;
		}
		if($prefix !== false){
			$key = $prefix.'['.$key.']';
		}
		if(is_array($value)){
			$string .= arrayToBrowseString($value,$key);
		}else{
			$value = str_replace(array('&lt;','&gt;','<','>'),'',$value);
			$string .= $sep.rawurlencode($key).'='.rawurlencode($value);
		}
		$sep = '&';
	}	
	return $string;
}


function removeWiki($text){
	$search = array("''''","'''","''",'====','===','==','[Image:','[image:','[',']','*','#');
	$text = str_replace($search,'',$text);
	return $text;
}
