<?php
define('THEME_ERROR_1', 'Theme folder not writable');
define('THEME_ERROR_2', 'Template File Not Found');

class clsThemeFile extends clsItem 
{
    var $Contents;
    var $Root;
    var $Errors = Array(); // global template error messages (not db related)
    
    function clsThemeFile($id=NULL)
    {
        $this->clsItem();
        $this->tablename = GetTablePrefix()."ThemeFiles";
        $this->id_field = "FileId";
        $this->NoResourceId=1;
        $this->Root = "";
        $this->Contents = '';
        if($id) $this->LoadFromDatabase($id);
    }

    function ThemeRoot()
    {
        if( !$this->Root )
        {
        	$t = new clsTheme( $this->Get("ThemeId") );
        	$this->Root = $t->Get("Name");
    	}
        return $this->Root;
    }
    
    function FullPath()
    {
        // need to rewrite (by Alex)
        global $objConfig, $pathchar,$pathtoroot;

        $path = $pathtoroot."themes".$pathchar.$this->ThemeRoot();
        if(strlen(trim($this->Get("FilePath"))))
            $path .= $pathchar.$this->Get("FilePath");
        $path .= $pathchar.$this->Get("FileName");
        //echo "Full Path is $path <br>\n";
        return str_replace('//','/',$path);
    }
    
    function Get($name)
    {
    	if($name == 'Contents')
    		return $this->Contents;
    	else
    		return parent::Get($name);
	}
	
	function Set($name, $value)
  	{		
		if( !is_array($name) )
		{
			$name = Array($name);
			$value = Array($value);
		}
		
		$i = 0; $field_count = count($name);
		while($i < $field_count)
		{
			if($name[$i] == 'Contents')
				$this->Contents = $value[$i];
			else
				parent::Set($name[$i], $value[$i]);
			$i++;	
		}
	}
	/*
    function LoadFromDatabase($Id)
    {
        global $Errors;
       
        if(!isset($Id))
        {
            $Errors->AddError("error.AppError",NULL,'Internal error: LoadFromDatabase id',"",get_class($this),"LoadFromDatabase");
            return false;
        }        
        $sql = sprintf("SELECT * FROM ".$this->tablename." WHERE ".$this->IdField()." = '%s'",$Id);
        $result = $this->adodbConnection->Execute($sql);
        if ($result === false)
        {
            $Errors->AddError("error.DatabaseError",NULL,$this->adodbConnection->ErrorMsg(),"",get_class($this),"LoadFromDatabase");
            return false;
        }

        $data = $result->fields;

        $this->SetFromArray($data);
        $this->Clean();
        return true;
    }
	*/
	
    function Delete()
    {
        $path = $this->FullPath();
        if($this->debuglevel) echo "Trying to delete file [$path]<br>";
        if( file_exists($path) ) @unlink($path);
        parent::Delete();
    }

    function LoadFileContents($want_return = true)
    {
        global $objConfig,$pathchar;
		
        $this->Contents = '';
        $path = $this->FullPath();

        if( file_exists($path) )
            $this->Contents = file_get_contents($path);
        else
        	$this->SetError(THEME_ERROR_2, 2); // template not found
        if($want_return) return $this->Contents;
    }
	
	function SetError($msg, $code, $field = 'global_error')
	{
		$this->Errors[$field]['msg'] = $msg;
		$this->Errors[$field]['code'] = $code;
	}
	
	function HasError()
	{
		return count($this->Errors) ? 1 : 0;	
	}
	
	function ErrorMsg()
	{
		return $this->Errors['global_error']['msg'];	
	}
	
    function SaveFileContents($filecontents, $new_file = false)
    {
        $path = $this->FullPath();
        if( is_array($filecontents) ) $filecontents = implode("\n",$filecontents);
        
        if( $this->IsWriteablePath($new_file) )
        {
            $fp = fopen($path,"w");
            if($fp)
            {
                fwrite($fp,$filecontents);
                fclose($fp);
                return true;
            }
        }
        return false;
    }
    
    function IsWriteablePath($new_file = false)
    {
    	$path = $this->FullPath();
        $path = str_replace('//','/',$path);
        $ret = $new_file ? is_writable(dirname($path)): is_writable($path);
        
        if(!$ret)
        {
        	$this->SetError(THEME_ERROR_1, 1);
        	return false;
        }
        return $ret;
    }
}

