<?php
/**
 * @package linea21.core
 * @subpackage config_files
 * @author linea21 <info@linea21.com>
 * @version $id SVN
 * @access public
 * @license http://opensource.org/licenses/gpl-3.0.html
 * Configuration Management
 */

include_once('system/afiles/class.afiles.php');
include_once('../lib/lib_common.php');

class config_file {

  var $file_release = "define_release"; // fichier define_release
  var $file_db = "define_db";  // fichier define_db
  var $section_theme = "theme";  // section theme dans le fichier de configuration define_release
  var $config_path = '../config/';
  var $ini_path = '../config/';
  var $backup_config_path = '../tmp/backup/config/';
  var $authorized_release_sections; //sections authorisées dans le fichier release
  var $authorized_db_sections; //sections authorisées dans le fichier db
  var $authorized_theme_sections; //sections authorisées dans le fichier release
  var $config_extension = ".ini";
  var $php_extension = ".php";
  var $db_params;
  var $release_params;
  var $a_file;
  var $theme_settings='THEME_SETTINGS';
  var $theme_public='THEME_PUBLIC';
  var $theme_list_public='THEME_LIST_PUBLIC';
  var $theme_admin='THEME_ADMIN';
  var $theme_list_admin='THEME_LIST_ADMIN';
  protected $dispatcher = null;

  /**
   * config_file::__construct()
   * constructeur de classe
   * @access public
   * @return void
   */
  function __construct()
  {
    $this->a_file=new afiles;
    $this->authorized_release_sections=$GLOBALS['authorized_release_sections'];
    $this->authorized_db_sections=$GLOBALS['authorized_db_sections'];
    $this->authorized_theme_sections=$GLOBALS['authorized_theme_sections'];
    $this->dispatcher = $GLOBALS['dispatcher'];

    //charge les paramètres et les place en constante globale par define
    $this->loadReleaseParams();
    $this->loadDbParams();
  }

  /**
   * config_file::setParams()
   * modifie le tableau de cache interne avec le paramètre $content
   * @access public
   * @param string $file_name
   * @param array $content
   * @return void
   */
  function setParams($file_name,$content)
  {
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.set_params', array('filename' => $file_name, 'content' => $content)));
  	
    if($file_name == $this->file_release)$this->setReleaseParams($content);
    else if($file_name == $this->section_theme) $this->setThemeParams($content);
    else $this->setDbParams($content);
  }

  /**
   * config_file::loadReleaseParams()
   * charge les paramètres dans le tableau $release_params
   * @access public
   * @return void
   */
  function loadReleaseParams() {
  	
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.load_release_params'));
  	
    //charge les paramètres release dans un tableau $release_params
    $this->release_params=$this->parseConfig($this->file_release);
  }
  /**
   * config_file::loadDbParams()
   * charge les paramètres dans le tableau $db_params
   * @access public
   * @return void
   */
  function loadDbParams()
  {
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.load_db_params'));
  	
    //charge les paramètres dans un tableau $db_params
    $this->db_params=$this->parseConfig($this->file_db);
  }

  /**
   * config_file::setReleaseParams()
   * modifie le tableau $release_params avec les entrées du tableau $content
   * @access public
   * @return void
   * @param array $content
   */
  function setReleaseParams($content) {
  	
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.set_release_params'));
  	
    //charge les paramètres release dans un tableau $release_params
    $this->setPostParams($this->file_release,$content);
  }
  /**
   * config_file::setThemeParams()
   * modifie le tableau $release_params avec les entrées du tableau $content
   * @access public
   * @return void
   * @param array $content
   */
  function setThemeParams($content) {
  	
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.set_theme_params'));
  	
    //charge les paramètres release dans un tableau $release_params
    $this->setPostParams($this->section_theme,$content);
  }
  /**
   * config_file::setDbParams()
   * modifie le tableau $db_params avec les entrées du tableau $content
   * @access public
   * @return void
   * @param array $content
   */
  function setDbParams($content)
  {
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.set_db_params'));
  	
    //charge les paramètres dans un tableau $db_params
    $this->setPostParams($this->file_db,$content);
  }

