<?php
/* search string syntax:
   +<word> : <word> is required
   -<word> : <word> cannot exist in the searched field
   "word word" : contents between the quotes are treated as a single entity
   +/-"word word"  is supported
   ignore words are not case sensitive
*/   
class clsSearchLog extends clsItemDB
{
    function clsSearchLog($id=NULL)
    {
        $this->clsItemDB();
        $this->tablename = GetTablePrefix()."SearchLog";
        $this->id_field = "SearchLogId";
        $this->NoResourceId = 1;
        if($id)
            $this->LoadFromDatabase($id);
    }

    function LoadFromDatabase($Id)
    {
		global $Errors;
       
        if(!isset($Id))
        {
            $Errors->AddError("error.AppError",NULL,'Internal error: LoadFromDatabase id',"",get_class($this),"LoadFromDatabase");
            return false;
        }        
        $sql = sprintf("SELECT * FROM ".$this->tablename." WHERE ".$this->IdField()." = '%s'",$Id);
        $result = $this->adodbConnection->Execute($sql);
        if ($result === false)
        {
            $Errors->AddError("error.DatabaseError",NULL,$this->adodbConnection->ErrorMsg(),"",get_class($this),"LoadFromDatabase");
            return false;
        }

        $data = $result->fields;

        $this->SetFromArray($data);
        $this->Clean();
        return true;
    }    
}

class clsSearchLogList extends clsItemCollection
{
    var $Page;
    var $PerPageVar;

    function clsSearchLogList()
    {
        $this->clsItemCollection();
        $this->SourceTable = GetTablePrefix()."SearchLog";
        $this->classname = "clsSearchLog";
        $this->Page=1;
        $this->PerPageVar = "Perpage_SearchLog";
        $this->AdminSearchFields = array("Keyword");
    }

    function UpdateKeyword($keyword,$SearchType)
    {
        $sql = "UPDATE ".$this->SourceTable." SET Indices = Indices+1 WHERE Keyword='$keyword' AND SearchType=$SearchType";
        //echo $sql."<br>\n";
        $this->adodbConnection->Execute($sql);
        if($this->adodbConnection->Affected_Rows()==0)
        {
            //echo "Creating Keyword record..<br>\n";
            $k = new clsSearchLog();
            $k->Set("Keyword",$keyword);
            $k->Set("Indices",1);
            $k->Set("SearchType",$SearchType);
            $k->Create();
        }
    }

    function AddKeywords($Keywords)
    {
        if(is_array($Keywords))
        {
            for($i=0;$i<count($Keywords);$i++)
            {
                $this->UpdateKeyword($Keywords[$i]);
            }
        }
        else
            $this->UpdateKeyword($Keywords);
    }
}

class clsEmailLog extends clsItemDB
{
    function clsEmailLog($id=NULL)
    {
        $this->clsItemDB();
        $this->tablename = GetTablePrefix()."SearchLog";
        $this->id_field = "SearchLogId";
        $this->NoResourceId = 1;
        if($id)
            $this->LoadFromDatabase($id);
    }

    function LoadFromDatabase($Id)
    {
		global $Errors;
       
        if(!isset($Id))
        {
            $Errors->AddError("error.AppError",NULL,'Internal error: LoadFromDatabase id',"",get_class($this),"LoadFromDatabase");
            return false;
        }        
        $sql = sprintf("SELECT * FROM ".$this->tablename." WHERE ".$this->IdField()." = '%s'",$Id);
        $result = $this->adodbConnection->Execute($sql);
        if ($result === false)
        {
            $Errors->AddError("error.DatabaseError",NULL,$this->adodbConnection->ErrorMsg(),"",get_class($this),"LoadFromDatabase");
            return false;
        }

        $data = $result->fields;

        $this->SetFromArray($data);
        $this->Clean();
        return true;
    }    
}

class clsEmailLogList extends clsItemCollection
{
    var $Page;
    var $PerPageVar;

    function clsEmailLogList()
    {
        $this->clsItemCollection();
        $this->SourceTable = GetTablePrefix()."SearchLog";
        $this->classname = "clsEmailLog";
        $this->Page=1;
        $this->PerPageVar = "Perpage_EmailsL";
        $this->AdminSearchFields = array("event", "fromuser", "addressto", "subject");
    }