class clsThemeFileList extends clsItemCollection 
{
    var $Page;
    var $PerPageVar;
    var $ThemeId;

    function clsThemeFileList($theme_id=NULL)
    {
    	global $m_var_list;
        $this->clsItemCollection();
        $this->classname = "clsThemeFile";
        $this->Page=(int)$m_var_list["p"];
        $this->PerPageVar = "Perpage_ThemeFiles";
        $this->SourceTable = GetTablePrefix()."ThemeFiles";
        $this->AdminSearchFields = array("FileName","FilePath","Description");

         
        $this->ThemeId=$theme_id;
        //if($theme_id)
        //    $this->LoadFiles($theme_id);
    }

    function LoadFiles($id,$where="",$orderBy="",$limit="")
    {
        global $objConfig;

        $this->Clear();
        $this->ThemeId=$id;
        $sql = "SELECT * FROM ".$this->SourceTable. " WHERE ThemeId=$id ";       
        if(strlen(trim($where))) $sql .= ' AND '.$where." ";
        if(strlen(trim($orderBy))) $sql .= "ORDER BY $orderBy";
		if(strlen(trim($limit))) $sql .= $limit;
		
        if(strlen($this->PerPageVar))
        {        
          $sql .= GetLimitSQL($this->Page,$objConfig->Get($this->PerPageVar));
        }
        //echo $sql;
        return $this->Query_Item($sql);
    }
    
    function GetFileByName($path,$name,$LoadFromDB=TRUE)
    {
        $found = FALSE;
        $f = FALSE;
        //echo "Looking through ".$this->NumItems()." Files <br>\n";
        if($this->NumItems()>0)
        {
          foreach($this->Items as $f)
          {
              if(($f->Get("FilePath")== $path) && ($f->Get("FileName")==$name))
              {
                 $found = TRUE;
                 break;
              }
          }
        }
        
        if(!$found && $LoadFromDB)
        {
            $sql = "SELECT * FROM ".$this->SourceTable." WHERE ThemeId=".$this->ThemeId." AND FileName LIKE '$name' AND FilePath LIKE '$path'";
            $rs = $this->adodbConnection->Execute($sql);
            //echo $sql."<br>\n";
            if($rs && !$rs->EOF)
            {            
                $data = $rs->fields;
                $f =& $this->AddItemFromArray($data);
            }
            else
                $f = FALSE;
        }
        return $f;
    }

    function AddFile($Path,$Name,$ThemeId,$Type,$Description,$contents=NULL)
    {
        $f = new clsThemeFile();
        $f->Set(array("FilePath","FileName","ThemeId","FileType","Description"),
                array($Path,$Name,$ThemeId,$Type,$Description));
        $f->Create();
        if($contents!=NULL)
            $f->SaveFileContents($contents);
        //echo $f->Get("FilePath")."/".$f->Get("FileName")."<br>\n";
        return $f;
    }

    function EditFile($FileId,$Path,$Name,$ThemeId,$Type,$Description,$contents=NULL)
    {
        $f = $this->GetItem($FileId);
        $f->Set(array("FilePath","FileName","ThemeId","FileType","Description"),
                array($Path,$Name,$ThemeId,$Type,$Description));
        $f->Update();
        if($Contents!=NULL)
            $f->SaveFileContents($Contents);        

        return $f;
    }

    function DeleteFile($FileId)
    {
        $f = $this->GetItem($FileId);
        $f->Delete();
    }                       

    function DeleteAll()
    {
        $this->Clear();
        $this->LoadFiles($this->ThemeId);
        foreach($this->Items as $f)
            $f->Delete();
        $this->Clear();
    }

    function SetFileContents($FileId,$Contents)
    {
        $f = $this->GetItem($FileId);
        $f->SaveFileContents($Contents);
    }

    function GetFileContents($FileId)
    {
        $f = $this->GetItem($FileId);
        return $f->LoadFileContents();        
    }