  /**
   * config_file::writeReleaseParams()
   * écrit dans le fichier ini les paramètres du tableau $release_params
   * @access public
   * @return boolean
   */
  function writeReleaseParams() {
  	
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.write_release_params'));
  	
    //écrit les paramètres $release_params vers les fichiers release  ini et php
    if($this->backupParams($this->file_release)){
      //on écrit les params après avoir fait le backup
      if($this->a_file->mkini($this->release_params, $this->ini_path.$this->file_release.$this->config_extension))
      return true;
    }
    return false;
  }
  /**
   * config_file::writedBParams()
   * écrit dans le fichier ini les paramètres du tableau $db_params
   * @access public
   * @return boolean
   */
  function writeDbParams() {
  	
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.write_db_params'));
  	
    //écrit les paramètres $db_params vers les fichier db ini et php
    if($this->backupParams($this->file_db)){
      //on écrit les params après avoir fait le backup
      if($this->a_file->mkini($this->db_params, $this->ini_path.$this->file_db.$this->config_extension))
      return true;
    }
    return false;
    //TODO : alert les paramètres db n'ont pas pu être écrit.
  }

  /**
   * config_file::backupParams()
   * sauvegarde le fichier $file_name dans le répertoire de backup
   * @access public
   * @param string $file_name
   * @return boolean
   */
  function backupParams($file_name)
  {
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.backup_params', array('filename' => $file_name)));
  	
    SureCreateDir($this->backup_config_path.$this->config_extension, 0755);
    if ($this->a_file->cp($this->ini_path.$file_name.$this->config_extension,$this->backup_config_path)) return true;
    else return false;
  }

  /**
   * config_file::writePhpParams()
   * écrit le fichier php $file_name dans le répertoire de config
   * @access public
   * méthode dépréciée
   * @param string $file_name
   * @return boolean
   */
  function writePhpParams($file_name)
  {
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.write_php_params', array('filename' => $file_name)));
  	
    $content=$this->generateHeader($file_name);
    $content.=$this->generateBody($file_name);
    $content.=$this->generateFooter($file_name);
    //on écrit le contenu dans le fichier php
    if($this->a_file->mkfile($content,$this->config_path.$file_name.$this->php_extension)) return true;
    else return false;
  }
  /**
   * config_file::parseConfig()
   * retourne un tableau contenant les paramètres du fichier ini $file_name
   * @access public
   * @param string $file_name
   * @return array
   */
  function parseConfig($file_name, $whithsection = true)
  {
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.parse_config', array('filename' => $file_name)));
  	
    //parse_ini_file
    return $this->a_file->parse_ini($this->ini_path.$file_name.$this->config_extension, $whithsection);

  }
  /**
   * config_file::setPostParams()
   * insère les données différentes contenues dans $post_params dans le tableau correspondant au paramètre release ou db
   * @access public
   * @param string $file_name
   * @param array $post_params
   * @return void
   */
  function setPostParams($file_name,$post_params)
  {
  	
  	// Filter data event + return value
  	$r = $this->dispatcher->filter(new sfEvent($this, 'config.set_params', array('data' => $post_params)), $post_params);
  	$post_params = $r->getReturnValue();
  	
    //parse du tableau des paramètres
    // ajoute les paramètres de post
    if($file_name == $this->file_release || $file_name == $this->section_theme)
    {
      foreach ($post_params as $key => $value)
      {
        foreach ($this->release_params as $section => $existing_params)
        {
          foreach ($existing_params as $existing_param => $existing_value)
          {
            // la clé existe dans le tableau de cache release_params, on insère la valeur dans ce tableau
            if($existing_param == $key) $this->release_params[$section][$key]=$this->strip_ini_char($value);
          }
        }
      }
    }
    if($file_name == $this->file_db)
    {
      foreach ($post_params as $key => $value)
      {
        foreach ($this->db_params as $section => $existing_params)
        {
          foreach ($existing_params as $existing_param => $existing_value)
          {
            // la clé existe dans le tableau de cache db_params, on insère la valeur dans ce tableau
            if($existing_param == $key) $this->db_params[$section][$key]=$this->strip_ini_char($value);
          }
        }
      }
    }
  }
  /**
   * config_file::generateBody()
   * génère le contenu d'un fichier php de configuration à parti du $file_name
   * @access private
   * @param string $file_name
   * @return string
   */
  function generateBody($file_name)
  {
  	
    $out = '';

    if($file_name == $this->file_release) $content=$this->release_params;
    else $content=$this->db_params;

    if (!is_array($content))
    return false;

    foreach ($content as $key => $ini)
    {
      if (is_array($ini))
      {
        $out .= "\n\n//	".$key." /////// \n\n";

        foreach ($ini as $var => $value)
        {
          $out .= "define('".$var."',\t\t".$this->a_file->quote_ini($value).");\n";
        }
      }
      else
      {
        $out .= "define('".$key."',\t\t".$this->a_file->quote_ini($ini).");\n";
      }
    }
    
    // Filter data event + return value
    $r = $this->dispatcher->filter(new sfEvent($this, 'config.generate_body', array('filename' => $file_name, 'content' => $out)), $out);
    $out = $r->getReturnValue();

    return $out;
  }
  /**
   * config_file::generateHeader()
   * génère l'en tête d'un fichier php de configuration à parti du $file_name
   * @access private
   * @param string $file_name
   * @return string
   */
  function generateHeader($file_name)
  {
    $ret.="<?php \n";
    $ret.="// Linea 21 - PHP ".$file_name."\n";
    $ret.="// last_modify	: ".date("d-m-Y")."\n";
    $ret.="// GPL 3\n";
    $ret.="// http://opensource.org/licenses/gpl-3.0.html\n\n";
    $ret.="// BE CAREFULL THIS FILE IS SYSTEM FILE : use interface or ".$file_name.$this->config_extension." FOR CONFIGURATION";
    
    // Filter data event + return value
    $r = $this->dispatcher->filter(new sfEvent($this, 'config.generate_header', array('filename' => $file_name, 'content' => $ret)), $ret);
    $ret = $r->getReturnValue();
    
    return $ret;
  }
  /**
   * config_file::generateFooter()
   * génère le pied d'un fichier php de configuration à parti du $file_name
   * @access private
   * @param string $file_name
   * @return string
   */
  function generateFooter($file_name)
  {
    $s = "?> \n";
    
    // Filter data event + return value
    $r = $this->dispatcher->filter(new sfEvent($this, 'config.generate_footer', array('filename' => $file_name, 'content' => $s)), $s);
    $s = $r->getReturnValue();
    
    return $s;
  }

