Index: trunk/kernel/include/category.php
===================================================================
--- trunk/kernel/include/category.php	(revision 1021)
+++ trunk/kernel/include/category.php	(revision 1022)
@@ -1,2366 +1,2369 @@
 <?php
 
 define('TYPE_CATEGORY', 0);
 
 $DownloadId=0;
 
 RegisterPrefix("clsCategory","cat","kernel/include/category.php");
 
 class clsCategory extends clsItem
 {
     var $Permissions;
     function clsCategory($CategoryId=NULL)
     {
         global $objSession;
         $this->clsItem(TRUE);
 
         $this->tablename = GetTablePrefix()."Category";
         $this->type=1;
         $this->BasePermission ="CATEGORY";
         $this->id_field = "CategoryId";
         $this->TagPrefix = "cat";
 
         $this->debuglevel=0;
         /* keyword highlighting */
         $this->OpenTagVar = "Category_Highlight_OpenTag";
         $this->CloseTagVar = "Category_Highlight_CloseTag";
 
         if($CategoryId!=NULL)
         {        
             $this->LoadFromDatabase($CategoryId);
             $this->Permissions = new clsPermList($CategoryId,$objSession->Get("GroupId"));
             
         }
         else
         {        
            $this->Permissions = new clsPermList();
 
         }
      }
 
     function ClearCacheData()
     {
        /*$env = "':m".$this->Get("CategoryId")."%'";
        DeleteTagCache("m_list_cats","",$env); */
        DeleteTagCache("m_itemcount","Category%");           
        DeleteModuleTagCache('kernel');
     }
     
   function DetectChanges($name, $value)
   {  	
   	global $objSession;
   	//print_pre($_POST);
 
 	if ($this->Data[$name] != $value) {		
 		//echo "$name Modified tt ".$this->Data[$name]." tt $value<br>";
 		if (!stristr($name, 'Modif') && !stristr($name, 'Created')) {
 			if ($objSession->GetVariable("HasChanges") != 1) {
 				$objSession->SetVariable("HasChanges", 2);		
 			}
 		}
 	}
   }    
 
       
     function Delete()
     {
     	global $CatDeleteList;
 		
     	if(!is_array($CatDeleteList))
     	  $CatDeleteList = array();    	 
     	if($this->UsingTempTable()==FALSE)
     	{
           $this->Permissions->Delete_CatPerms($this->Get("CategoryId"));
-          $sql = "DELETE FROM ".GetTablePrefix()."CountCache WHERE CategoryId=".$this->Get("CategoryId");
-          $this->adodbConnection->Execute($sql);
+          
+          // TODO: find way to delete specific category cache only
+          /*$sql = "DELETE FROM ".GetTablePrefix()."CountCache WHERE CategoryId=".$this->Get("CategoryId");
+          $this->adodbConnection->Execute($sql);*/
+          
 		  $CatDeleteList[] = $this->Get("CategoryId");          
       	  if($this->Get("CreatedById")>0)
          	$this->SendUserEventMail("CATEGORY.DELETE",$this->Get("CreatedById"));
       	  $this->SendAdminEventMail("CATEGORY.DELETE");          
 		  
     	  parent::Delete();
           $this->ClearCacheData();          
     	}
     	else 
     	{
     		parent::Delete();    		
     	}
     }
     
 
     function Update($UpdatedBy=NULL)
     {
         parent::Update($UpdatedBy);
         if($this->tablename==GetTablePrefix()."Category")
             $this->ClearCacheData();
     }
 
     function Create()
     {
     	if((int)$this->Get("CreatedOn")==0)
     	  $this->Set("CreatedOn",date("U"));
         parent::Create();
         if($this->tablename==GetTablePrefix()."Category")
             $this->ClearCacheData();        
     }
 
     function SetParentId($value) 
     {
         //Before we set a parent verify that propsed parent is not our child.
         //Otherwise it will cause recursion.
          
       $id = $this->Get("CategoryId");
       $path = $this->Get("ParentPath");
       $sql = sprintf("SELECT CategoryId From ".GetTablePrefix()."Category WHERE ParentPath LIKE '$path%' AND CategoryId = %d ORDER BY ParentPath",$value);     
       $rs = $this->adodbConnection->SelectLimit($sql,1,0);
       if(!$rs->EOF)
       {
          return;
         }
         $this->Set("ParentId",$value);
     } 
 
 	function Approve()
 	{
       global $objSession;
 
       if($this->Get("CreatedById")>0)
         $this->SendUserEventMail("CATEGORY.APPROVE",$this->Get("CreatedById"));
       $this->SendAdminEventMail("CATEGORY.APPROVE");
 	  $this->Set("Status", 1);
 	  $this->Update();
     }
 
     function Deny()
     {
         global $objSession;
 
         if($this->Get("CreatedById")>0)
         	$this->SendUserEventMail("CATEGORY.DENY",$this->Get("CreatedById"));
         $this->SendAdminEventMail("CATEGORY.DENY");
 
         $this->Set("Status", 0);
         $this->Update();
     }
 
 
     function IsEditorsPick() 
     {
         return $this->Is("EditorsPick");
     }
     
     function SetEditorsPick($value) 
     {
         $this->Set("EditorsPick", $value);
     }
        
    function GetSubCats($limit=NULL, $target_template=NULL, $separator=NULL, $anchor=NULL, $ending=NULL, $class=NULL)
    {
       global $m_var_list, $m_var_list_update, $var_list, $var_list_update;
       
       $sql = "SELECT CategoryId, Name from ".GetTablePrefix()."Category where ParentId=".$this->Get("CategoryId")." AND Status=1 ORDER BY Priority";
       if(isset($limit))
       {        
       	$rs = $this->adodbConnection->SelectLimit($sql, $limit, 0);
         }
         else
         {
             $rs = $this->adodbConnection->Execute($sql);
         }
       $count=1;
       
       $class_name = is_null($class)? "catsub" : $class;
       
       
       while($rs && !$rs->EOF)
       {
       	
          if(!is_null($target_template))
          {            
            $var_list_update["t"] = $target_template;
          }
          $m_var_list_update["cat"] = $rs->fields["CategoryId"];
          $m_var_list_update["p"] = "1";
          $cat_name = $rs->fields['Name'];
 		if (!is_null($anchor))
 			$ret .= "<a class=\"$class_name\" href=\"".GetIndexURL(2)."?env=" . BuildEnv() . "\">$cat_name</a>";            
 		else
 			$ret .= "<span=\"$class_name\">$cat_name</span>";       
         
             $rs->MoveNext();
             if(!$rs->EOF)
             {
                 $ret.= is_null($separator)? ", " : $separator;
             }
       	}
         if(strlen($ret))
           $ret .= is_null($ending)? " ..." : $ending;
           
       	unset($var_list_update["t"], $m_var_list_update["cat"], $m_var_list_update["p"]);
       	
         return $ret;
    }
 
     function Validate()
     {
       global $objSession;
       
         $dataValid = true;             
       if(!isset($this->m_Type))
         {
             $Errors->AddError("error.fieldIsRequired",'Type',"","","clsCategory","Validate");
             $dataValid = false;
         }
         
         if(!isset($this->m_Name))
         {
             $Errors->AddError("error.fieldIsRequired",'Name',"","","clsCategory","Validate");
             $dataValid = false;
         }
         
         if(!isset($this->m_Description))
         {
             $Errors->AddError("error.fieldIsRequired",'Description',"","","clsCategory","Validate");
             $dataValid = false;
         }
         
         if(!isset($this->m_Visible))
         {
             $Errors->AddError("error.fieldIsRequired",'Visible',"","","clsCategory","Validate");
             $dataValid = false;
         }
         
         if(!isset($this->m_CreatedById))
         {
             $Errors->AddError("error.fieldIsRequired",'CreatedBy',"","","clsCategory","Validate");
             $dataValid = false;
         }
         return $dataValid;
     }
     
     function UpdateCachedPath()
    {
    	  if($this->UsingTempTable()==TRUE)
    	    return;
       $Id = $this->Get("CategoryId");
       $Id2 = $Id;
         $NavPath = "";
         $path = array();        
       do
       {  
          $rs = $this->adodbConnection->Execute("SELECT ParentId,Name from ".$this->tablename." where CategoryId='$Id2'");
             $path[] = $Id2;            
             $nav[] = $rs->fields["Name"];
          if ($rs && !$rs->EOF)
          {                    
              //echo $path;
             $Id2 = $rs->fields["ParentId"];
                 
          }
          else
             $Id2="0"; //to prevent infinite loop
       } while ($Id2 != "0");
         $parentpath = "|".implode("|",array_reverse($path))."|";
         $NavBar = implode(">",array_reverse($nav));    
         //echo "<BR>\n";
       //$rs = $this->adodbConnection->Execute("update Category set ParentPath='$path' where CategoryId='$Id'");
         if($this->Get("ParentPath")!=$parentpath || $this->Get("CachedNavbar")!=$NavBar)
         {        
           $this->Set("ParentPath",$parentpath);
           $this->Set("CachedNavbar",$NavBar);
           $this->Update();
         }
    }
 
    function GetCachedNavBar()
    {
        $res = $this->Get("CachedNavbar");
        if(!strlen($res))
        {
            $this->UpdateCachedPath();
            $res = $this->Get("CachedNavbar");
        }
        return $res;
    }
    function Increment_Count()
    {
       $this->Increment("CachedDescendantCatsQty");
    }
 
    function Decrement_Count()
    {
       $this->Decrement("CachedDescendantCatsQty");
       $this->Update();
    }
 
     function LoadFromDatabase($Id)
     {
       global $objSession, $Errors, $objConfig;
         if($Id==0)
             return FALSE;
         
         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 CategoryId = '%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;
         if(is_array($data))
         {
            $this->SetFromArray($data);
            $this->Clean();
         }
         else
            return false;
       return true;
     }
 
     function SetNewItem()
     {
         global $objConfig;
 
         $value = $this->Get("CreatedOn");
 
         $cutoff = adodb_date("U") - ($objConfig->Get("Category_DaysNew") * 86400);
         $this->IsNew = FALSE;
         if($value>$cutoff)
             $this->IsNew = TRUE;
         return $this->IsNew;      
     }
 
     
     function LoadFromResourceId($Id)
     {
         global $objSession, $Errors;
         if(!isset($Id))
         {
             $Errors->AddError("error.AppError",NULL,'Internal error: LoadFromDatabase id',"",get_class($this),"LoadFromResourceId");
             return false;
         }        
         $sql = sprintf("SELECT * FROM ".$this->tablename." WHERE ResourceId = '%s'",$Id); 
         $result = $this->adodbConnection->Execute($sql);
         if ($result === false)
         {
             $Errors->AddError("error.DatabaseError",NULL,$adodbConnection->ErrorMsg(),"",get_class($this),"LoadFromResourceId");
             return false;
         }        
         $data = $result->fields;
         if(is_array($data))
             $this->SetFromArray($data);
         else
             return false;  
         return true;
     }
 
     function GetParentField($fieldname,$skipvalue,$default)
     {
         /* this function moves up the category tree until a value for $field other than
            $skipvalue is returned.  if no matches are made, then $default is returned */
 
         $path = $this->Get("ParentPath");
         $path = substr($path,1,-1); //strip off the first & last tokens
         $aPath = explode("|",$path);
         $aPath = array_slice($aPath,0,-1);
         $ParentPath = implode("|",$aPath);
         $sql = "SELECT $fieldname FROM category WHERE $fieldname != '$skipvalue' AND ParentPath LIKE '$ParentPath' ORDER BY ParentPath DESC";
         $rs = $this->adodbConnection->execute($sql);
         if($rs && !$rs->EOF)
         {
             $ret = $rs->fields[$fieldname];
         }
         else
             $ret = $default;
         $update = "UPDATE ".$this->SourceTable." SET $fieldname='$ret' WHERE CategoryId=".$this->Get("CategoryId");
         $this->adodbConnection->execute($update);
         return $ret;
     }
 
     
 
     function GetCustomField($fieldName)
     {
       global $objSession, $Errors;
 
         if(!isset($this->m_CategoryId))
         {
            $Errors->AddError("error.appError","Get field is required in order to set custom field values","","",get_class($this),"GetCustomField");
            return false;
         }
 
         return GetCustomFieldValue($this->m_CategoryId,"category",$fieldName);
     }
 
     function SetCustomField($fieldName, $value)
     {
       global $objSession, $Errors;
 
         if(!isset($this->m_CategoryId))
         {
            $Errors->AddError("error.appError","Set field is required in order to set custom field values","","",get_class($this),"SetCustomField");
            return false;
         }
         return SetCustomFieldValue($this->m_CategoryId,"category",$fieldName,$value);
     }
     
     function LoadPermissions($first=1)
     {        
         /* load all permissions for group on this category */
         $this->Permissions->CatId=$this->Get("CategoryId");
         if($this->Permissions->NumItems()==0)
         {      
           $cats = explode("|",substr($this->Get("ParentPath"),1,-1));
           if(is_array($cats))
           {             
             $cats = array_reverse($cats);    
             $cats[] = 0;
             foreach($cats as $catid)
             { 
               $this->Permissions->LoadCategory($catid);
             }
           }
         }
         if($this->Permissions->NumItems()==0)
         {        
           if($first==1)
           {
             $this->Permissions->GroupId=NULL;
             $this->LoadPermissions(0);
           }
         }
     }
 
     function PermissionObject()
     {
         return $this->Permissions;
     }
 
     function PermissionItemObject($PermissionName)
     {
         $p = $this->Permissions->GetPermByName($PermissionName);
         return $p;
     }
 
     function HasPermission($PermissionName,$GroupID)
     { 
         global $objSession;
 
         $perm = $this->PermissionValue($PermissionName,$GroupID);
 //        echo "Permission $PermissionName for $GroupID is $perm in ".$this->Get("CategoryId")."<br>\n";
         if(!$perm)
         {
             $perm=$objSession->HasSystemPermission("ROOT");
         }
         return ($perm==1);
     }
 
     function PermissionValue($PermissionName,$GroupID)
     {
       //$this->LoadPermissions();            
       $ret=NULL;
       //echo "Looping though ".count($this->Permissions)." permissions Looking for $PermissionName of $GroupID<br>\n";
       if($this->Permissions->GroupId != $GroupID)
       {
           $this->Permissions->Clear();
           $this->Permissions->GroupId = $GroupID;
       }
 
       $this->Permissions->CatId=$this->Get("CategoryId");
       $ret = $this->Permissions->GetPermissionValue($PermissionName);
       if($ret == NULL)
       {
          $cats = explode("|",substr($this->Get("ParentPath"),1,-1));
 
        if(is_array($cats))
         { 
           $cats = array_reverse($cats);          
           $cats[] = 0;
           foreach($cats as $catid)
           {  
             $this->Permissions->LoadCategory($catid);
             $ret = $this->Permissions->GetPermissionValue($PermissionName);
             if(is_numeric($ret))
               break;
           }
         }
       }
       return $ret;
     }
 
     function SetPermission($PermName,$GroupID,$Value,$Type=0)
     {
         global $objSession, $objPermissions, $objGroups;
         
         if($this->Permissions->GroupId != $GroupID)
         {
             $this->Permissions->Clear();
             $this->Permissions->GroupId = $GroupID;
         }
 
         if($objSession->HasSystemPermission("GRANT"))
         {
             $current = $this->PermissionValue($PermName,$GroupID);
 
             if($current == NULL)
             {
                 $this->Permissions->Add_Permission($this->Get("CategoryId"),$GroupId,$PermName,$Value,$Type);
             }
             else
             {
                 $p = $this->Permissions->GetPermByName($PermName);
                 if($p->Inherited==FALSE)
                 {
                     $p->Set("PermissionValue",$Value);
                     $p->Update();
                 }
                 else
                    $this->Permissions->Add_Permission($this->Get("CategoryId"),$GroupId,$PermName,$Value,$Type);
             }
             if($PermName == "CATEGORY.VIEW")
             {           
               $Groups = $objGroups->GetAllGroupList();
               $ViewList = $this->Permissions->GetGroupPermList($this,"CATEGORY.VIEW",$Groups);
               $this->SetViewPerms("CATEGORY.VIEW",$ViewList,$Groups);
               $this->Update();
             }
        }
     }
 
     function SetViewPerms($PermName,$acl,$allgroups)
     {
        global $objPermCache;
 
        $dacl = array();
        if(!is_array($allgroups))
        {
            global $objGroups;
            $allgroups = $objGroups->GetAllGroupList();
        }
        
        for($i=0;$i<count($allgroups);$i++)
        {
            $g = $allgroups[$i];
            if(!in_array($g,$acl))
                $dacl[] = $g;
        }
         if(count($acl)<count($dacl))
         {
             $aval = implode(",",$acl);
             $dval = "";
         }
         else
         {            
             $dval = implode(",",$dacl);
             $aval = "";
         }
         if(strlen($aval)==0 && strlen($dval)==0)
         {
          $aval = implode(",",$allgroups);
         }
         $PermId = $this->Permissions->GetPermId($PermName);
         $pc = $objPermCache->GetPerm($this->Get("CategoryId"),$PermId);
         if(is_object($pc))
         {            
             $pc->Set("ACL",$aval);
             $pc->Set("DACL",$dval);
             $pc->Update();
         }
         else
             $objPermCache->AddPermCache($this->Get("CategoryId"),$PermId,$aval,$dval);
 
         //$this->Update();
     }
 
     function GetACL($PermName)
     {
         global $objPermCache;
 
         $ret = "";
         $PermId = $this->Permissions->GetPermId($PermName);
         $pc = $objPermCache->GetPerm($this->Get("CategoryId"),$PermId);
         if(is_object($pc))
         {            
             $ret = $this->Get("ACL");
         }
         return $ret;
     }
 
 
     function UpdateACL()
     {
        global $objGroups, $objPermCache;
 
        $glist = $objGroups->GetAllGroupList();
 
        $ViewList = $this->Permissions->GetGroupPermList($this,"CATEGORY.VIEW",$glist);       
        $perms = $this->Permissions->GetAllViewPermGroups($this,$glist);
        //echo "<PRE>";print_r($perms); echo "</PRE>";
        foreach($perms as $PermName => $l)
        {                
          $this->SetViewPerms($PermName,$l,$glist);
        }
     }
 
     function Cat_Link()
     {
         global $m_var_list_update;
 
         $m_var_list_update["cat"] = $this->Get("CategoryId");
         $ret =  GetIndexURL(2)."?env=".BuildEnv();
         unset($m_var_list_update["cat"]);
         return $ret;
     }
 
     function Parent_Link()
     {
         global $m_var_list_update;
 
         $m_var_list_update["cat"] = $this->Get("ParentId");
         $ret =  GetIndexURL(2)."?env=".BuildEnv();
         unset($m_var_list_update["cat"]);
         return $ret;
     }
 
     function Admin_Parent_Link($page=NULL)
     {
         global $m_var_list_update;
 
         if(!strlen($page))
             $page = $_SERVER["PHP_SELF"];
         $m_var_list_update["cat"] = $this->Get("ParentId");
         $ret =  $page."?env=".BuildEnv();
         unset($m_var_list_update["cat"]);
         return $ret;
     }
 
     function StatusIcon()
     {
         global $imagesURL;
 
         $ret = $imagesURL."/itemicons/";
 
         switch($this->Get("Status"))
         {
           case STATUS_DISABLED:
             $ret .= "icon16_cat_disabled.gif";
             break;
           case STATUS_PENDING:
             $ret .= "icon16_cat_pending.gif";  
             break;
           case STATUS_ACTIVE:
             $img = "icon16_cat.gif";
             if($this->IsPopItem())
                 $img = "icon16_cat_pop.gif";
             if($this->IsHotItem())
                 $img = "icon16_cat_hot.gif";
             if($this->IsNewItem())           
                 $img = "icon16_cat_new.gif";
             if($this->Is("EditorsPick"))
                 $img = "icon16_car_pick.gif";
             $ret .= $img;
             break;
         }
         return $ret;
     }
 
     function SubCatCount()
     {
         $ret = $this->Get("CachedDescendantCatsQty");
 
             $sql = "SELECT COUNT(*) as SubCount FROM ".$this->tablename." WHERE ParentPath LIKE '".$this->Get("ParentPath")."%' AND CategoryId !=".$this->Get("CategoryId");
             $rs = $this->adodbConnection->Execute($sql);
             if($rs && !$rs->EOF)
             {
                 $val = $rs->fields["SubCount"];
                 if($val != $this->Get("CachedDescendantCatsQty"))
                 {               
                   $this->Set("CachedDescendantCatsQty",$val);
                   $this->Update();
                 }
                 $ret = $this->Get("CachedDescendantCatsQty");                
             }                       
         return $ret;
     }
 
     function GetSubCatIds()
     {
         $sql = "SELECT CategoryId FROM ".$this->tablename." WHERE ParentPath LIKE '".$this->Get("ParentPath")."%' AND CategoryId !=".$this->Get("CategoryId");
         $rs = $this->adodbConnection->Execute($sql);
         $ret = array();
         while($rs && !$rs->EOF)
         {
             $ret[] = $rs->fields["CategoryId"];
             $rs->MoveNext();
         }
         return $ret;
     }
     
     function GetParentIds()
     {
     	$Parents = array();
     	$ParentPath = $this->Get("ParentPath");
     	if(strlen($ParentPath))
     	{
     		$ParentPath = substr($ParentPath,1,-1);
     		$Parents = explode("|",$ParentPath);
     	}
     	return $Parents;
     }
     
     function ItemCount($ItemType="")
     {
 		global $objItemTypes,$objCatList,$objCountCache;
 	
 		if(!is_numeric($ItemType))
 		{
       		$TypeId = $objItemTypes->GetItemTypeValue($ItemType); 
 		}
 		else
 	  		$TypeId = (int)$ItemType;      		 		
 	  	  
 	  	//$path = $this->Get("ParentPath");
 	  	//$path = substr($path,1,-1);
 	  	//$path = str_replace("|",",",$path);
 	  	$path = implode(",",$this->GetSubCatIds());
 	  	if(strlen($path))
 	  	{
 	  		$path = $this->Get("CategoryId").",".$path;
 	  	}
 	  	else
 	  	  $path = $this->Get("CategoryId");
 	  	
 	  	$res = TableCount(GetTablePrefix()."CategoryItems","CategoryId IN ($path)",FALSE);    
 	  	
 	  	return $res;	  	
     }
 
     function ParseObject($element)
     {
         global $objConfig, $objCatList, $rootURL, $var_list, $var_list_update, $m_var_list_update, $objItemTypes,$objCountCache;
         $extra_attribs = ExtraAttributes($element->attributes);
         
         //print_r($element);
         if(strtolower($element->name)==$this->TagPrefix)
         {          
             $field = strtolower( $element->GetAttributeByName('_field') );
             switch($field)
             {
             	case 'm_language':
             		$ret = language( $element->GetAttributeByName('_Phrase') );
             		break;
             	
             	case 'parentcategorylink':
 	            	$m_var_list_update['cat'] = $this->Get('ParentId');
 	                $m_var_list_update['p'] = 1;
 	                $ret = str_replace('advanced_view.php','browse.php',$_SERVER['PHP_SELF']).'?env='.BuildEnv();
 	                unset($m_var_list_update['cat']);
 	                unset($m_var_list_update['p']);
 	                return $ret;
 	                break;
 
 	            case 'primarycategory':
             		$ret = $this->Get('CachedNavbar');
             		if($ret) // category not in root
             		{
             			$ret = explode('>',$ret);
             			array_pop($ret);
             			$ret = implode('>',$ret);
             		}
             		
             		$ret = prompt_language($objConfig->Get("Root_Name")).($ret ? '>' : '').$ret;
             		break;
             	
             	case "name":
             case "Name":
             	/*
             	@field:cat.name
             	@description:Category name
             	*/
                 $ret = $this->HighlightField("Name");
             break;
             case "description":
             	/*
             	@field:cat.description
             	@description:Category Description
             	*/            
                 $ret = ($this->Get("Description"));
                 $ret = $this->HighlightText($ret);
             break;
             case "cachednavbar":
             	/*
             	@field:cat.cachednavbar
             	@description: Category cached navbar
             	*/
                 $ret = $this->HighlightField("CachedNavbar");
                 if(!strlen($ret))
                 {
                     $this->UpdateCachedPath();
                     $ret = $this->HighlightField("CachedNavbar");
                 }
             break;
             case "image":
             	/*
  				@field:cat.image
  				@description:Return an image associated with the category
   				@attrib:_default:bool:If true, will return the default image if the requested image does not exist
   				@attrib:_name::Return the image with this name
   				@attrib:_thumbnail:bool:If true, return the thumbnail version of the image
   				@attrib:_imagetag:bool:If true, returns a complete image tag. exta html attributes are passed to the image tag
                */            
                $default = $element->GetAttributeByName('_primary');
                $name = $element->GetAttributeByName('_name');
                if(strlen($name))
                {
                    $img = $this->GetImageByName($name);
                }
                else
                {
                    if($default)
                      $img = $this->GetDefaultImage();
                }
                if($img)
                {
                    if( $element->GetAttributeByName('_thumbnail') )
                    {
                      $url = $img->parsetag("thumb_url");
                    }
                    else
                      $url = $img->parsetag("image_url");
 
                }
                else
                {
                   $url = $element->GetAttributeByName('_defaulturl');
                }
 
                if( $element->GetAttributeByName('_imagetag') )
                {
                    if(strlen($url))
                    {
                      $ret = "<IMG src=\"$url\" $extra_attribs >";
                    }
                    else
                        $ret = "";
                }
                else
                    $ret = $url;
             break;
             case "createdby":
 				/*
 				@field:cat.createdby
 				@description:parse a user field of the user that created the category
   				@attrib:_usertag::User field to return (defaults to login ID)            
   				*/            
                 $field = $element->GetAttributeByName('_usertag');
                 if(!strlen($field))
                 {
                     $field = "user_login";
                 }
                 $u = $objUsers->GetUser($this->Get("CreatedById"));
                 $ret = $u->parsetag($field);
             break;
             case "custom":
                 /*
                 @field:cat.custom
                 @description:Returns a custom field
   				@attrib:_customfield::field name to return
   				@attrib:_default::default value
   				*/            
                 $field =  $element->GetAttributeByName('_customfield'); 
                 $default = $element->GetAttributeByName('_default');
                 $ret = $this->GetCustomFieldValue($field,$default);
             break;
             
             case "catsubcats":
                 /*
                 @field:cat.catsubcats
                 @description:Returns a list of subcats of current category
   				@attrib:_limit:int:Number of categories to return
   				@attrib:_separator::Separator between categories
   				@attrib:_anchor:bool:Make an anchor (only if template is not specified)
   				@attrib:_TargetTemplate:tpl:Target template
   				@attrib:_Ending::Add special text at the end of subcategory list
   				@attrib:_Class::Specify stly sheet class for anchors (if used) or "span" object			
   				*/            
                 $limit =  ((int)$element->attributes["_limit"]>0)? $element->attributes["_limit"] : NULL; 
                 $separator = $element->attributes["_separator"];
                 $anchor = (int)($element->attributes["_anchor"])? 1 : NULL;                
                 $template = strlen($element->attributes["_TargetTemplate"])? $element->attributes["_TargetTemplate"] : NULL;                       
                 $ending = strlen($element->attributes["_ending"])? $element->attributes["_ending"] : NULL;
                 $class = strlen($element->attributes["_class"])? $element->attributes["_class"] : NULL;
                 
                 $ret = $this->GetSubCats($limit, $template, $separator, $anchor, $ending, $class);
                 
             break;
             
             case "date":
             	/*
   				@field:cat.date
   				@description:Returns the date/time the category was created
   				@attrib:_tz:bool:Convert the date to the user's local time
   				@attrib:_part::Returns part of the date.  The following options are available: month,day,year,time_24hr,time_12hr
             	*/            
                 $d = $this->Get("CreatedOn");
 
                 if( $element->GetAttributeByName('_tz') )
                 {
                     $d = GetLocalTime($d,$objSession->Get("tz"));
                 }
 
                 $part = strtolower( $element->GetAttributeByName('_part') );
                 if(strlen($part))
                 {
                     $ret = ExtractDatePart($part,$d);
                 }
                 else
                 {                                        
                   if(!is_numeric($d))
                   {                  
                     $ret = "";
                   }
                   else
                     $ret = LangDate($d);
                 }
             break;
             case "link":
             	/*
   				@field:cat.link
   				@description:Returns a URL setting the category to the current category
   				@attrib:_template:tpl:Template URL should point to   
   				@attrib:_mod_template:tpl:Template INSIDE a module to which the category belongs URL should point to
   				*/        
   				if ( strlen( $element->GetAttributeByName('_mod_template') ) ){ 
   					//will prefix the template with module template root path depending on category
             			$ids = $this->GetParentIds();
             			$tpath = GetModuleArray("template");
             			$roots = GetModuleArray("rootcat");
             			
             			// get template path of module, by searching for moudle name 
             			// in this categories first parent category 
             			// and then using found moudle name as a key for module template paths array
             			$path = $tpath[array_search ($ids[0], $roots)];
             			$t = $path . $element->GetAttributeByName('_mod_template');
             		}
             		else 
             			$t = $element->GetAttributeByName('_template');
             		  
                 
                 if(strlen($t))
                 {                
                     $var_list_update["t"] = $t;
                 }
                 else
                     $var_list_update["t"] = $var_list["t"];
                 $m_var_list_update["cat"] = $this->Get("CategoryId");
                 $ret = GetIndexURL(2)."?env=" . BuildEnv();
                 unset($m_var_list_update["cat"], $var_list_update["t"]);
             break;
             case "adminlink":
                 $m_var_list_update["cat"] = $this->Get("CategoryId");
                 $m_var_list_update["p"] = 1;
                 $ret = $_SERVER["PHP_SELF"]."?env=" . BuildEnv();
                 unset($m_var_list_update["cat"]);
                 unset($m_var_list_update["p"]);
                 return $ret;
                 break;            
             case "customlink":
                 $t = $this->GetCustomFieldValue("indextemplate","");
                 if(strlen($t))
                 {                
                     $var_list_update["t"] = $t;
                 }
                 else
                     $var_list_update["t"] = $var_list["t"];
                 $m_var_list_update["cat"] = $this->Get("CategoryId");
                 $ret = GetIndexURL(2)."?env=" . BuildEnv();
                 unset($m_var_list_update["cat"], $var_list_update["t"]);
 			break;            
             case "link_selector":
                 $m_var_list_update["cat"] = $this->Get("CategoryId");
                 $ret = $_SERVER["PHP_SELF"]."?env=" . BuildEnv();
                 
                 // pass through selector
                 if( isset($_REQUEST['Selector']) ) $ret .= '&Selector='.$_REQUEST['Selector'];
                 
                 // pass new status
                 if( isset($_REQUEST['new']) ) $ret .= '&new='.$_REQUEST['new'];
                 
                 unset($m_var_list_update["cat"]);
                 return $ret;
                 break;
             case "admin_icon":
                 if( $element->GetAttributeByName('fulltag') )
                 {
                     $ret = "<IMG $extra_attribs SRC=\"".$this->StatusIcon()."\">";
                 }
                 else
                     $ret = $this->StatusIcon();
             break;
             case "subcats":
             	/*
             	@field:cat.subcats
             	@description: Loads category's subcategories into a list and renders using the m_list_cats global tag           	
             	@attrib:_subcattemplate:tpl:Template used to render subcategory list elements
   				@attrib: _columns:int: Numver of columns to display the categories in (defaults to 1)
   				@attrib: _maxlistcount:int: Maximum number of categories to list
   				@attrib: _FirstItemTemplate:tpl: Template used for the first category listed
   				@attrib: _LastItemTemplate:tpl: Template used for the last category listed  				
   				@attrib: _NoTable:bool: If set to 1, the categories will not be listed in a table. If a table is used, all HTML attributes are passed to the TABLE tag
 				*/            	
                 $attr = array();
                 $attr["_catid"] = $this->Get("CategoryId");
                 $attr["_itemtemplate"] = $element->GetAttributeByName('_subcattemplate');
                 if( $element->GetAttributeByName('_notable') )
                     $attr["_notable"]=1;
                 $ret = m_list_cats($attr);
             break;
             case "subcatcount":
             	/*
             	@field:cat.subcatcount
             	@description:returns number of subcategories
             	*/
             	$GroupOnly = $element->GetAttributeByName('_grouponly') ? 1 : 0;
             	$txt = "<inp:m_itemcount _CatId=\"".$this->Get("CategoryId")."\" _SubCats=\"1\" ";
             	$txt .="_CategoryCount=\"1\" _ItemType=\"1\" _GroupOnly=\"$GroupOnly\" />";
             	$tag = new clsHtmlTag($txt);
             	$ret = $tag->Execute();	            	
             break;    
             case "itemcount":
                /*
                @field:cat.itemcount
                @description:returns the number of items in the category
                @attrib:_itemtype::name of item type to count, or all items if not set
                */
                $typestr = $element->GetAttributeByName('_itemtype');
                if(strlen($typestr))
                {
                  $type = $objItemTypes->GetTypeByName($typestr);
                  if(is_object($type))
                  {
                    $TypeId = $type->Get("ItemType");
             	   $GroupOnly = $element->GetAttributeByName('_grouponly') ? 1 : 0;
             	   $txt = "<inp:m_itemcount _CatId=\"".$this->Get("CategoryId")."\" _SubCats=\"1\" ";
             	   $txt .=" _ListType=\"category\" _CountCurrent=\"1\" _ItemType=\"$TypeId\" _GroupOnly=\"$GroupOnly\" />";
             	   $tag = new clsHtmlTag($txt);
             	   $ret = $tag->Execute();	            	
                  }
                  else
                    $ret = "";
                }
                else
                {
                	   $ret = (int)$objCountCache->GetCatListTotal($this->Get("CategoryId"));
                }
             break;
             case "totalitems":
                /*
                @field:cat.totalitems
                @description:returns the number of items in the category and all subcategories               
                */           
                 $ret = $this->ItemCount();               
             break;
             
             case 'modified':
             	$ret = '';
             	$date = $this->Get('Modified');
             	if(!$date) $date = $this->Get('CreatedOn');
             	if( $element->GetAttributeByName('_tz') )
             	{
             		$date = GetLocalTime($date,$objSession->Get("tz"));
             	}
 
             	$part = strtolower($element->GetAttributeByName('_part') );
             	if(strlen($part))
             	{
             		$ret = ExtractDatePart($part,$date);
             	}
             	else
             	{
             		$ret = ($date <= 0) ? '' : LangDate($date);
             	}
             	break;
             
             case "itemdate":
             	/*
             	@field:cat.itemdate
             	@description:Returns the date the cache count was last updated
             	@attrib:_itemtype:Item name to check
   				@attrib:_tz:bool:Convert the date to the user's local time
   				@attrib:_part::Returns part of the date.  The following options are available: month,day,year,time_24hr,time_12hr            	
             	*/
                 $typestr = $element->GetAttributeByName('_itemtype');
                 $type = $objItemTypes->GetTypeByName($typestr);
                 if(is_object($type))
                 {
                     $TypeId = $type->Get("ItemType");
                     $cc = $objCountCache->GetCountObject(1,$TypeId,$this->get("CategoryId"),0);
                     if(is_object($cc))
                     {
                     	$date = $cc->Get("LastUpdate");
                     }
                     else  
                       $date = "";
                       
                     //$date = $this->GetCacheCountDate($TypeId);
                     if( $element->GetAttributeByName('_tz') )
                     {
                         $date = GetLocalTime($date,$objSession->Get("tz"));
                     }
 
                     $part = strtolower($element->GetAttributeByName('_part') );
                     if(strlen($part))
                     {
                         $ret = ExtractDatePart($part,$date);
                     }
                     else
                     {
                       if($date<=0)
                       {
                         $ret = "";
                       }
                       else
                         $ret = LangDate($date);
                     }
                 }
                 else
                   $ret = "";
             break;
             case "new":
             	/*
  				@field:cat.new
  				@description:returns text if category's status is "new"
   				@attrib:_label:lang: Text to return if status is new            
   				*/            
                 if($this->IsNewItem())
                 {
                   $ret = $element->GetAttributeByName('_label');
                   if(!strlen($ret))
                     $ret = "lu_new";
                   $ret = language($ret);
                 }
                 else
                  $ret = "";
            		break;
             case "pick":
             	/*
  				@field:cat.pick
  				@description:returns text if article's status is "hot"
   				@attrib:_label:lang: Text to return if status is "hot"            
   				*/               
                 if($this->Get("EditorsPick")==1)
                 {
                   $ret = $element->GetAttributeByName('_label');
                   if(!strlen($ret))
                     $ret = "lu_pick";
                   $ret = language($ret);
                 }
                 else
                    $ret = "";
             	break;
                         
             case "parsetag":
             	/*
  				@field:cat.parsetag
  				@description:returns a tag output with this categoriy set as a current category
   				@attrib:_tag:: tag name            
   				*/               
                 
   				$tag = new clsHtmlTag();
                 $tag->name = $element->GetAttributeByName('_tag');
                 $tag->attributes = $element->attributes;               
                 $tag->attributes["_catid"] = $this->Get("CategoryId"); 
                 $ret = $tag->Execute();               
             	break;
             	
            
             /*
             @field:cat.relevance
            	@description:Displays the category relevance in search results
   			@attrib:_displaymode:: How the relevance should be displayed<br>
   				<UL>
   					<LI>"Numerical": Show the decimal value 
   				    <LI>"Bar": Show the HTML representing the relevance. Returns two HTML cells &lg;td&lt; with specified background colors
   				    <LI>"Graphical":Show image representing the relevance
   				</UL>  
 			@attrib:_onimage::Zero relevance image shown in graphical display mode. Also used as prefix to build other images (i.e. prefix+"_"+percentage+".file_extension"
 			@attrib:_OffBackGroundColor::Off background color of HTML cell in bar display mode
 			@attrib:_OnBackGroundColor::On background color of HTML cell in bar display mode           
             */  
             
             }
             if( !isset($ret) ) $ret = parent::ParseObject($element);
             
         }
         return $ret;
     }
 
 
     function parsetag($tag)
     { 
         global $objConfig,$objUsers, $m_var_list, $m_var_list_update;
         if(is_object($tag))
         {        
             $tagname = $tag->name;
         }
         else
             $tagname = $tag;
 
         switch($tagname)
         {
           case "cat_id":
                 return $this->Get("CategoryId");
                 break;        
           case "cat_parent":
                 return $this->Get("ParentId");
                 break;  
           case "cat_fullpath":
                 return $this->Get("CachedNavbar");
                 break;
           case "cat_name":
                 return $this->Get("Name");
                 break;
           case "cat_desc":
                 return $this->Get("Description");
                 break;
           case "cat_priority":
                 if($this->Get("Priority")!=0)
                 {               
                   return (int)$this->Get("Priority");
                 }
                 else
                   return "";
                 break;
           case "cat_pick":
                 if ($this->Get("EditorsPick"))
                     return "pick";
                 break;
           case "cat_status":
                 return $this->Get("Status");
                 break;
           case "cat_Pending":
                 return $this->Get("Name");
                 break;
 
           case "cat_pop":
                 if($this->IsPopItem())
                     return "pop";
                 break;
           case "cat_new":
                 if($this->IsNewItem())
                     return "new";
                 break;
           case "cat_hot":
                 if($this->IsHotItem())
                     return "hot";
                 break;
           case "cat_metakeywords":
                 return $this->Get("MetaKeywords");
                 break;
           case "cat_metadesc":
                 return $this->Get("MetaDescription");
                 break;
           case "cat_createdby":
                 return $objUsers->GetUserName($this->Get("CreatedById"));
                 break;
           case "cat_resourceid":
                 return $this->Get("ResourceId");
                 break;
           case "cat_sub_cats":
                 return $this->GetSubCats($objConfig->Get("SubCat_ListCount"));
                 break;
             case "cat_link":
                 return $this->Cat_Link();
                 break;
             case "subcat_count":
                 return $this->SubCatCount();
                 break;
             case "cat_itemcount":
                 return (int)$this->GetTotalItemCount();
                 break;
             case "cat_link_admin":
                 $m_var_list_update["cat"] = $this->Get("CategoryId");
                 $m_var_list_update["p"] = 1;
                 $ret = $_SERVER["PHP_SELF"]."?env=" . BuildEnv();
                 unset($m_var_list_update["cat"]);
                 unset($m_var_list_update["p"]);
                 return $ret;
                 break;
             case "cat_admin_icon":
                 $ret = $this->StatusIcon();
                 return $ret;
                 break;
             case "cat_link_selector":
                 $m_var_list_update["cat"] = $this->Get("CategoryId");
                 $ret = $_SERVER["PHP_SELF"]."?env=" . BuildEnv();
                 unset($m_var_list_update["cat"]);
                 return $ret;
                 break;
 
             case "cat_link_edit":
                 $m_var_list_update["id"] = $this->Get("CategoryId");
                 $ret = "addcategory.php?env=" . BuildEnv();
                 unset($m_var_list_update["id"]);
                 return $ret;
                 break;        
 
             case "cat_date":               
                 return LangDate($this->Get("CreatedOn"));
                 break;
             case "cat_num_cats":
                 return $this->Get("CachedDescendantCatsQty");
                 break;
          case "cell_back":
              if ($m_var_list_update["cat_cell"]=="#cccccc")
              {
                  $m_var_list_update["cat_cell"]="#ffffff";
                  return "#ffffff";
              }
              else
              {
                  $m_var_list_update["cat_cell"]="#cccccc";
                  return "#cccccc";
              }
              break;
           default:
               return "Undefined:$tagname";
         }
     }
 
     function ParentNames()
     {
         global $objCatList;
 
         if(strlen($this->Get("CachedNavbar"))==0)
         {
           $nav = "";
           //echo "Rebuilding Navbar..<br>\n";
           if(strlen($this->Get("ParentPath"))==0)
           {   
             $this->UpdateCachedPath();
           }
           $cats = explode("|",substr($this->Get("ParentPath"),1,-1));
           
           foreach($cats as $catid)
           { 
               $cat =& $objCatList->GetCategory($catid);
               if(is_object($cat))
               { 
                   if(strlen($cat->Get("Name")))
                       $names[] = $cat->Get("Name");   
                 
               }
           }       
           $nav = implode(">", $names);
           $this->Set("CachedNavbar",$nav);
           $this->Update();
         }
         $res = explode(">",$this->Get("CachedNavbar"));
         return $res;
     }
 
 // not used anywhere
     /*    function UpdateCacheCounts()
     {
     	global $objItemTypes;
 
     	$CatId = $this->Get("CategoryId");
 
     	if($CatId>0)
     	{
     		//echo "Updating count for ".$this->Get("CachedNavbar")."<br>\n";
     		UpdateCategoryCount(0,$CatId);
     	}
     }*/
     
     /**
     * @return void
     * @param int $date
     * @desc Set Modified field for category & all it's parent categories
     */
     function SetLastUpdate($date)
     {
     	$parents = $this->Get('ParentPath');
     	$parents = substr($parents, 1, strlen($parents) - 2 );
     	$parents = explode('|', $parents);
     	
     	$db =&GetADODBConnection();
     	$sql = 'UPDATE '.$this->tablename.' SET Modified = '.$date.' WHERE CategoryId IN ('.implode(',', $parents).')';
     	$db->Execute($sql);
     }
     
       
 }
 
 class clsCatList extends clsItemList //clsItemCollection
 {
   	//var $Page; // no need because clsItemList class used instead of clsItemCollection
   	//var $PerPageVar;
 
   	function clsCatList()
   	{
   	    global $m_var_list;
   	    $this->clsItemCollection();
   	    $this->classname="clsCategory";
   	    $this->AdminSearchFields = array("Name","Description");
   	    $this->Page = (int)$m_var_list["p"];
   	    $this->PerPageVar = "Perpage_Category";
   	    $this->SourceTable = GetTablePrefix()."Category";
   	    $this->BasePermission="CATEGORY";
   	    $this->DefaultPerPage = 20;
   	}
 
 	function SaveNewPage()
     {
     	global $m_var_list;
     	$m_var_list["p"] = $this->Page;
     }
 
   function GetCountSQL($PermName,$CatId=NULL, $GroupId=NULL, $AdditonalWhere="")
   {
   	global $objSession, $objPermissions, $objCatList;
   	
   	$ltable = $this->SourceTable;
     $acl = $objSession->GetACLClause();
     $cattable = GetTablePrefix()."CategoryItems";
     $CategoryTable = GetTablePrefix()."Category";
     $ptable = GetTablePrefix()."PermCache";  	
     $VIEW = $objPermissions->GetPermId($PermName);
   	
   	$sql = "SELECT count(*) as CacheVal FROM $ltable ";
     $sql .="INNER JOIN $ptable ON ($ltable.CategoryId=$ptable.CategoryId) ";
     $sql .="WHERE ($acl AND PermId=$VIEW AND $ltable.Status=1) ";
 
 	if(strlen($AdditonalWhere)>0)
     {
       $sql .= "AND (".$AdditonalWhere.")";
     }
     return $sql;
   }  
 
   function CountCategories($attribs)
   {
   	global $objSession;
   	$ParentWhere='';
   	$cat = getArrayValue($attribs,'_catid');
     if(!is_numeric($cat))
     {
         $cat = $this->CurrentCategoryID();
     }
     if((int)$cat>0)
         $c = $this->GetCategory($cat);
         
   	if( getArrayValue($attribs,'_subcats') && $cat>0)
     {
        $ParentWhere = "(ParentPath LIKE '".$c->Get("ParentPath")."%' AND ".$this->SourceTable.".CategoryId != $cat)";
     }
     if( getArrayValue($attribs,'_today') )
     {
       $today = mktime(0,0,0,date("m"),date("d"),date("Y"));             
       $TodayWhere = "(CreatedOn>=$today)";	
     }
     else
     {
     	$TodayWhere = '';
     }
     if( getArrayValue($attribs,'_grouponly') )
 	{
 	   $GroupList = $objSession->Get("GroupList");	    	  
 	}
 	else        		
 	   $GroupList = NULL;
 	       	
 	$where = "";
 	if(strlen($ParentWhere))
 	{
 	  $where = $ParentWhere;    
 	}
 	if(strlen($TodayWhere))
 	{
 	  if(strlen($where))	       		
 	     $where .=" AND ";
 	   $where .= $TodayWhere;
 	}
     $sql = $this->GetCountSQL("CATEGORY.VIEW",$cat,$GroupList,$where);
     
 //    echo "SQL: ".$sql."<BR>";
     
 	$rs = $this->adodbConnection->Execute($sql);  
 	if($rs && !$rs->EOF)
 	{
 	   $ret = $rs->fields["CacheVal"];		  
 	}
 	else
 	  $ret = 0;
 	  
 	return $ret;  
   }         
     
   function CurrentCategoryID()
   {
       global $m_var_list;      
       return (int)$m_var_list["cat"];
   }
 
   function NumCategories()
   {
       return $this->NumItems();
   }
 
   function &CurrentCat()
   {
       //return $this->GetCategory($this->CurrentCategoryID());
       return $this->GetItem($this->CurrentCategoryID());
   }
 
   function &GetCategory($CatID)
   {
       return $this->GetItem($CatID);
   }
 
   function GetByResource($ResId)
   {
       return $this->GetItemByField("ResourceId",$ResId);
   }
 
   function QueryOrderByClause($EditorsPick=FALSE,$Priority=FALSE,$UseTableName=FALSE)  
   {
   	global $objSession;
   	
     if($UseTableName)
     {
       $TableName = $this->SourceTable.".";
     }
     else
       $TableName = "";	
 
     $Orders = array();
 
     if($EditorsPick)  
     {
     	$Orders[] = $TableName."EditorsPick DESC";
     }
     if($Priority)
     {
        $Orders[] = $TableName."Priority DESC";  	
     }
   
   	$FieldVar = "Category_Sortfield";
     $OrderVar = "Category_Sortorder";
        	 	   
     if(is_object($objSession))
     {
       if(strlen($objSession->GetPersistantVariable($FieldVar))>0)  
       {  	
       		$Orders[] = trim($TableName.$objSession->GetPersistantVariable($FieldVar) . " ". 
           		       $objSession->GetPersistantVariable($OrderVar));            	
       }
     }
 
   	$FieldVar = "Category_Sortfield2";
     $OrderVar = "Category_Sortorder2";
        	 	   
     if(is_object($objSession))
     {
       if(strlen($objSession->GetPersistantVariable($FieldVar))>0)  
       {  		
       		$Orders[] = trim($TableName.$objSession->GetPersistantVariable($FieldVar) . " ". 
           		       $objSession->GetPersistantVariable($OrderVar));            	
       }
     }
     
     
     if(count($Orders)>0)
     {
     	$OrderBy = "ORDER BY ".implode(", ",$Orders);
     }
     else   
       $OrderBy="";
     return $OrderBy; 
   }
   
 
 	function LoadCategories($where="", $orderBy = "", $no_limit = true, $fix_method = 'set_first')
   	{
       	// load category list using $where clause
       	// apply ordering specified in $orderBy
       	// show all cats ($no_limit = true) or only from current page ($no_limit = false)
       	// in case if stored page is greather then page count issue page_fixing with
       	// method specified (see "FixInvalidPage" method for details)
       	$PerPage = $this->GetPerPage();
       
       	$this->QueryItemCount = TableCount($this->SourceTable,$where,0);
       	if($no_limit == false)
       	{
       	    $this->FixInvalidPage($fix_method);
       	    $Start = ($this->Page-1) * $PerPage;
       	    $limit = "LIMIT ".$Start.",".$PerPage;
       	}
       	else
       		$limit = NULL;           
       
       	return $this->Query_Category($where, $orderBy, $limit);
   	}
 
   function Query_Category($whereClause="",$orderByClause="",$limit=NULL)
   {   
     global $m_var_list, $objSession, $Errors, $objPermissions;
     $GroupID = $objSession->Get("GroupID");
     $resultset = array();
 
    $table = $this->SourceTable;
    $ptable = GetTablePrefix()."PermCache";
    $CAT_VIEW = $objPermissions->GetPermId("CATEGORY.VIEW");
    if(!$objSession->HasSystemPermission("ADMIN"))
    {   
      $sql = "SELECT * FROM $table INNER JOIN $ptable ON ($ptable.CategoryId=$table.CategoryId)";
      $acl_where = $objSession->GetACLClause(); 
      if(strlen($whereClause))
      {    
         $sql .= " WHERE ($acl_where) AND PermId=$CAT_VIEW AND ".$whereClause;
      }
      else
         $sql .= " WHERE ($acl_where) AND PermId=$CAT_VIEW ";
    }
    else
    {
        $sql ="SELECT * FROM $table ".($whereClause ? "WHERE $whereClause" : '');
    }
    $sql .=" ".$orderByClause;
 
    if(isset($limit) && strlen(trim($limit)))
        $sql .= " ".$limit;
     if($objSession->HasSystemPermission("DEBUG.LIST"))
       echo $sql;
     //echo "SQL: $sql<br>";
     return $this->Query_item($sql);
   }
   
   function CountPending()
   {
       return TableCount($this->SourceTable,"Status=".STATUS_PENDING,0);
   }
 
   function GetPageLinkList($dest_template=NULL,$page="",$PagesToList=10,$HideEmpty=TRUE)
   {
       global $objConfig, $m_var_list_update, $var_list_update, $var_list;
 
       if(!strlen($page))
           $page = GetIndexURL(2);
 
       $PerPage = $this->GetPerPage();
       $NumPages = ceil( $this->GetNumPages($PerPage) );
       
       if($NumPages == 1 && $HideEmpty) return '';
 
       if(strlen($dest_template))
       {
           $var_list_update["t"] = $dest_template;
       }
       else
           $var_list_update["t"] = $var_list["t"];
 
       $o = "";
       if($this->Page>$NumPages)
           $this->Page=$NumPages;
 
       $StartPage = (int)$this->Page - ($PagesToList/2);
       if($StartPage<1)
           $StartPage=1;
 
       $EndPage = $StartPage+($PagesToList-1);
       if($EndPage>$NumPages)
       {
           $EndPage = $NumPages;
           $StartPage = $EndPage-($PagesToList-1);
           if($StartPage<1)
               $StartPage=1;
       }
 
       $o = "";
       if($StartPage>1)
       {
         $m_var_list_update["p"] = $this->Page-$PagesToList;
         $prev_url = $page."?env=".BuildEnv();
         $o .= "<A HREF=\"$prev_url\">&lt;&lt;</A>";
       }
 
 
       for($p=$StartPage;$p<=$EndPage;$p++)
       {
           if($p!=$this->Page)
           {
               $m_var_list_update["p"]=$p;
               $href = $page."?env=".BuildEnv();
               $o .= " <A HREF=\"$href\" >$p</A> ";
           }
           else
           {
               $o .= "$p";
           }
       }
       if($EndPage<$NumPages && $EndPage>0)
       {
         $m_var_list_update["p"]=$this->Page+$PagesToList;
         $next_url = $page."?env=".BuildEnv();
         $o .= "<A HREF=\"$next_url\"> &gt;&gt;</A>";
       }
       unset($m_var_list_update,$var_list_update["t"] );
       return $o;
   }
 	
   	function GetAdminPageLinkList($url)
   	{
       	global $objConfig, $m_var_list_update, $var_list_update, $var_list;
 		
 		$PerPage = $this->GetPerPage();
       	$NumPages = ceil($this->GetNumPages($PerPage));
       	$o = "";
 
       	if($this->Page>1)
       	{
         	$m_var_list_update["p"]=$this->Page-1;
         	$prev_url = $url."?env=".BuildEnv();
         	unset($m_var_list_update["p"]);
          	$o .= "<A HREF=\"$prev_url\" class=\"NAV_URL\"><<</A>";
       	}
 
       	if($this->Page<$NumPages)
       	{
         	$m_var_list_update["p"]=$this->Page+1;
         	$next_url = $url."?env=".BuildEnv();
         	unset($m_var_list_update["p"]);
       	}
 
       	for($p=1;$p<=$NumPages;$p++)
       	{
           	if($p != $this->Page)
           	{
               	$m_var_list_update["p"]=$p;
               	$href = $url."?env=".BuildEnv();
               	unset($m_var_list_update["p"]);
               	$o .=  " <A HREF=\"$href\" class=\"NAV_URL\">$p</A> ";
           	}
           	else
               $o .= "<SPAN class=\"CURRENT_PAGE\">$p</SPAN>";
       	}
       	
       	if($this->Page < $NumPages)
          	$o .= "<A HREF=\"$next_url\" class=\"NAV_URL\">>></A>";
 
       	return $o;        
   	}
 
   function Search_Category($orderByClause)
   {
     global $objSession, $objConfig, $Errors;    
 
     $PerPage = $this->GetPerPage();
     $Start = ($this->Page-1) * $PerPage;
     $objResults = new clsSearchResults("Category","clsCategory");
     $this->Clear();
     $this->Categories = $objResults->LoadSearchResults($Start,$PerPage);
     
     return $this->Categories;
   }
 
 
   function GetSubCats($ParentCat)
   {   
       return $this->Query_Category("ParentId=".$ParentCat,"");
   }
 
   function AllSubCats($ParentCat)
   {
       $c =& $this->GetCategory($ParentCat);
       $sql = "SELECT * FROM ".$this->SourceTable." WHERE ParentPath LIKE '".$c->Get("ParentPath")."%'";
       $rs = $this->adodbConnection->Execute($sql);
       $subcats = array();
       while($rs && !$rs->EOF)
       {
       	  if($rs->fields["CategoryId"]!=$ParentCat)
       	  {
             $subcats[] = $rs->fields["CategoryId"];
       	  }
           $rs->MoveNext();
       }
 	  if($ParentCat>0)
 	  {
         if($c->Get("CachedDescendantCatsQty")!=count($subcats))
         {
           $c->Set("CachedDescendantCatsQty",count($subcats));
         }
 	  }
       return $subcats;
   }
 
   function cat_navbar($admin=0, $cat, $target_template, $separator = " > ", $LinkLeaf = FALSE,
   					  $root = 0,$RootTemplate="",$modcat=0, $ModTemplate="", $LinkRoot = FALSE)  					 
   {
     // draw category navigation bar (at top)
     global $Errors, $var_list_update, $var_list, $m_var_list_update, $m_var_list, $objConfig;
 
 	$selector = isset($_REQUEST['Selector']) ? '&Selector='.$_REQUEST['Selector'] : '';
 	$new = isset($_REQUEST['new']) ? '&new='.$_REQUEST['new'] : '';
 
     $nav = "";
     $m_var_list_update["p"]=1;   
     if(strlen($target_template)==0)
       $target_template = $var_list["t"];
    
    
     if($cat == 0)
     {
         $cat_name = language($objConfig->Get("Root_Name"));
         if ($LinkRoot)
         {
         	$var_list_update["t"] = strlen($RootTemplate)? $RootTemplate : $target_template;
         	$nav = "<a class=\"navbar\" href=\"".GetIndexURL(2)."?env=". BuildEnv().$selector.$new."\">$cat_name</a>";	}
         else
         	$nav = "<span class=\"NAV_CURRENT_ITEM\">$cat_name</span>";
     }
     else
     {
       $nav = array();
       $c =& $this->GetCategory($cat);
       $nav_unparsed = $c->Get("ParentPath");    
       if(strlen($nav_unparsed)==0)
       {  
         $c->UpdateCachedPath();
         $nav_unparsed = $c->Get("ParentPath");
       }
       //echo " Before $nav_unparsed ";
       if($root)
       {      
         $r =& $this->GetCategory($root);
         $rpath = $r->Get("ParentPath");
         $nav_unparsed = substr($nav_unparsed,strlen($rpath),-1);
         $cat_name = $r->Get("Name");
         $m_var_list_update["cat"] = $root;
         if($cat == $catid && !$LinkLeaf)
         {
           $nav[] = "<span class=\"NAV_CURRENT_ITEM\" >".$cat_name."</span>";         //href=\"browse.php?env=". BuildEnv() ."\"
         }
         else
         {          
           if ($admin == 1)       
           {
             $nav[] = "<a class=\"control_link\" href=\"".$_SERVER["PHP_SELF"]."?env=". BuildEnv().$selector.$new."\">".$cat_name."</a>";
           }
           else
           {
             if(strlen($RootTemplate))
             {
                 $var_list_update["t"] = $RootTemplate;
             }
             else
             {
               $var_list_update["t"] = $target_template;
             }
             $nav[] = "<a class=\"navbar\" href=\"".GetIndexURL(2)."?env=". BuildEnv().$selector.$new."\">".$cat_name."</a>";
           }
         }
       }
       else
       {      
         $nav_unparsed = substr($nav_unparsed,1,-1);
         $cat_name = language($objConfig->Get("Root_Name"));
         $m_var_list_update["cat"] = 0;
         if($cat == 0)
         {
           $nav[] = "<span class=\"NAV_CURRENT_ITEM\" >".$cat_name."</span>";         //href=\"browse.php?env=". BuildEnv() ."\"
         }
         else
         {          
           if ($admin == 1)       
           {
             $nav[] = "<a class=\"control_link\" href=\"".$_SERVER["PHP_SELF"]."?env=". BuildEnv().$selector.$new."\">".$cat_name."</a>";
           }
           else
           {
             if(strlen($RootTemplate))
             {
               $var_list_update["t"] = $RootTemplate;
             }
             else
               $var_list_update["t"] = $target_template;
             $nav[] = "<a class=\"navbar\" href=\"".GetIndexURL(2)."?env=". BuildEnv().$selector.$new."\">".$cat_name."</a>";
           }
         }
         
       }
       //echo " After $nav_unparsed <br>\n";
       if(strlen($target_template)==0)
         $target_template = $var_list["t"];    
         
       $cats = explode("|", $nav_unparsed);
       foreach($cats as $catid)
       {
           if($catid)
           {          
             $c =& $this->GetCategory($catid);
             if(is_object($c))
             {          
               $cat_name = $c->Get("Name");
           
               $m_var_list_update["cat"] = $catid;
               if($catid==$modcat && strlen($ModTemplate)>0)
               {
               	$t = $ModTemplate;
               }
               else 
               	$t = $target_template;
               if($cat == $catid && !$LinkLeaf)
               {
                 $nav[] = "<span class=\"NAV_CURRENT_ITEM\" >".$cat_name."</span>";
               }
               else
               {          
                 if ($admin == 1)       
                 {
                   $nav[] = "<a class=\"control_link\" href=\"".$_SERVER["PHP_SELF"]."?env=". BuildEnv().$selector.$new."\">".$cat_name."</a>";
                 }
                 else
                 {
                   $var_list_update["t"] = $t;
                   $nav[] = "<a class=\"navbar\" href=\"".GetIndexURL(2)."?env=". BuildEnv().$selector.$new."\">".$cat_name."</a>";
                   unset($var_list_update["t"]);
                 }
               }
              unset($m_var_list_update["cat"]); 
             }
           }          
       }
       $nav = implode($separator, $nav);
     }
     return $nav;
   }
 
   function &Add($ParentId, $Name, $Description, $CreatedOn, $EditorsPick, $Status, $Hot, $New, $Pop,
                 $Priority, $MetaKeywords,$MetaDesc)  
   {
       global $objSession;
 
       $UserId = $objSession->Get("UserId");
 
       $d = new clsCategory(NULL);
       $d->tablename = $this->SourceTable;
       if($d->UsingTempTable())
         $d->Set("CategoryId",-1);
       $d->idfield = "CategoryId";
       $d->Set(array("ParentId", "Name", "Description", "CreatedOn",  "EditorsPick", "Status", "HotItem", 
                     "NewItem","PopItem", "Priority", "MetaKeywords", "MetaDescription", "CreatedById"), 
               array($ParentId, $Name, $Description, $CreatedOn, $EditorsPick, $Status, $Hot, $New,
                     $Pop, $Priority, $MetaKeywords,$MetaDesc, $UserId));
 
       $d->Create();
       if($Status==1)
       {      
         $d->SendUserEventMail("CATEGORY.ADD",$objSession->Get("PortalUserId"));
         $d->SendAdminEventMail("CATEGORY.ADD");
       }
       else
       {
           $d->SendUserEventMail("CATEGORY.ADD.PENDING",$objSession->Get("PortalUserId"));
           $d->SendAdminEventMail("CATEGORY.ADD.PENDING");
       }
       $d->UpdateCachedPath();
       //RunUp($ParentId, "Increment_Count");
 
       return $d;
   }
 
   function &Edit_Category($CategoryId, $Name, $Description, $CreatedOn, $EditorsPick, $Status, $Hot, 
                          $NewItem, $Pop, $Priority, $MetaKeywords,$MetaDesc) 
   {
       $d =& $this->GetCategory($CategoryId);
       $d->Set(array("Name", "Description", "CreatedOn",  "EditorsPick", "Status", "HotItem",
                     "NewItem", "PopItem", "Priority", "MetaKeywords","MetaDescription"), 
               array($Name, $Description, $CreatedOn,  $EditorsPick, $Status, $Hot, $NewItem, 
                     $Pop, $Priority, $MetaKeywords,$MetaDesc));           
       $d->Update();
       $d->UpdateCachedPath();
       return $d;
 
   }
 
   function Move_Category($Id, $ParentTo)
   {
       global $objCatList;
       
       $d =& $this->GetCategory($Id);
       $oldparent = $d->Get("ParentId");      
       $ChildList = $d->GetSubCatIds();
       
       /*
       echo "Target Parent Id: $ParentTo <br>\n";
       echo "<PRE>";print_r($ChildList); echo "</PRE>";
       echo "Old Parent: $oldparent <br>\n";
       echo "ID: $Id <br>\n";
       */
       /* sanity checks */
       
       if(!in_array($ParentTo,$ChildList) && $oldparent != $ParentTo && $oldparent != $Id &&
       	 $Id != $ParentTo)
       {
           $d->Set("ParentId", $ParentTo);
           $d->Update();
           $d->UpdateCachedPath();
           RunUp($oldparent, "Decrement_Count");
           RunUp($ParentTo, "Increment_Count");
           RunDown($ParentTo, "UpdateCachedPath");
           return TRUE; 
       }
       else 
       {
 		   	global $Errors;
       		$Errors->AddAdminUserError("la_error_move_subcategory");
         	return FALSE;
       }      
       die();  
   }
 
   function Copy_CategoryTree($Id, $ParentTo)
   {
       global $PastedCatIds;
 
       $new = $this->Copy_Category($Id, $ParentTo);
       if($new)
       {
         $PastedCatIds[$Id] = $new;
         $sql = "SELECT CategoryId from ".GetTablePrefix()."Category where ParentId=$Id";
         $result = $this->adodbConnection->Execute($sql);
         if ($result && !$result->EOF)
         {
           while(!$result->EOF)
           {       
               $this->Copy_CategoryTree($result->fields["CategoryId"], $new);
               $result->MoveNext();
           }
         }
       }
       return $new;
   }
 
   function Copy_Category($Id, $ParentTo)
   {        
       global $objGroups;
 
       
       $src = $this->GetCategory($Id);
       $Children = $src->GetSubCatIds();
       if($Id==$ParentTo || in_array($ParentTo,$Children))
       {
       	/* sanity error here */
       	global $Errors;
       	$Errors->AddAdminUserError("la_error_copy_subcategory");      	
       	return 0;
       }      
       $dest = $src;
       $dest->Set("ParentId", $ParentTo);
       if ($src->get("ParentId") == $ParentTo)
       {
    		$OldName = $src->Get("Name");
     	if(substr($OldName,0,5)=="Copy ")
     	{
     		$parts = explode(" ",$OldName,4);
     		if($parts[2]=="of" && is_numeric($parts[1]))
     		{
     			$Name = $parts[3];
     		}
     		else
     		  if($parts[1]=="of")
     		  {
     		    $Name = $parts[2]." ".$parts[3];
     		  }
     		  else
     		    $Name = $OldName; 
     	}
     	else
     	  $Name = $OldName;      	
     	//echo "New Name: $Name<br>";
 		$dest->Set("Name", $Name);    	  
 		$Names = CategoryNameCount($ParentTo,$Name); 
 		//echo "Names Count: ".count($Names)."<br>";
     	if(count($Names)>0)
     	{    		
     		$NameCount = count($Names);
     		$found = FALSE;
     		$NewName = "Copy of $Name";
     		
     		if(!in_array($NewName,$Names))
     		{
     			//echo "Matched on $NewName in:<br>\n";
     			$found = TRUE;
     		}
     		else
     		{
     		  for($x=2;$x<$NameCount+2;$x++)
     		  {
 
     				$NewName = "Copy ".$x." of ".$Name;
     				if(!in_array($NewName,$Names))
     				{
     					$found = TRUE;
     					break;
     				}
     				
     			}
     		}    	
     		if(!$found)
     		{
     			$NameCount++;
     			$NewName = "Copy $NameCount of $Name";
     		} 
     		//echo "New Name: $NewName<br>";
             $dest->Set("Name",$NewName);      
     	}
     	
       }
       $dest->UnsetIdField();
       $dest->Set("CachedDescendantCatsQty",0);
       $dest->Set("ResourceId",NULL);
       $dest->Create();      
       $dest->UpdateCachedPath();     
       $p = new clsPermList();
       $p->Copy_Permissions($src->Get("CategoryId"),$dest->Get("CategoryId"));   
       $glist =  $objGroups->GetAllGroupList();
       $view = $p->GetGroupPermList($dest, "CATEGORY.VIEW", $glist);
       $dest->SetViewPerms("CATEGORY.VIEW",$view,$glist);
       RunUp($ParentTo, "Increment_Count");
       return $dest->Get("CategoryId");     
   }
 
   function Delete_Category($Id)
   {
       global $objSession;
 
       $d =& $this->GetCategory($Id);
       
       if(is_object($d))
       {      
         if($d->Get("CategoryId")==$Id)
         {    
           $d->SendUserEventMail("CATEGORY.DELETE",$objSession->Get("PortalUserId"));
           $d->SendAdminEventMail("CATEGORY.DELETE");
           $p =& $this->GetCategory($d->Get("ParentId"));        
           RunDown($d->Get("CategoryId"), "Delete");
           RunUp($p->Get("CategoryId"), "Decrement_Count");   
           RunUp($d->Get("CategoryId"),"ClearCacheData");
 
         }
       }
   }
   
   function PasteFromClipboard($TargetCat)
   {
         global $objSession;
 
         $clip = $objSession->GetVariable("ClipBoard");
         if(strlen($clip))
         {
             $ClipBoard = ParseClipboard($clip);
             $IsCopy = (substr($ClipBoard["command"],0,4)=="COPY") || ($ClipBoard["source"] == $TargetCat);
 
             $item_ids = explode(",",$ClipBoard["ids"]);
             for($i=0;$i<count($item_ids);$i++)
             {   
                 $ItemId = $item_ids[$i];
                 $item = $this->GetItem($item_ids[$i]);
                 if(!$IsCopy)
                 { 
                     $this->Move_Category($ItemId, $TargetCat);                    
                     $clip = str_replace("CUT","COPY",$clip);
                     $objSession->SetVariable("ClipBoard",$clip);
                 }
                 else
                 {              
                   $this->Copy_CategoryTree($ItemId,$TargetCat);
                 }
             }
         }
       }
 
 
   function NumChildren($ParentID)
   {   
    $cat_filter = "m_cat_filter";
    global $$cat_filter;
 
    $filter = $$cat_filter;
    $adodbConnection = &GetADODBConnection();
 
    $sql = "SELECT COUNT(Name) as children from ".$this->SourceTable." where ParentId=" . $ParentID . $filter;
    $result = $adodbConnection->Execute($sql);
     return $result->fields["children"];
   }
 
   function UpdateMissingCacheData()
   {
       $rs = $this->adodbConnection->Execute("SELECT * FROM ".$this->SourceTable." WHERE ParentPath IS NULL or ParentPath=''");
       while($rs && !$rs->EOF)
       {
           $c = new clsCategory(NULL);
           $data = $rs->fields;
           $c->SetFromArray($data);
           $c->UpdateCachedPath();
           $rs->MoveNext();
       }
 
       $rs = $this->adodbConnection->Execute("SELECT * FROM ".$this->SourceTable." WHERE CachedNavbar IS NULL or CachedNavBar=''");
       while($rs && !$rs->EOF)
       {
           $c = new clsCategory(NULL);
           $data = $rs->fields;
           $c->SetFromArray($data);
           $c->UpdateCachedPath();
           $rs->MoveNext();
       }      
   }
  
   function CopyFromEditTable($idfield)
   {
       global $objGroups, $objSession, $objPermList;
 		$GLOBALS['_CopyFromEditTable']=1;
       $objPermList = new clsPermList();
       $edit_table = $objSession->GetEditTable($this->SourceTable);
 
       $sql = "SELECT * FROM $edit_table";
       $rs = $this->adodbConnection->Execute($sql);
       
       while($rs && !$rs->EOF)
       {
           $data = $rs->fields;
           $c = new $this->classname;
           $c->SetFromArray($data);          
           $c->Dirty();          
           
           if($c->Get("CategoryId")>0)
           {          
             $c->Update();
           }
           else
           {
           	  $c->UnsetIdField();
               $c->Create();
               $sql = "UPDATE ".GetTablePrefix()."Permissions SET CatId=".$c->Get("CategoryId")." WHERE CatId=-1";
               $this->adodbConnection->Execute($sql);
           }
           $c->UpdateCachedPath();                     
           $c->UpdateACL();
           $c->SendUserEventMail("CATEGORY.MODIFY",$objSession->Get("PortalUserId"));
           $c->SendAdminEventMail("CATEGORY.MODIFY");
           $c->Related = new clsRelationshipList();
           if(is_object($c->Related))
           {            
             $r = $c->Related;
             $r->CopyFromEditTable($c->Get("ResourceId"));
           }
           
           //RunDown($c->Get("CategoryId"),"UpdateCachedPath");
           //RunDown($c->Get("CategoryId"),"UpdateACL");
           unset($c);
           unset($r);
           $rs->MoveNext();
       }
       @$this->adodbConnection->Execute("DROP TABLE IF EXISTS $edit_table");
 		unset($GLOBALS['_CopyFromEditTable']);
       
       //$this->UpdateMissingCacheData();
   }   
   
   function PurgeEditTable($idfield)
   {
   	 parent::PurgeEditTable($idfield);
   	 $sql = "DELETE FROM ".GetTablePrefix()."Permissions WHERE CatId=-1";
   	 $this->adodbConnection->Execute($sql);
   }
 
   function GetExclusiveType($CatId)
   {
       global $objItemTypes, $objConfig;
 
       $itemtype = NULL;
       $c =& $this->GetItem($CatId);
       $path = $c->Get("ParentPath");
       foreach($objItemTypes->Items as $Type)
       {
           $RootVar = $Type->Get("ItemName")."_Root";
           $RootId = $objConfig->Get($RootVar);
           if((int)$RootId)
           {
               $rcat = $this->GetItem($RootId);
               $rpath = $rcat->Get("ParentPath");
               $p = substr($path,0,strlen($rpath));
               //echo $rpath." vs. .$p [$path]<br>\n";
               if($rpath==$p)
               {              
                   $itemtype = $Type;
                   break;
               }
           }      
       }
       return $itemtype;
   }
 }
 
 function RunUp($Id, $function, $Param=NULL)
 {     
     global $objCatList;
 
    $d =  $objCatList->GetCategory($Id);
    $ParentId = $d->Get("ParentId");
    if ($ParentId == 0)
     {
         if($Param == NULL)
         {        
         	$d->$function();
         }
         else
         {            
             $d->$function($Param);
         }
     }
    else
    {
       	RunUp($ParentId, $function, $Param);
         if($Param == NULL)
         {        
         $d->$function();
         }
         else
         {               
             $d->$function($Param);
         }
 
    }
    
 }
 
 function RunDown($Id, $function, $Param=NULL)
 {
     global $objCatList;
 
    $adodbConnection = &GetADODBConnection(); 
    $sql = "select CategoryId from ".GetTablePrefix()."Category where ParentId='$Id'";
    $rs = $adodbConnection->Execute($sql);
   
    while($rs && !$rs->EOF) 
    {  
       RunDown($rs->fields["CategoryId"], $function, $Param);           
       $rs->MoveNext();
    }
    $d = $objCatList->GetCategory($Id);
     if($Param == NULL)
     {        
       $d->$function();
     }
     else
         $d->$function($Param);
 }
 ?>