	function FindMissingFiles($path, $where = null, $OrderBy = null, $limit = null)
	{
		global $pathtoroot;
		$this->Clear();
		$fullpath = $pathtoroot.'themes/'.$path;
		// get all templates from database
		$sql = 'SELECT FileId AS i,CONCAT(FilePath,"/",FileName) AS f FROM '.$this->SourceTable. ' WHERE ThemeId='.$this->ThemeId;
		$DBfiles=Array();
		if($rs = $this->adodbConnection->Execute($sql))
		{
			while(!$rs->EOF)
			{
				$DBfiles[$rs->fields['i']] = $fullpath.$rs->fields['f'];
				$rs->MoveNext();          
			}
			$rs->Free();
		}
		// get all templates file from disk
		$HDDfiles = filelist($fullpath, NULL, "tpl");

		$missingFiles=array_diff($HDDfiles,$DBfiles);
		$orphanFiles=array_diff($DBfiles,$HDDfiles);
		
		$sql = 'DELETE FROM '.$this->SourceTable.' WHERE FileId IN('.join(',',array_keys($orphanFiles)).')';
		$this->adodbConnection->Execute($sql);

		$l=strlen($fullpath);
		foreach($missingFiles as $file)
			$this->AddFile(substr(dirname($file),$l),basename($file),$this->ThemeId,0,'');
	}
}

RegisterPrefix("clsTheme","theme","kernel/include/theme.php");

class clsTheme extends clsParsedItem  
{
    var $Files;
    var $FileCache;
    var $IdCache;
    var $ParseCacheDate;
    var $ParseCacheTimeout;

    function clsTheme($Id = NULL)
    {
      $this->clsParsedItem($Id);
      $this->tablename = GetTablePrefix()."Theme";
      $this->id_field = "ThemeId";
      $this->NoResourceId=1;
      $this->TagPrefix="theme";

      $this->Files = new clsThemeFileList($Id);
      $this->FileCache = array();
      $this->IdCache = array();
      $this->ParseCacheDate=array();
      $this->ParseCacheTimeout = array();

      if($Id)
          $this->LoadFromDatabase($Id);
    }

    function ThemeDirectory()
    {
        global $objConfig, $pathchar, $pathtoroot;

        $path = $pathtoroot."themes/".strtolower($this->Get("Name"));
        return $path;
    }

    function UpdateFileCacheData($id,$CacheDate)
    {
        $sql = "UPDATE ".GetTablePrefix()."ThemeFiles SET CacheDate=$CacheDate WHERE FileId=$id";
        $this->adodbConnection->Execute($sql);
    }

    function LoadFileCache()
    {
        $sql = "SELECT * FROM ".GetTablePrefix()."ThemeFiles WHERE ThemeId=".$this->Get("ThemeId");
        $rs = $this->adodbConnection->Execute($sql);
        while($rs && ! $rs->EOF)
        {
            //$this->Files->AddItemFromArray($rs->fields,TRUE);
            $f = $rs->fields["FileName"];
            $t = $rs->fields["FilePath"];
            if(strlen($t))
              $t .= "/";
            $parts = pathinfo($f);
            $fname = substr($f,0,(strlen($parts["extension"])+1)*-1);
            // echo "Name: $fname<br>\n";
            $t .= $fname;
 
            $this->FileCache[$t] = $rs->fields["FileId"];
            $this->IdCache[$rs->fields["FileId"]] = $t;
            /*
            if($rs->fields["EnableCache"]) // no such field in this table (commented by Alex)
            {            
                $this->ParseCacheDate[$rs->fields["FileId"]] = $rs->fields["CacheDate"];
                $this->ParseCacheTimeout[$rs->fields["FileId"]] = $rs->fields["CacheTimeout"];
            }
            */
            if( defined('ADODB_EXTENSION') && constant('ADODB_EXTENSION') > 0 )
                adodb_movenext($rs);
            else
              $rs->MoveNext();          
        }
        //echo "<PRE>"; print_r($this->IdCache); echo "</PRE>";
    }

    function GetTemplateById($FileId)
    {
        if(count($this->FileCache)==0)
            $this->LoadFileCache();
        $f = $this->IdCache[$FileId];        

        return $f;
    }

    function GetTemplateId($t)
    {
        if( count($this->IdCache) == 0 ) $this->LoadFileCache();
        $f = isset( $this->FileCache[$t] ) ? $this->FileCache[$t] : '';
        return is_numeric($f) ? $f : $t;
    }

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