  /**
   * config_file::getReleaseParams()
   * génère le corps html d'un fichier de configuration pour affichage
   * @access public
   * @param string $updatable : champ texte modifiable
   * @param string $hidden : présence d'input type hidden
   * @return string
   */
  function getReleaseParams($updatable = false, $hidden = false) {

  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.get_release_params'));
  	
    return $this->getAllParams($this->file_release,$updatable, $hidden);
  }
  /**
   * config_file::getDbParams()
   * génère le corps html d'un fichier de configuration pour affichage
   * @access public
   * @param string $updatable : champ texte modifiable
   * @param string $hidden : présence d'input type hidden
   * @return string
   */
  function getDbParams($updatable = false, $hidden = false) {

  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.get_db_params'));
  	
    return $this->getAllParams($this->file_db,$updatable, $hidden);
  }
  /**
   * config_file::getAllParams()
   * génère le corps html d'un fichier de configuration pour affichage
   * @access private
   * @param string $updatable : champ texte modifiable
   * @param string $hidden : présence d'input type hidden
   * @param string $file_name
   * @return string
   */
  function getAllParams($file_name, $updatable = false, $hidden = false)
  {
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.get_all_params', array('filename' => $file_name)));
  	
    $out = '';
    $authorized_sections=array();

    include('../languages/' . U_L . '/lang_system.'. CHARSET .'.php');

    if($file_name == $this->file_release) {
      // le tableau de cache à utiliser est celui de realease
      $content=$this->release_params;
      //initialisation des sections à afficher/mdofier
      $authorized_sections=$this->authorized_release_sections;
    }
    else if($file_name == $this->section_theme)
    {
      // le tableau de cache à utiliser est celui de realease
      $content=$this->release_params;
      $authorized_sections=$this->authorized_theme_sections;
    }
    else
    {
      // le tableau de cache à utiliser est celui de db
      $content=$this->db_params;
      //initialisation des sections à afficher/mdofier
      $authorized_sections=$this->authorized_db_sections;
    }

    if (!is_array($content))
    return false;

    foreach ($content as $key => $ini)
    {

      if (is_array($ini))
      {
        if((in_array($key,$authorized_sections)))
        {

          if(isset($GLOBALS['lang']['system'][$key])) $label='<abbr title="'.$GLOBALS['lang']['system'][$key].'">'.$key.'</abbr>';
          else $label=$key;

          $out .= "\n<br style='clear:both' />\n";
          $out .= "\n<h2>".$label."</h2>\n";
          if(!$updatable) $out .="<dl>\n";
          //génération d'un bloc
          foreach ($ini as $var => $value)
          {
            $label='';
            if(isset($GLOBALS['lang']['system'][$var])) $label='<abbr title="'.$GLOBALS['lang']['system'][$var].'">'.$var.'</abbr>';
            else $label=$var;
            if(!$updatable)	{
              $out .="<dt>".$label;
              if($hidden) $out .= "<input name=\"".$var."\" id=\"".$var."\" value=\"".$value."\" type=\"hidden\"  />\n";
              if($var !='LANGUAGE') {
              	if($var=='DB_PASS') {
              	  $out .= "</dt><dd>".preg_replace("/[a-zA-Z0-9_]/", "•", $value)."</dd>\n";
              	} else {
                  $out .= "</dt><dd>".$value."</dd>\n";
              	}
              } else {
                $out .="</dt><dd>".culture::getInstance()->getCultureInfo($value, 'Language')."</dd>\n";
              }

            }
            else {
              if($var=='DB_PASS') {
              	$out .= "<p><label for=\"".$var."\">".$label."</label><input name=\"".$var."\" id=\"".$var."\" value=\"".$value."\" type=\"password\" class=\"textfield\" /></p>\n";
              }
              elseif($var !='LANGUAGE') {
                $out .= "<p><label for=\"".$var."\">".$label."</label><input name=\"".$var."\" id=\"".$var."\" value=\"".$value."\" type=\"text\" class=\"textfield\" /></p>\n";
              } else {
                $out .= "<p><label for=\"".$var."\">".$label."</label>".CultureSelectBox($var, $value)."</p>\n";
              }

            }
          }
          if(!$updatable) $out .="</dl>";
        }
      }
      else
      {
        if(!$updatable && $hidden) $out .= "<input name=\"".$key."\" id=\"".$key."\" value=\"".$ini."\" type=\"hidden\"  />\n";
        if(!$updatable)	$out .="<dt>".$key."</dt><dd>".$ini."</dd>\n";
        else $out .= "<p><label for=\"".$key."\">".$key."</label><input name=\"".$key."\" id=\"".$key."\" value=\"".$ini."\" type=\"text\" class=\"textfield\" /></p>\n";
      }
    }
    return $out;

  }
  /**
   * config_file::getThemeParams()
   * génère le corps html d'un fichier de configuration pour affichage
   * @access public
   * @param string $updatable : champ texte modifiable
   * @param string $hidden : présence d'input type hidden
   * @return string
   */
  function getThemeParams($updatable = false, $hidden = false) {

  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.get_theme_params'));
  	
    $out = '';
    $authorized_sections=array();

    include('../languages/' . U_L . '/lang_system.'. CHARSET .'.php');

    $content=$this->release_params;
    $authorized_sections=$this->authorized_theme_sections;

    $theme_public=$content[$this->theme_settings][$this->theme_public];
    $theme_admin=$content[$this->theme_settings][$this->theme_admin];

    if(isset($GLOBALS['lang']['system'][$this->theme_public])) $label='<abbr title="'.$GLOBALS['lang']['system'][$this->theme_public].'">'.$this->theme_public.'</abbr>';
    else $label=$this->theme_public;

    $out .= "\n<h2 style=\"clear:both;\">".$label."</h2>\n";
    $out .=$this->getOneThemeParams($updatable, $hidden, true,$theme_public,$this->theme_public,$this->theme_public, "public");

    $public_themes = getThemes('public');

    foreach ($public_themes as $key => $value)
    {
      if($value != $theme_public)
      $out .=$this->getOneThemeParams($updatable, $hidden, false,$value,$this->theme_list_public,$this->theme_public, "public");
    }

    if(isset($GLOBALS['lang']['system'][$this->theme_admin])) $label='<abbr title="'.$GLOBALS['lang']['system'][$this->theme_admin].'">'.$this->theme_admin.'</abbr>';
    else $label=$this->theme_admin;

    $out .= "\n<h2 style=\"clear:both;\">".$label."</h2>\n";

    $out .=$this->getOneThemeParams($updatable, $hidden, true,$theme_admin,$this->theme_admin,$this->theme_admin, "admin");

    $admin_themes = getThemes('admin');

    foreach ($admin_themes as $key => $value)
    {
      if($value != $theme_admin)
      $out .=$this->getOneThemeParams($updatable, $hidden, false,$value,$this->theme_list_admin,$this->theme_admin, "admin");
    }

    $out .= "\n<br style=\"clear:both;\" />\n";
    return $out;
  }