    function UpdateKeyword($keyword,$SearchType)
    {
        $sql = "UPDATE ".$this->SourceTable." SET Indices = Indices+1 WHERE Keyword='$keyword' AND SearchType=$SearchType";
        //echo $sql."<br>\n";
        $this->adodbConnection->Execute($sql);
        if($this->adodbConnection->Affected_Rows()==0)
        {
            //echo "Creating Keyword record..<br>\n";
            $k = new clsSearchLog();
            $k->Set("Keyword",$keyword);
            $k->Set("Indices",1);
            $k->Set("SearchType",$SearchType);
            $k->Create();
        }
    }

    function AddKeywords($Keywords)
    {
        if(is_array($Keywords))
        {
            for($i=0;$i<count($Keywords);$i++)
            {
                $this->UpdateKeyword($Keywords[$i]);
            }
        }
        else
            $this->UpdateKeyword($Keywords);
    }
}

class clsSearchResults extends clsItemCollection
{
    var $ResultTable;
    var $FieldList;
    var $FieldWeight;
    var $WhereClauses;
    var $SourceTable;
    var $Relationships;
    var $Ignored_Words;
    var $CatClause;   
    var $Keywords;
    var $Phrase = "";
    var $SearchType;
    var $RequiredRelevance;
    var $PctRelevance;
    var $PctPop;
    var $PctRating;

    function clsSearchResults($SearchSource,$DataClass)
    {
        global $objConfig;

        $this->clsItemCollection();
        $this->SourceTable = $SearchSource;
        $this->SetResultTable($SearchSource,$DataClass);
        $this->FieldList = array();
        $this->Relationships = array();
        $this->Ignored_Words = array();
        $this->WhereClauses = array();
        $this->FieldWeight = array();
        $this->Keywords = GetKeywords("");
        $this->SearchType = 0; //simple
        $this->RequiredRelevance=0;
        $this->PctRelevance = $objConfig->Get("SearchRel_DefaultKeyword")/100;
        $this->PctPop = $objConfig->Get("SearchRel_DefaultPop")/100;
        $this->PctRating = $objConfig->Get("SearchRel_DefaultRating")/100;
    }

    function SetResultTable($SearchSource,$DataClass)
    {
        global $objSession;

        $this->ResultTable = $objSession->GetSearchTable();
        $this->classname= $DataClass;
    }

    function LoadSearchResults($Start=0,$PerPage=NULL)
    {
      if($PerPage)
      {
          $limit = "LIMIT $Start,$PerPage";
      }
      $sql = "SELECT * FROM ".$this->ResultTable." ".$limit;     

      $this->Clear();
      $rs = $this->adodbConnection->Execute($sql);
      return $this->Query_Item($sql);
    }
    
    function SetCategoryClause($whereclause)
    {
        $this->CatClause=$whereclause;
    }

    function AddRelationship($JoinTable,$JoinExpression=NULL)
    {
    	
        $this->Relationships[$JoinTable]=$JoinExpression;        
    }

    function SetKeywords($keywords)
    {
        $this->Phrase=$keywords; 
        $this->keywords = GetKeywords($keywords);
    }
    
    function AddSimpleCustomFields()
    {
        $sql = "SELECT * FROM ".GetTablePrefix()."SearchConfig WHERE TableName='".$this->SourceTable."' AND SimpleSearch=1 AND CustomFieldId>0";
        //echo $sql;
        foreach($this->Relationships as $Table=>$clause) 
        {
            if(strlen($Table)>0 && $Table != "Category")
              $sql .= " OR TableName='".$Table."'";
        }
        $ctable = GetTablePrefix()."CustomMetaData";
        $rs = $this->adodbConnection->Execute($sql);
        $CustomJoined = FALSE;       
        while($rs && !$rs->EOF)
        {
        	$x = $rs->fields["CustomFieldId"];
        	$t = $ctable." as c".$x;
        	$join = "(c$x.ResourceId=".GetTablePrefix().$this->SourceTable.".ResourceId AND c$x.CustomFieldId=".$rs->fields["CustomFieldId"].")";        	
        	$this->AddRelationship($t,$join);
        	$f = "c".$x.".Value ";           	
            $this->FieldList[] = $f;
            $this->FieldWeight[$f] = $rs->fields["Priority"];
            $rs->MoveNext();
        }
    }    

    function AddSimpleFields()
    {
        $sql = "SELECT * FROM ".GetTablePrefix()."SearchConfig WHERE TableName='".$this->SourceTable."' AND SimpleSearch=1 AND CustomFieldId=0";
        //echo $sql;
        foreach($this->Relationships as $Table=>$clause) 
        {
            if(strlen($Table)>0 && $Table != "Category")
              $sql .= " OR TableName='".$Table."'";
        }
        $rs = $this->adodbConnection->Execute($sql);
        
        while($rs && !$rs->EOF)
        {
            $f = GetTablePrefix().$rs->fields["TableName"].".".$rs->fields["FieldName"];
            $this->FieldList[] = $f;
            $this->FieldWeight[$f] = $rs->fields["Priority"];
            $rs->MoveNext();
        }
        $this->AddSimpleCustomFields();
    }