        $data = $result->fields;

        $this->SetFromArray($data);
        $this->Clean();
        $this->Files = new clsThemeFileList($Id);
        return true;
    }

    function GetFileList($where,$OrderBy)
    {
        global $objConfig, $pathchar;
       
        $this->Files->PerPageVar="";
        $this->Files->ThemeId = $this->Get("ThemeId");
        $this->Files->LoadFiles($this->Get("ThemeId"),$where,$OrderBy);
    }

    function VerifyTemplates($where = null,$OrderBy = null,$limit = null)
    {
        if(!is_object($this->Files))
			$this->Files = new clsThemeFileList($this->Get("ThemeId"));
        $this->Files->ThemeId = $this->Get("ThemeId");
        
        $this->Files->FindMissingFiles(strtolower($this->Get("Name")),$where,$OrderBy,$limit);
    }

    function EditTemplateContents($FileId,$Contents)
    {
        $this->Files->SetFileContents($FileId,$Contents);
    }

    function ReadTemplateContents($FileId)
    {
        return $this->Files->GetFileContents($FileId);
    }

    function CreateDirectory()
    {
    	$dir = $this->ThemeDirectory();
    	if(!is_dir($dir))
    	   	mkdir($dir);
    }
    
    function Delete()
    {
        $this->Files->DeleteAll();
        $dir = $this->ThemeDirectory();
        if(is_writable($dir))
            @rmdir($dir);
        parent::Delete();
    }

    function AdminIcon()
    {
        global $imagesURL;

        $file = $imagesURL."/itemicons/icon16_theme";
        if($this->Get("PrimaryTheme")==1)
        {
            $file .= "_primary.gif";
        }
        else
        {
            if($this->Get("Enabled")==0)
            {
                $file .= "_disabled";
            }
            $file .= ".gif";
        }
        return $file;
    }

    function ParseObject($element)
    {
        global $var_list_update, $objSession;

        $extra_attribs = ExtraAttributes($element->attributes);
        if(strtolower($element->name)==$this->TagPrefix)
        {          
            $field = strtolower($element->attributes["_field"]);          
            switch($field)
            {     
            case "id":
                $ret = $this->Get("ThemeId");
                break;
            case "name": // was "nane"
                $ret = $this->Get("Name");
            break;
            case "description":
                $ret = $this->Get("Description");
            break;
            case "adminicon":
                $ret = $this->AdminIcon();
            break;
            case "directory":
                $ret = $this->ThemeDirectory();
            break;
            case "select_url":
                $var_list_update["t"] = "index";
                $ret = GetIndexURL()."?env=".BuildEnv()."&Action=m_set_theme&ThemeId=".$this->Get("ThemeId");
            break;
            case "selected":
                $ret = "";
                if($this->Get("Name")==$objSession->Get("Theme"))
                    $ret = "SELECTED";
            break;
            default:
              $tag = $this->TagPrefix."_".$field;
              $ret = ""; $this->parsetag($tag);
              break;
            }
        }
        return $ret;
    }
}

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

    function clsThemeList($id=NULL)
    {
        $this->clsItemCollection();
        $this->classname="clsTheme";
        $this->SourceTable=GetTablePrefix()."Theme";
        $this->PerPageVar = "Perpage_Themes";
        $this->AdminSearchFields = array("Name","Description"); 
    }

    function LoadThemes($where="",$order="")
    {
        global $objConfig;

        $this->Clear();
        $sql = "SELECT * FROM ".$this->SourceTable."  ";
        if(strlen(trim($where)))
            $sql .= "WHERE ".$where." ";
        if(strlen(trim($orderBy)))
           $sql .= "ORDER BY $orderBy";
        
        $sql .= GetLimitSQL($this->Page,$objConfig->Get($this->PerPageVar));
        return $this->Query_Item($sql);
    }

    function AddTheme($Name,$Description,$Enabled,$Primary,$CacheTimeout=3600)
    {
        $t = new clsTheme();
        $t->tablename = $this->SourceTable;
        $t->Set(array("Name","Description","Enabled","PrimaryTheme","CacheTimeout"),
                array($Name,$Description,$Enabled,$Primary,$CacheTimeout));
        $t->Create();
        if($Primary==1)
        {
          $sql = "UPDATE ".$this->SourceTable." SET PrimaryTheme=0 WHERE ThemeId != ".$t->Get("ThemeId");
          $this->adodbConnection->Execute($sql);
        }        
        return $t;
    }

    function EditTheme($ThemeId,$Name,$Description,$Enabled,$Primary, $CacheTimeout)
    {
        $t = $this->GetItem($ThemeId);
        $t->Set(array("Name","Description","Enabled","PrimaryTheme","CacheTimeout"),
                array($Name, $Description, $Enabled, $Primary, $CacheTimeout));
        $t->Dirty();
        $t->Update();
        if($Primary==1)
        {
          $sql = "UPDATE ".$this->SourceTable." SET PrimaryTheme=0 WHERE ThemeId!=$ThemeId";
          $this->adodbConnection->Execute($sql);
        }
        return $t;
    }

    function DeleteTheme($ThemeId)
    {
        $t = $this->GetItem($ThemeId);
        $t->Delete();
    }                                 

    function SetPrimaryTheme($ThemeId)
    {
    	$theme = $this->GetItem($ThemeId);
    	$theme->Dirty();
    	if($theme->Get("Enabled")==1)
    	{
          $sql = "UPDATE ".$this->SourceTable." SET PrimaryTheme=0";
          $this->adodbConnection->Execute($sql);          
          $theme->Set("PrimaryTheme","1");
          $theme->Update();
    	}
    }

    function GetPrimaryTheme($field="ThemeId")
    {
        $sql = "SELECT * FROM ".$this->SourceTable." WHERE PrimaryTheme=1";       
        $rs = $this->adodbConnection->Execute($sql);
        if($rs && !$rs->EOF)
        {
            $l = $rs->fields[$field];
        }
        else
             $l = 0;
        return $l;
    }
    
    function CreateMissingThemes()
    {
        global $objConfig,$pathchar, $pathtoroot;

        $path = $pathtoroot."themes";

        $themes = array();
        if ($dir = @opendir($path))
        {          
          while (($file = readdir($dir)) !== false)
          {
              if($file !="." && $file !=".." && substr($file,0,1)!="_")
              {
                  if(is_dir($path."/".$file))
                  {
                      $file = strtolower($file);
                      $themes[$file]=0;
                  }
              }
          }
        }
        closedir($dir);
        $this->Clear();
        $this->Query_Item("SELECT * FROM ".$this->SourceTable);
        foreach($this->Items as $i)
        {
            $n = strtolower($i->Get("Name"));
            $themes[$n] = $i->Get("ThemeId");
        }
        $names = array_keys($themes);
        for($i=0;$i<count($names);$i++)
        {
          $name = $names[$i];
          $value = $themes[$name];
          if($value==0)
          {
                $t = $this->AddTheme($name,"New Theme",0,0);
                $themes[$name] = $t->Get("ThemeId");
          }
        }
        $where = implode(",",array_values($themes));
        $sql = "DELETE FROM ".$this->SourceTable." WHERE ThemeId NOT IN ($where)";
    }

    function CopyFromEditTable()
    {
        global $objSession;

        $edit_table = $objSession->GetEditTable($this->SourceTable);         
        $idlist = array();
        $sql = "SELECT * FROM $edit_table";
        $this->Clear();
        $rs = $this->adodbConnection->Execute($sql);
        while($rs && !$rs->EOF)
        {
            $data = $rs->fields;
            $c = $this->AddItemFromArray($data);

            $c->Dirty();
            if($data["ThemeId"]>0)
            {
                $c->Update();
            }
            else
            {
                $c->UnsetIdField();
                $c->Create();
                $c->CreateDirectory();
            }
			if($c->Get("PrimaryTheme"))
			{
				$this->SetPrimaryTheme($c->Get("ThemeId"));
			}
            $rs->MoveNext();
        }
        $this->adodbConnection->Execute($sql);
    }
    
    function PurgeEditTable()
    {
      global $objSession;

      $edit_table = $objSession->GetEditTable($this->SourceTable);
      $this->adodbConnection->Execute("DROP TABLE IF EXISTS $edit_table");
    }


}
?>