  /**
   * config_file::getOneThemeParams()
   * génère le corps html d'un fichier de configuration pour affichage
   * @access private
   * @param string $updatable
   * @param string $hidden
   * @param string $selected
   * @param string $value
   * @param string $field_name
   * @param string $radio_name
   * @return string
   */
  function getOneThemeParams($updatable = false, $hidden = false, $selected=false,$value,$field_name,$radio_name, $type) {

  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.get_one_theme_params'));
  	
    include('../languages/' . U_L . '/lang_system.'. CHARSET .'.php');

    $selected_pattern='';
    $checked_pattern='';
    $hidden_pattern='';
    $updatable_pattern='';
    $info = loadThemeInfo($type, $value);

    if ($selected)
    {
      $selected_pattern='_selected';
      $checked_pattern='checked="checked"';
    }
    if(!$updatable)$hidden_pattern='style="display:none;"';
    else $updatable_pattern="onclick=\"javascript:document.getElementById('".$type.$value."').checked='checked';\"";
    $out = '';
    $out .="<div class=\"config_theme" . $selected_pattern. "\">\n";
    $out .="<img src=\"../templates/" .$type. "/" .$value. "/preview.png\" style=\"width:250px;height:160px;\" alt=\"" .$value. "\" id=\"img_" .$type."-".$value. "\" ".$updatable_pattern."/>\n";

    $out .= '<input type="radio" name="' .$radio_name. '" id="' .$type.'-'.$value. '" value="' .$value. '" ' .$checked_pattern. ' ' .$hidden_pattern. ' />';
    $out .=	'<label for="' .$type.'-'.$value. '" class="autowidth">' . $value . '</label>';
    $out .= '<div class="themeinfo"><em>'._t('theme','name').'</em> : '.$info['name'].'<br />'.END_LINE;
    $out .= '<em>'._t('theme','author').'</em> : <a href="'.$info['homepage'].'">'.$info['author'].'</a><br />'.END_LINE;
    $out .= '<em>'._t('theme','version').'</em> : '.$info['version'].' | ';
    $out .= '<em>'._t('theme','compatibility').'</em> : '.$info['compatibility'].'<br />'.END_LINE;
    $out .= '<em>'._t('theme','description').'</em> : '.$info['description'].'<br />'.END_LINE;
    $out .= '</div>';
    $out .="</div>";
    return $out;
  }