    function AddSearchWhereClause($FieldName)
    {
          $req_where = "";
          /* build required keywords string */

          if(count($this->keywords["required"])>0)
          {          
            $required = $this->keywords["required"];            
            for($i=0;$i<count($required);$i++)
            {
              if(strlen($required[$i])>0)
              {
                  if($i>0)
                  {              
                    $or =" AND ";
                  }
                  else
                    $or = "";
                  $w .= $or." ".$FieldName." LIKE '%".$required[$i]."%'"; 
              }
            }
            if(strlen($w)>0)
            {            
                $req_where = "(". $w.")";
            }
            else
                $req_where = "";
          }
          $w = "";
          $not_where="";
          if(count($this->keywords["notallowed"])>0)
          {          
            $words = $this->keywords["notallowed"];
            for($i=0;$i<count($words);$i++)
            {
              if(strlen($words[$i])>0)
              {
                  if($i>0)
                  {              
                    $or =" AND ";
                  }
                  else
                    $or = "";
                  $w .= $or." ".$FieldName." NOT LIKE '%".$words[$i]."%'"; 
              }              
            }
            if(strlen($w)>0)
            {            
                $not_where = "(".$w.")";
            }
            else
                $not_where = "";
          }
          
          $w="";
          $normal = $this->keywords["normal"];
          if(count($normal)>0)
          {          
           for($i=0;$i<count($normal);$i++)
            { 
              if (strlen($normal[$i])>0) 
              {             
                if($i>0)
                {              
                  $or =" OR ";
                }
                else
                  $or = "";
                $w  .= "$or $FieldName LIKE '%".$normal[$i]."%'";
              }
            }     
           if(count($required)>0)
               $w .= " OR ";
           for($i=0;$i<count($required);$i++)
           {
               if(strlen($required[$i])>0)
               {
                   if($i>0)
                   {
                       $or = " OR ";
                   }
                   else
                       $or="";
                   $w  .= "$or $FieldName LIKE '%".$required[$i]."%'";
               }
           }
            if(strlen($w)>0)
            {            
               $where = "(".$w.")";
            }
            else
               $where = "";
          }

          $complete= BuildWhereClause($where,$req_where,$not_where);
          $this->WhereClauses[$FieldName]="(".$complete.")";
          $this->Ignored_Words=$this->keywords["ignored"];        
    }
            