\ No newline at end of file

Property changes on: trunk/kernel/include/category.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.22
\ No newline at end of property
+1.23
\ No newline at end of property
Index: trunk/kernel/include/itemdb.php
===================================================================
--- trunk/kernel/include/itemdb.php	(revision 1021)
+++ trunk/kernel/include/itemdb.php	(revision 1022)
@@ -1,638 +1,638 @@
 <?php
 
 define('FT_OPTION', 1); // option formatter
 
 class clsItemDB 
 { 
   var $Formatters = Array(); //  by Alex
   var $m_dirtyFieldsMap = array();
   var $Data = array();
   var $adodbConnection;
   var $tablename;
   var $BasePermission;
   var $id_field;
   var $NoResourceId;
   var $debuglevel;
 
   var $SelectSQL = 'SELECT * FROM %s WHERE %s';
   
   function clsItemDB()
   {
       $this->adodbConnection = &GetADODBConnection();
       $this->tablename="";
       $this->NoResourceId=0;  
       $this->debuglevel=0;
   }
   
   // ============================================================================================
   function GetFormatter($field)
   {
   	return $this->HasFormatter($field) ? $this->Formatters[$field] : false;
   }
   
   function SetFormatter($field, $type, $params)
   {
   	// by Alex
   	// all params after 2nd are formmater type specific
   	$this->Formatters[$field]['type'] = $type;
   	switch($type)
   	{
   		case FT_OPTION:
   			$this->Formatters[$field]['options'] = $params;
   			break;	
   	}
   }
   /*	
   function FormatFields()
   {
 	// format item in list data before printing
 	
 	foreach($this->Formatters as $field => $formatter)
 		$this->Data[$field] = $this->FormatField($field);
   }
   */
   function FormatField($field)
   {
   	// formats single field if it has formatter
   	if( $this->HasFormatter($field) )
   	{
   		$fmt = $this->Formatters[$field];
   		switch($fmt['type'])
 		{
 			case FT_OPTION:
 				return $fmt['options'][ $this->Data[$field] ];
 				break;	
 		}
   	}
   	else
   		return $this->Get($field);
   }
   
   function HasFormatter($field)
   {
   	// checks if formatter is set for field
   	return isset($this->Formatters[$field]) ? 1 : 0;
   }
   // ============================================================================================
   
   function UnsetIdField()
   {
     $f = $this->IdField();
     unset($this->Data[$f]);
     unset($this->m_dirtyFieldsMap[$f]);
   }
 
   function UnsetField($field)
   {
       unset($this->Data[$field]);
       unset($this->m_dirtyFieldsMap[$field]);
   }
 
   function IdField()
   {
       if(!strlen($this->id_field))
       {      
         return $this->tablename."Id";
       }
       else
           return $this->id_field;
   }
 
   function UniqueId()
   {
       return $this->Get($this->IdField());
   }
 
   function SetUniqueId($value)
   {
       $var = $this->IdField();	  
       $this->Set($var, $value);
   }
 
   function SetModified($UserId=NULL,$modificationDate=null)
   {
       global $objSession;
       
       $keys = array_keys($this->Data);
       if(in_array("Modified",$keys))
       {
           $this->Set("Modified", isset($modificationDate) ? $modificationDate : adodb_date("U") );
       }
       if(in_array("ModifiedById",$keys))
       {
           if(!$UserId)
               $UserId = $objSession->Get("PortalUserId");
           $this->Set("ModifiedById",$UserId);
       }
   }
 
   function PrintVars()
   {
       echo '<pre>'.print_r($this->Data, true).'</pre>';
   }
   
 // =================================================================
   function GetFormatted($name)
   {	
       // get formatted field value
       return $this->FormatField($name);
   }
 
   function Get($name)
   {	
       // get un-formatted field value
       //if( !isset($this->Data[$name]) ) print_pre( debug_backtrace() );
       return $this->HasField($name) ? $this->Data[$name] : '';
   }
 // =================================================================
 
 	function HasField($name)
 	{
 		// checks if field exists in item
 		return isset($this->Data[$name]) ? 1 : 0;	
 	}
 	
 	/**
 	 * Set's value(-s) of field(-s) specified.
 	 * Modifies HasChanges flag automatically.
 	 *
 	 * @param string/array $name
 	 * @param string/array $value
 	 * @access public
 	 */
 	function Set($name, $value)
 	{
 		//echo "Setting Field <b>$name</b>: = [$value]<br>";
 		if( is_array($name) )
 		{
 			for ($i=0; $i < sizeof($name); $i++)
 			{
 				$this->_Set($name[$i],$value[$i]);
 			}
 		}
 		else
 		{
 			$this->_Set($name,$value);
 		}
 	}
 	
 	
 	/**
 	 * Set's value(-s) of field(-s) specified.
 	 * Modifies HasChanges flag automatically.
 	 *
 	 * @param string $name
 	 * @param string $value
 	 * @access private
 	 */
 	function _Set($name,$value)
 	{
 		$var = 'm_'.$name;
 		if( !$this->HasField($name) || $this->Data[$name] != $value )
 		{
 			if( !(isset($_GET['new']) && $_GET['new']) ) {
 				$this->DetectChanges($name, $value);
 			}
 			$this->Data[$name] = $value;
 			$this->m_dirtyFieldsMap[$name] = $value;
 		}
 	}
 
   function Dirty($list=NULL)
   {
       if($list==NULL)
       {
         foreach($this->Data as $field => $value)
         {
         	$this->m_dirtyFieldsMap[$field] = $value;
         }
       }
       else
       {      
         foreach($list as $field) 
         {	
        		$this->m_dirtyFieldsMap[$field] = $this->Data[$field];
         }
       }
   }
 
   function Clean($list=NULL)
   {
       if($list == NULL)
       {
           unset($this->m_dirtyFieldsMap);
           $this->m_dirtyFieldsMap=array();
       }
       else
       {      
         foreach($list as $value) 
         {	
           $varname = "m_" . $value;
           unset($this->m_dirtyFieldsMap[$value]);
         }
       }
   }
 
   function SetDebugLevel($value)
   {
       $this->debuglevel = $value;
   }
 
   function SetFromArray($data, $dirty = false)
   { 
       if(is_array($data))
       {      
         $this->Data = $data;
         if($dirty) $this->m_dirtyFieldsMap = $data;
       }
   }
 
   function GetData()
   {
     return $this->Data;
   }
 
   function SetData($data, $dirty = false)
   {
       $this->SetFromArray($data, $dirty);
   }
 
   function Delete()
   { 
       global $Errors;
 
       if($this->Get($this->IdField())==0)
       {
           $Errors->AddError("error.AppError",NULL,'Internal error: Delete requires set id',"",get_class($this),"Delete");
           return false;
       }
 
       $sql = sprintf('DELETE FROM %s WHERE %s = %s', $this->tablename, $this->IdField(),
                       $this->UniqueId());
       if($this->debuglevel>0)
         echo $sql."<br>";
       if ($this->adodbConnection->Execute($sql) === false)
       {
           $Errors->AddError("error.DatabaseError",NULL,$this->adodbConnection->ErrorMsg(),"",get_class($this),"Delete");
           return false;
       }
       return true;
   }
 
   function Update($UpdatedBy=NULL,$modificationDate = null)
   {
       global $Errors, $objSession;
 		
       if(count($this->m_dirtyFieldsMap) == 0)
           return true;
 
       $this->SetModified($UpdatedBy,$modificationDate);
       $sql = "UPDATE ".$this->tablename ." SET ";
       $first  = 1;
 
       foreach ($this->m_dirtyFieldsMap as $key => $value)
       {
           if(!is_numeric($key) && $key != $this->IdField() && $key!='ResourceId')
           {          
             if($first)
             {
 				if(isset($GLOBALS['_CopyFromEditTable']))
     	          $sql = sprintf("%s %s=%s",$sql,$key,$this->adodbConnection->qstr(($value)));
     	        else
     	          $sql = sprintf("%s %s=%s",$sql,$key,$this->adodbConnection->qstr(stripslashes($value)));
               $first = 0;
             }
             else
             {
 				if(isset($GLOBALS['_CopyFromEditTable']))
 	              $sql = sprintf("%s, %s=%s",$sql,$key,$this->adodbConnection->qstr(($value)));
 	            else
 	              $sql = sprintf("%s, %s=%s",$sql,$key,$this->adodbConnection->qstr(stripslashes($value)));
             }
           }           	
       }
 
 		$sql = sprintf("%s WHERE %s = '%s'",$sql, $this->IdField(), $this->UniqueId());
 
      if($this->debuglevel>0)
           echo $sql."<br>";
       if ($this->adodbConnection->Execute($sql) === false)
       {
           $Errors->AddError("error.DatabaseError",NULL,$this->adodbConnection->ErrorMsg(),"",get_class($this),"Update");
           return false;
       }
       
   	  if ($objSession->GetVariable("HasChanges") == 2)    {
   	  	$objSession->SetVariable("HasChanges", 1);
   	  }      
       
 /*      if ($this->adodbConnection->Affected_Rows() > 0) {
       	$objSession->SetVariable("HasChanges", 1);
   	  }*/
       
       return true;
   }
 	
 	function ReplaceID($new_id)
 	{
 		// replace item's id, because Update method 
 		// is too dummy to do this autommatically
 		// USED in temporary table editing stuff
 		$db =& $this->adodbConnection;
 		$sql = "UPDATE %1\$s SET `%2\$s` = %3\$s WHERE `%2\$s` = %4\$s"; 
 		$sql = sprintf($sql, $this->tablename, $this->IdField(), $new_id, (int)$this->UniqueId() );
 		if($this->debuglevel > 0) echo $sql.'<br>';
 		$db->Execute($sql);
 	}
 	
   function CreateSQL()
   {
   	 global $Errors;
   	 
      $sql = "INSERT IGNORE INTO ".$this->tablename." (";
      $first  = 1;
      foreach ($this->Data as $key => $value)
      {
           if($first)
           {
               $sql = sprintf("%s %s",$sql,$key);
               $first = 0;
           }
           else
           {
               $sql = sprintf("%s, %s",$sql,$key);
           }
      }
      $sql = sprintf('%s ) VALUES (',$sql);
      $first = 1;
      foreach ($this->Data as $key => $value)
      {
      	if( is_array($value) )
      	{
      		global $debugger;
      		$debugger->dumpVars($value);
      		$debugger->appendTrace();
      		trigger_error('Value of array type not allowed in method <b>CreateSQL</b> of <b>clsItemDB</b> class', E_USER_ERROR);
      	}
      	if($first)
      	{
 			if(isset($GLOBALS['_CopyFromEditTable']))
 	     		$sql = sprintf("%s %s",$sql,$this->adodbConnection->qstr(($value)));
 	     	else
 	     		$sql = sprintf("%s %s",$sql,$this->adodbConnection->qstr(stripslashes($value)));
      		$first = 0;
      	}
      	else
      	{
 			if(isset($GLOBALS['_CopyFromEditTable']))
 	     		$sql = sprintf("%s, %s",$sql,$this->adodbConnection->qstr(($value)));
 	     	else
 	     		$sql = sprintf("%s, %s",$sql,$this->adodbConnection->qstr(stripslashes($value)));
      	}
      }
      $sql = sprintf('%s)',$sql);
      
   	return $sql;
   }
   
   /**
    * Set's HasChanges flag based on new field
    * with $name with value $value.
    *
    * @param string $name
    * @param string $value
    * @access private
    */
   function DetectChanges($name, $value)
   {  	
   	global $objSession;
   	
   	//echo "<b>class: ".get_class($this)."</b><br>";
 	if ($this->Data[$name] != $value && $value != '') {		
 		//echo "$name Modified tt ".$this->Data[$name]." tt $value<br>";
 		if ($objSession->GetVariable("HasChanges") != 1) {
 			$objSession->SetVariable("HasChanges", 2);		
 		}
 	}
   }
   
   function Create()
   {
      global $Errors, $objSession;
      
 	if($this->debuglevel) echo "Creating Item: ".get_class($this)."<br>";
      if($this->NoResourceId!=1 && (int)$this->Get("ResourceId")==0)
      {
         $this->Set("ResourceId", GetNextResourceId());
      }
 	$sql = $this->CreateSql();
      
      if($this->debuglevel>0)
         echo $sql."<br>\n";
 
      if ($this->adodbConnection->Execute($sql) === false)
       {  
           $Errors->AddError("error.DatabaseError",NULL,$this->adodbConnection->ErrorMsg(),"",get_class($this),"Create");
           return false;
       }
 
       $this->SetUniqueId($this->adodbConnection->Insert_ID());
       
   	  if ($objSession->GetVariable("HasChanges") == 2)    {
   	  	$objSession->SetVariable("HasChanges", 1);
   	  }         
       
       /*if ($this->adodbConnection->Affected_Rows() > 0) {
       	$objSession->SetVariable("HasChanges", 1);
   	  }  */ 
       
       return true;
   }
 
   function Increment($field, $calculate_hot = false)
   {	    
       global $Errors;
       
       if ($calculate_hot) {
       	$sql = "SELECT $field FROM ".$this->tablename." WHERE ".$this->IdField()." = ".$this->UniqueId();
       	$rs = $this->adodbConnection->Execute($sql);
       	
       	$sql = "SELECT MAX($field) AS max_value FROM ".$this->tablename." WHERE ROUND($field) = ".round($rs->fields[$field]);
       	$rs = $this->adodbConnection->Execute($sql);
       	//echo "MAX VALUE: ".$rs->fields['max_value']."<br>";
       	//echo "MAX SQL: $sql<br>";
 		$new_val = $rs->fields['max_value'] + 1;
 		
       	$sql = "SELECT count($field) AS count FROM ".$this->tablename." WHERE $field = $new_val";
       	$rsc = $this->adodbConnection->Execute($sql);		
       	//echo "New Value:$new_val<br>";
       	if ($rsc->fields['count'] > 0) {
       		$new_val = $new_val + 0.000001;
       	}
       	
       	$sql = "Update ".$this->tablename." set $field=$new_val where ".$this->IdField()."=" . $this->UniqueId();
       }
 	  else {
       	$sql = "Update ".$this->tablename." set $field=$field+1 where ".$this->IdField()."=" . $this->UniqueId();
 	  }
       if($this->debuglevel>0)
           echo $sql."<br>";
       $result = $this->adodbConnection->Execute($sql);
       if ($result === false)
       {
           $Errors->AddError("error.DatabaseError",NULL,$this->adodbConnection->ErrorMsg(),"",get_class($this),"Increment");
           return false;
       }
       
       if ($calculate_hot) {
       	$this->Set($field,$new_val);
       }
       else {
       	$this->Set($field, $this->Get($field) + 1);
       }
   }
 
   function Decrement($field)
   {	
       global $Errors;
 
-      $sql = "Update ".$this->tablename." set $field=$field-1 where ".$this->IdField()."=" . $this->UniqueId();
+      $sql = "Update ".$this->tablename." set $field=$field-1 where ".$this->IdField()."=" .(int)$this->UniqueId();
       if($this->debuglevel>0)
           echo $sql;
       $result = $this->adodbConnection->Execute($sql);
       if ($result === false)
       {
           $Errors->AddError("error.DatabaseError",NULL,$this->adodbConnection->ErrorMsg(),"",get_class($this),"Decrement");
           return false;
       }
       $this->Set($field,$this->Get($field)-1);
   }
   
   function GetFieldList($UseLoadedData=FALSE)
   {
   	if(count($this->Data) && $UseLoadedData==TRUE)
   	{
   		$res = array_keys($this->Data);
   	}
   	else
   	{
   		$res = $this->adodbConnection->MetaColumnNames($this->tablename);
   	}
   	return $res;
   }
   
   function UsingTempTable()
   {
   	global $objSession;
   	
   	$temp = $objSession->GetEditTable($this->tablename);
   	$p = GetTablePrefix()."ses";
   	$t = substr($temp,0,strlen($p));
   	$ThisTable = substr($this->tablename,0,strlen($p));  	
   	if($t==$ThisTable)
   	{
   		return TRUE;
   	}
   	else
   	  return FALSE;
   }
   
     function LoadFromDatabase($Id, $IdField = null) // custom IdField by Alex
     {
 		global $objSession,$Errors;
        
         if(!isset($Id))
         {
             $Errors->AddError("error.AppError",NULL,'Internal error: LoadFromDatabase id',"",get_class($this),"LoadFromDatabase");
             return false;
         }
        
        // --------- multiple ids allowed: begin -----------------
        $id_field = isset($IdField) ? $IdField : $this->IdField();
        if( !is_array($id_field) ) $id_field = Array($id_field);
        if( !is_array($Id) ) $Id = Array($Id);
        
        $i = 0; $id_count = count($id_field);
        $conditions = Array();
        while($i < $id_count)
        {
        		$conditions[] = "(`".$id_field[$i]."` = '".$Id[$i]."')";
        		$i++;
        }
        $sql = sprintf($this->SelectSQL, $this->tablename, implode(' AND ', $conditions) );
        // --------- multiple ids allowed: end --------------------
        if($this->debuglevel) echo "Load SQL: $sql<br>"; 
         $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;
 		if($this->debuglevel) print_pre($data);
 		if(is_array($data))
           $this->SetFromArray($data);
         $this->Clean();
         return TRUE;
     }
     
     function FieldExists($field)
     {
       $res = array_key_exists($field,$this->Data);
       return $res;	
     }
   
     function ValueExists($Field,$Value)
     {
     	$sql = "SELECT $Field FROM ".$this->tablename." WHERE $Field='$Value'";
     	$rs = $this->adodbConnection->Execute($sql);
     	if($rs && !$rs->EOF)
     	{
     		return TRUE;
     	}
     	else
     	  return FALSE;
     }
 
     function FieldMax($Field)
     {
     	$sql = "SELECT Max($Field) as m FROM ".$this->tablename;
     	$rs = $this->adodbConnection->Execute($sql);
     	if($rs && !$rs->EOF)
     	{
     		$ret = $rs->fields["m"];
     	}
     	else
     	  $ret = 0;
     }
     
     function FieldMin($Field)
     {
     	$sql = "SELECT Min($Field) as m FROM ".$this->tablename;
     	$rs = $this->adodbConnection->Execute($sql);
     	if($rs && !$rs->EOF)
     	{
     		$ret = $rs->fields["m"];
     	}
     	else
     	  $ret = 0;
     }
     
     function TableExists($table = null)
     {
     	// checks if table specified in item exists in db	
     	$db =& $this->adodbConnection;
     	$sql = "SHOW TABLES LIKE '%s'";
     	if($table == null) $table = $this->tablename;
     	$rs = $db->Execute( sprintf($sql, $table) );
     	
     	if( $rs->RecordCount() == 1 ) // table exists in normal case
     		return 1;
     	else // check if table exists in lowercase
     		$rs = $db->Execute( sprintf($sql, strtolower($table) ) );
     	
     	return ($rs->RecordCount() == 1) ? 1 : 0;
     }	
     	
 }
 ?>

Property changes on: trunk/kernel/include/itemdb.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.24
\ No newline at end of property
+1.25
\ No newline at end of property