  /**
   * config_file::strip_ini_char
   * suppression des caractères interdits dans un fichier ini
   * @access private
   * @param string $content
   * @return string
   */
  function strip_ini_char($content)
  {
    $ret='';
    // on remplace les caractères "[]; par '(),
    $ret=strtr($content, "\"[];", "'(),");
    if (get_magic_quotes_gpc()) $ret=stripslashes($ret);
    return $ret;
  }

  /**
   * config_file::initializeIniParams()
   * charge les paramètres des fichiers ini et les place en constante globale par define
   * @access public
   * @param void
   * @return void
   */
  function initializeIniParams()
  {

  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'config.init_ini'));
  	
    foreach ($this->release_params as $section => $existing_params)
    {
      foreach ($existing_params as $existing_param => $existing_value)
      {
        if(!defined($existing_param))
        {
          if(is_numeric($existing_value))
          {
            $existing_value=$this->convert_type($existing_value);
          }
          define($existing_param,$existing_value);
        }
      }
    }
    foreach ($this->db_params as $section => $existing_params)
    {
      foreach ($existing_params as $existing_param => $existing_value)
      {
        if(!defined($existing_param))
        {
          if(is_numeric($existing_value))
          {
            $existing_value=$this->convert_type($existing_value);
          }
          define($existing_param,$existing_value);
        }
      }
    }
  }

  /**
   * config_file::convert_type()
   * conversion d'une variable en entier ou en float selon son contenu
   * @param unknown_type $var
   * @return int or float
   */
  function convert_type( $var )
  {
    if( is_numeric( $var ) )
    {
      if( (float)$var != (int)$var )
      {
        return (float)$var;
      }
      else
      {
        return (int)$var;
      }
    }
    if( $var == "true" )    return true;
    if( $var == "false" )    return false;
    return $var;
  }
  /**
   * config_file::getPhpInfo()
   * Retourne un string contenant les informations php en html
   * @access public
   * @return string
   */
  function getPhpInfo() {
    ob_start();
    phpinfo();
    $info = ob_get_contents();
    ob_end_clean();
    return preg_replace('%^.*<body>(.*)</body>.*$%ms', '$1', $info);
  }
}

?>