    function PerformSearch($ItemType,$OrderBy=NULL,$InitTable=FALSE, $idlist=NULL)
    {
        static $SelectSQL, $OldItemType;
        global $objSession, $objItemTypes;
        //echo "perfirming Simple Search<br>";
        //echo "Old Item Type: $OldItemType  New: $ItemType <br>\n";
        if($ItemType != $OldItemType)
            $SelectSQL = "";
        $OldItemType = $ItemType;

        $ctype = $objItemTypes->GetItem($ItemType);
        $idField = $ctype->Get("SourceTable")."Id";
        $this->SourceTable = GetTablePrefix().$ctype->Get("SourceTable");
        $result=0;
        $PopField = $ctype->Get("PopField");
        $RateField = $ctype->Get("RateField");
        
        //print_pre($this->keywords);
        
        if(!strlen($SelectSQL))
        {      
          $typestr = str_pad($ItemType,2,"0",STR_PAD_LEFT);
          $SelectSQL = "SELECT ";
          $ifs = array();
          $weightsum = 0;         
          foreach($this->FieldWeight as $w)
              $weightsum += $w;
          $wordcount = count($this->keywords["normal"])+count($this->keywords["required"]);
          $single = ($wordcount == 1);
          foreach($this->FieldList as $f)
          {
              $weight = (int)$this->FieldWeight[$f];
              $s = array();

              if(!$single)
              { 
                $full = trim(implode(" ",$this->keywords["normal"]));
                $s[] = " (IF ($f LIKE '%$full%', ".$weightsum.", 0))";                
              }
              foreach($this->keywords["normal"] as $k)
              {                  
                  if($k != $full || $single)
                  {                  
                    $temp = " (IF ($f LIKE '%$k%', ".$weight.", 0))";
                    $s[] = $temp;
                  }
              }
              
              foreach($this->keywords["required"] as $k)
              {
                if($this->RequiredRelevance>0)
                  $weight = $this->FieldWeight[$f] + ($this->FieldWeight[$f]*($this->RequiredRelevance/100));
						
                  if($k != $full || $single)
                  {
                      $s[] = " (IF ($f LIKE '%$k%', ".$weight.", 0))";
                  }
              }
             // echo "<PRE>";print_r($s); echo "</PRE>";     
              $txt = implode("+",$s);
              //echo $txt."<br>\n";
              $ifs[] = $txt;  
              unset($s);
          }
//          echo "<PRE>";print_r($ifs); echo "</PRE>";

          /* add relevance formula for weighting hits & popularity */
          
          if($weightsum==0)
              $weightsum=1;

          if(strlen($PopField)>0 && $this->PctPop>0)
          {              
              $popcalc = " + ((($PopField + 1) / (max($PopField)+1)*".$this->PctPop."))";
          }
          else
              $popcalc = "";

          if(strlen($RateField)>0 && $this->PctRating>0)
          {          
            $ratecalc = " + ((($RateField + 1) / (max($RateField)+1)*".$this->PctRating."))";
          }
          else
              $ratecalc = "";

          if($this->PctRelevance>0)
          {
              $relcalc = "(((".implode("+",$ifs).")/$weightsum)*".$this->PctRelevance.")";
          }
          else
              $relcalc = "0";

          $SelectSQL .= $relcalc.$popcalc.$ratecalc."  as Relevance, ";
          
          $SelectSQL .= $this->SourceTable.".".$idField." as ItemId, ".$this->SourceTable.".ResourceId as ResourceId, CONCAT($typestr) as ItemType, EditorsPick as EdPick FROM ".$this->SourceTable." ";
        
          foreach($this->Relationships as $JoinTable=>$OnClause)
          {            
            $SelectSQL .= "LEFT JOIN $JoinTable ON $OnClause ";
          }
          $first=1;
          $where=0;

          foreach($this->FieldList as $field)
          {
          	if(strpos($field,"as")>0)
          	{
          		$fparts = explode("as",$field,2);
          		$f = $fparts[1];
          		$this->AddSearchWhereClause($field);
          	}
          	else {
            	$this->AddSearchWhereClause($field);
            }            
          }

          $SelectSQL .= " WHERE ";
          $SelectSQL .= implode(" or ",$this->WhereClauses);

          if(is_array($idlist))
          {
              $SelectSQL .= " AND (ResourceId IN (".implode(",",$idlist)."))";
          }
        }
        $SelectSQL .= "GROUP BY $idField ";
        
        //echo $SelectSQL."<br><br>\n";
        
        if($InitTable)
        {   
           $this->adodbConnection->Execute("DROP TABLE IF EXISTS ".$this->ResultTable);
           //$indexSQL = "(INDEX(Relevance), INDEX(ItemId), INDEX(ItemType), INDEX sorting (EdPick,Relevance)) ";
           $full_sql = "CREATE TABLE ".$this->ResultTable." ".$indexSQL.$SelectSQL;         
           //echo $full_sql."<br>\n";
           $this->adodbConnection->Execute($full_sql);
           //echo $this->adodbConnection->ErrorMsg()."<br>\n";
           $objSession->SetVariable("Search_Keywords",$this->Phrase);
        }
        else
        {
          $full_sql = "INSERT INTO ".$this->ResultTable." (Relevance,ItemId,ResourceId,ItemType,EdPick) ".$SelectSQL;
        //echo "[<b>".htmlspecialchars($full_sql)."</b>]<br>\n";
          $this->adodbConnection->Execute($full_sql);
          //echo $this->adodbConnection->ErrorMsg()."<br>\n";
        }
        //Here we need to remove found items which was found by HTML tags matching keywords
         //$this->adodbConnection->Execute("DELETE FROM ".$this->ResultTable." WHERE ItemId = 13 AND ItemType = 4");
    }
    
    function BuildIndexes()
    {
       $sql = "ALTER TABLE ".$this->ResultTable." ADD INDEX (Relevance), ";
       $sql .="ADD INDEX (ItemId), ";
       $sql .="ADD INDEX (ItemType), ";
       $sql .=" ADD INDEX sorting (EdPick,Relevance)";
       //echo $sql;
       $this->adodbConnection->Execute($sql);
    }

    function Result_IdList()
    {
        /* returns an array contain a resource ID list */
        $sql = "SELECT DISTINCT(ResourceId) FROM ".$this->ResultTable;
        $rs = $this->adodbConnection->Execute($sql);
        $result = array();
        while($rs && !$rs->EOF)
        {
            $result[] = $rs->fields["ResourceId"];
            $rs->MoveNext();
        }
        return $result;
    }
}

function count_words($string) 
{
   // below line added to make contiguous spaces count as one space
   if(strlen($string))
   {
     $string = eregi_replace(" +", " ", $string);
     return substr_count($string," ")+1;
   }
   else
       return 0;
}

function GetKeywords($phrase)
{
    global $KeywordIgnore;
    
       if(count($KeywordIgnore)==0)
       GetIgnoreList();
    $keywords["normal"]= array();
    $keywords["required"]= array();
    $keywords["notallowed"] = array();
    $keywords["ignored"] = array();  
    if(!strlen($phrase))
        return $keywords;
    $w_array = array();
    $phrase=trim($phrase);
    //if(count_words($phrase)>1)
    //  $keywords["normal"][] = $phrase;
    $t_len = strlen($phrase);
	$ce=0;
	for ($i=0; $i<$t_len; $i++)
	{	#search for next special tag
		switch ($phrase[$i])
		{
			case "\"":
					$exact_match_close = strpos($phrase,"\"", $i+1);
					if(!$exact_match_close)
						break;
					$exact_word=substr($phrase, $i+1, ($exact_match_close-$i)-1);
					$i=$exact_match_close;
					if($exact_word)
					{	
                        if(strlen($token)==0)
                            $token="|";
                        $w_array[$ce]=$token.addslashes($exact_word);						
                        $token="";
                        $ce++;
						$exact_word="";
					}
					break;
					
            case "+":
                if(strlen($exact_word)==0)
                {                
                  $token = "+";
                }
                else
                    $exact_word .= "+";
				break;
            case "-":
                if(strlen($exact_word)==0)
                {                
				  $token = "-";
                }
                else
                    $exact_word .="-";
                break;
			case " ":
			case ",":
				if($exact_word)
				{	                
                  if(strlen($token)==0)
                    $token="|";
                  if($token=="|")
                  {
                      if($KeywordIgnore[strtolower($exact_word)]==1)
                      {
                          $w_array[$ce]= "=".addslashes($exact_word);
                          $ce++;
                      }
                      else
                      {                      
                        $w_array[$ce]=$token.addslashes($exact_word);
                        $ce++;
                      }
                  }
                  else
                  {
                    $w_array[$ce]=$token.addslashes($exact_word);
                    $ce++;
                  }
                  $token="";
				  $exact_word="";				
				}
				break;

			default:
				$exact_word.=$phrase[$i];
		}
	}
	if($exact_word)
    {
      if(strlen($token)==0)
          $token="|";
      if($KeywordIgnore[strtolower($exact_word)]==1 && ($token =="|" || $token=="="))
      {
          $w_array[$ce]= "=".addslashes($exact_word);
          $ce++;
      }
      else
      {                      
        $w_array[$ce]=$token.addslashes($exact_word);
        $ce++;
      }
    }
  for ($i=0;$i<count($w_array);$i++) 
  {
      $keyword = $w_array[$i];
      switch(substr($keyword,0,1))
      {
        case "|":
           $keywords["normal"][]=substr($keyword,1);
           break;
        case "+":
           $keywords["required"][] = substr($keyword,1);
           break;
        case "-":
           $keywords["notallowed"][] = substr($keyword,1);
           break;
        case "=":
           $keywords["ignored"][] = substr($keyword,1);
           break;
      }
  }
  return($keywords);
}

function BuildWhereClause($normal,$required,$notallowed)
{
    $return="";
    
    $return = $required;
    
    if(strlen($return)>0 && strlen($notallowed)>0)
    {
        $return .= " AND ";
    }
    $return .= $notallowed;
    if(strlen($return)>0 && strlen($normal)>0)
    {
        $return .= " AND ";
    }
    $return .= $normal;
    return $return;
}

function GetIgnoreList()
{
    global $KeywordIgnore;

    $adodbConnection = &GetADODBConnection();

    $rs = $adodbConnection->Execute("SELECT * FROM ".GetTablePrefix()."IgnoreKeywords");
    while($rs && !$rs->EOF)
    {
        $KeywordIgnore[strtolower($rs->fields["keyword"])]=1;
        $rs->MoveNext();
    }
//    foreach($KeywordIgnore as $word=>$dummy)
//        echo $word.",";
//    echo "<br>\n";
}

?>