<?php if (!defined('HTTP_SERVER')) die('You can not access this file directly!');
/**
  @licence GPL 2005-2010  The osCSS developers - osCSS Open Source E-commerce
  @portion code Copyright (c) 2002 osCommerce
  @package osCSS-2 <www http://www.oscss.org>
  @version 2.0.9
  @date  08/06/10, 22:46
  @author oscim <mail aurelien@oscim.fr> <www http://www.oscim.fr>
  @encode UTF-8
  Original:
    Made by Vlad Savitsky
        http://forums.oscommerce.com/index.php?showuser=20490
    Support:
        http://forums.oscommerce.com/index.php?showtopic=156667
    Released under GPL

  Prend en charge le package, traitement d'un package donné


  Ordre des methodes
    - get
    - zip
    - Database
    - Register (in db cip)

*/

class CIP {
  public static $debugg=true;
  /**
   Name of contrib folder
  */
  public static $cip_name;
  /**
     Name of the zip file with cip
  */
  var $zip_name;
  /**
    True if CIP should be read from ZIP-file
  */
  var $is_cip_in_zip;
  /**
    tags data
  */
  var $contrib_data;
  /**
    @param array level error (cf fin de fichier)

  */
//   public static $level_error=array(0=>array(),1=>array(),2=>array(),3=>array());
  /**
    @param bool  True if we have an error. error() sets this var
  */
//   public static $error=false;
  /**
    @param array  collector erreur
  */
//   public static $ArrayError=array();
  /**
    @param string
  */
  public static $ident=null;
  /**
    @param string
  */
  public static $version=null;
  /**
    @param boolean/null
  */
  private static $is_unpacked=null;
  /**
    @param boolean/null
  */
  private static $was_unpacked=null;
  /**
    @param object DB;
  */
  public static $DB;

  /**
    @param array tableau des sous class de tag ;
  */
  public static $ArrayTag;
  /**
    @param numeric DB;
  */
  public static $stamptime;
  /**
   Number of php tags in install.xml
  */
  var $count_php_tags=0;
  /**
  */
  var $cip_id;
  /**
    * '1' if CIP was installed, '0' if not.
    */
  var $cip_installed;


  /**
    Config
  */

  /**
  */
  const CONFIG_FILENAME = 'install.xml';
  /**
  */
  const PATH_BACKUP = DIR_FS_BACKUP;



  /**
    Class Constructor
  */
  function CIP($cip_name_arg='') {

    self::$stamptime=explode(' ', microtime());
    self::$DB=Database::getInstance();

    if (!$cip_name_arg or $cip_name_arg=="." or $cip_name_arg==".."){
      self::InProcess(__("no contribution name text"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      trigger_error(__CLASS__.sprintf('error %s', __FUNCTION__), E_USER_ERROR);
      return;
    }


    //! init des class tag
    self::include_tag_classes();
//     if(!defined('DIR_WS_BACKUP')){
//       define('DIR_WS_BACKUP',self::PATH_BACKUP) ;
//       define('DIR_FS_ADMIN_BACKUP',DIR_FS_ADMIN.self::PATH_BACKUP) ;
//     }

    if (substr($cip_name_arg, -4)=='.zip') {
      $this->is_cip_in_zip=true;
      $this->zip_name=$cip_name_arg;
      self::$cip_name=substr($cip_name_arg, 0, -4); //name without extention
    } else {
      $this->is_cip_in_zip=false;
      $this->zip_name=$cip_name_arg.'.zip';
      self::$cip_name=$cip_name_arg;
    }

    //! control db etat
    $result=self::$DB->query("select cip_id, cip_installed, cip_version from ".TABLE_CIP. " where cip_folder_name='".self::$cip_name."'; ");
    $installed=$result->fetchAssoc();

    //! Register CIP in database:
    if (!isset($installed['cip_id'])) $this->register();
    else{
      $this->cip_id=(string)$installed['cip_id'];
      $this->cip_installed=(int)$installed['cip_installed'];
    }

    define('CONTRIB_INSTALLER_NAME', 'CIP');
    define('CONTRIB_INSTALLER_VERSION', 'oscss 2 2.0.1');
  }

/** ================================================================== Get class variables: ================================================================== */

  public function get_cip_name() {return self::$cip_name;}
  public function get_zip_name() {return $this->zip_name;}
  public function is_cip_in_zip() {return $this->is_cip_in_zip;}
  public function get_contrib_data() {return $this->contrib_data;}
//   public function get_error() {return self::$error;}
  public function get_cip_id() {return $this->cip_id;}
  public function get_description_id(){return @$this->description_id;}
  public function get_data($id){return $this->contrib_data[$id];}
  //Post install notes:
  public function post_install_notes() {
    $c=(isset($this->contrib_data[$this->description_id]->data['post_install_notes']))?$this->contrib_data[$this->description_id]->data['post_install_notes'] : false;
    return ($c !=false && tep_not_null($c))? $c : false;
  }
  function get_count_php_tags() {return $this->count_php_tags;}

/** ================================================================== Archiver ZIP ================================================================== */

  /**
    True if we unpack. So we should delete
  */
  function was_unpacked() {
    if(self::$was_unpacked===null) return false;
    else return self::$was_unpacked;
  }
  /**
    True if  unpacked folder exists.
  */
  function is_unpacked() {
    return (self::$is_unpacked===null) ? is_dir(DIR_FS_CIP.self::$cip_name) :self::$is_unpacked ;
  }
  /**
    True if we have a zip for this CIP
  */
  function is_zipped() {return (is_file(DIR_FS_CIP.$this->zip_name));}
  /**
  */
  function full_path_to_zip() {return escapeshellcmd(DIR_FS_CIP.$this->zip_name);}

  /**
    Creat zip
    si zip exists > delete
  */
  function pack_cip($ext='zip') {
    if (!$this->is_unpacked() || $this->is_zipped())    return false;
    if(file_exists(DIR_FS_CIP.escapeshellcmd(self::$cip_name))) unlink(DIR_FS_CIP.escapeshellcmd(self::$cip_name));
    switch ($ext) {
      case 'gzip':
        if(CI_ARCHIVER_GZIP)    @ exec(CI_ARCHIVER_GZIP.' '.DIR_FS_CIP.escapeshellcmd(self::$cip_name), $output);
      break;
      case 'zip':
        $zipfile = new PclZip($this->full_path_to_zip());
        if($this->is_Windows())  define('OS_WINDOWS',1);
        else  define('OS_WINDOWS',0);

        $ret = $zipfile->add(DIR_FS_CIP.escapeshellcmd(self::$cip_name),"",DIR_FS_CIP);
        if($ret == 0) {
          $messageStack->add(__('Unrecoverable error'). ' "'.$zipfile->errorName(true).'"' );
          return false;
        }
      break;
    }
    return true;
  }

  /**
    upack zip
  */
  function unpack_cip($ext='zip') {
  error_reporting(E_ALL);

    global $messageStack;
    switch ($ext) {
      case 'zip':
        $zipfile = new PclZip( $this->full_path_to_zip() );

        if($this->is_Windows() ) { if(!defined('OS_WINDOWS'))define('OS_WINDOWS',1); }
        else { if(!defined('OS_WINDOWS'))define('OS_WINDOWS',0); }

        $ret = $zipfile->extract( PCLZIP_OPT_PATH, DIR_FS_CIP );
        if($ret == 0) {
          $messageStack->add(__('Unrecoverable error'). ' "'.$zipfile->errorName(true).'"' );
          return false;
        }
      break;
      case 'tbz':
      case 'tbz2':
      case 'bz2':
      case 'bz':
        if(CI_ARCHIVER_BZIP2)    @ exec(CI_ARCHIVER_BZIP2.' '.$this->full_path_to_zip().' -d > '. DIR_FS_CIP.self::$cip_name, $output);
      break;
      case 'gz':
        if(CI_ARCHIVER_GUNZIP)    @ exec(CI_ARCHIVER_GUNZIP.' '.$this->full_path_to_zip() .' -c > '. DIR_FS_CIP.self::$cip_name, $output);
      break;
    }
  }



///================================================================== //Database //==================================================================

  /**
    Write db for tags contrib
  */
  function write_to_database(){
    if (!$this->is_all_right()) self::InProcess(__("Erreur avant traitement de cette fonction "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'error');
    foreach ($this->contrib_data as $id=>$tag) {
      if (!$tag->write_to_database()) {
	self::InProcess(__("Erreur avant traitement de cette fonction "), 'tag_xml-['.$id.']'. $tag->tag_name.'->'.__FUNCTION__.'()', 'error');
	break;
      }
    }
  }

  /**
    Load db for tags contrib
  */
  function read_from_database(){
    if (!$this->is_all_right()) self::InProcess(__("Erreur avant traitement de cette fonction "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'error');
    foreach ($this->contrib_data as $id=>$tag) {
      if (!$tag->read_from_database()){
	self::InProcess(__("Erreur avant traitement de cette fonction "), 'tag_xml-['.$id.']'. $tag->tag_name.'->'.__FUNCTION__.'()', 'error');
	break;
      }
    }
  }

  /**
    delete db for tags contrib
  */
  function delete_tags_tables() {
    if (!$this->is_all_right()) self::InProcess(__("Erreur avant traitement de cette fonction "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'error');
    foreach ($this->contrib_data as $id=>$tag) {
      if (!$tag->delete_database_table()){
	self::InProcess(__("Erreur avant traitement de cette fonction "), 'tag_xml-['.$id.']'. $tag->tag_name.'->'.__FUNCTION__.'()', 'error');
	break;
      }
    }
    //If we will create just an objects for tag-classes we could not use this function with new tags...
  }

///================================================================== //Register //==================================================================

  /**
  */
  private function is_registered() {return (($this->cip_id) ? true : false);}

  /**
    Write in db this contrib
  */
  private function register() {

    $resobj=self::$DB->query($sql="insert into ".TABLE_CIP." (cip_id, cip_folder_name, cip_installed, cip_ident, cip_version) values ('', '".self::$cip_name."', '0', '".$this->getIdent()."','".$this->getVersion()."')");
    $this->cip_id=$resobj->__get('insertId');

    $this->cip_installed=0;
    self::InProcess(__("register add db table_cip "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'info');
  }

  /**
    Delete in db this contrib
  */
  public function unregister() {
    self::$DB->query("DELETE FROM ".TABLE_CIP." WHERE cip_folder_name='".self::$cip_name."' ");
  }

///================================================================== //Is installed? //==================================================================

  /**
  */
  private  function is_installed() {
    if (!isset($this->cip_installed)) {
      $result=tep_db_query("select cip_installed from ".TABLE_CIP." where cip_folder_name='".self::$cip_name."'");
      if ($result===false)  { trigger_error(__CLASS__.sprintf('error %s', __FUNCTION__.'::'.__LINE__), E_USER_ERROR); return $this->cip_installed=false; }
      $installed=tep_db_fetch_array($result);
      $this->cip_installed=$installed['cip_installed'];
    }
    return $this->cip_installed;
  }

  /**
  */
  private function unset_installed() {$this->set_installed('0');}

  /**
  */
  private function set_installed($status='1') {
    self::$DB->query("UPDATE ".TABLE_CIP." SET cip_installed='".$status."', cip_ident='".$this->getIdent()."', cip_version='".$this->getVersion()."' WHERE cip_folder_name='".self::$cip_name."'");
    self::InProcess(__("Install update db table_cip "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'normal');
  }


///================================================================== //XML //==================================================================
  /**
  */
  public function read_xml() {
    global $messageStack;
    if (is_array($this->contrib_data) && count($this->contrib_data)>0)
      self::InProcess(__("[data] contrib_data erreurs "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'error');

    if ($this->is_cip_in_zip && !$this->is_unpacked()) {
      //We unzip only if we get a zip-filename as a and do not have a unpacked version of CIP.
      $this->unpack_cip();
      self::$was_unpacked=true;
    }

    if ($this->is_unpacked()) {

      if(!$this->read_from_xml()) self::InProcess(__("havn't contained well formed XML-file: ").(($this->is_cip_in_zip) ? $this->get_zip_name() : $this->get_cip_name()), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');

      //! Erreur fatal before process, delete and exit
      if(!$this->check_bylevel(1)){
	self::InProcess(__("Erreur suite lecture XML file "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
	return false;

	$this->DeleteContribFull();
      }
      else
	return true;
    }
    elseif ($this->was_unpacked()) {
      $messageStack->add( 'Couldn\'t unpack <strong>'.$this->get_zip_name().'</strong> to read data about CIP. ', 'warning');
      $this->DeleteContribFull();
    }
    return false;
  }


  /**
  */
  private function read_from_xml() {
    $tagcnt = array();
    $this->does_have_install_xml();

    if(!$xmlDoc=new DomDocument()) return false;
// $xmlDoc->prevservWhiteSpace = false;
    if(! $xmlDoc->load(DIR_FS_CIP.self::$cip_name.'/'.self::CONFIG_FILENAME)) return false;
    if(!$root = $xmlDoc->documentElement) return false;
    if(!$this->parcourir($root)) return false;
    return true;
  }

  /**
    Check file xml
  */
  function does_have_install_xml() {
    $file=DIR_FS_CIP.self::$cip_name.'/'.self::CONFIG_FILENAME;
    if (file_exists($file)) return true;
    else {
      self::InProcess(__("error could not open xml").$file, __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return false;
    }
  }

  function compare_tag_priority($a, $b){ return $b->priority - $a->priority; }


  /**
    Parcours XML recursif
    @return bool
  */
  private function parcourir($noeud, $p = 0){
    global $tagcnt;
    if($p > 1) return true;

    if ($noeud->nodeType==8 || $noeud->nodeName=='#text' )  return true;

    if($noeud->nodeName !='contrib'){
      if(isset($tagcnt[$noeud->nodeName])) $tagcnt[$noeud->nodeName]++;
      else $tagcnt[$noeud->nodeName] = 0;

      if (strtolower($noeud->nodeName)=='php')$this->count_php_tags++;

      $clsname='Tc_'.strtolower($noeud->nodeName);

      if (class_exists($clsname)){
	$this->contrib_data[]=new $clsname($this, $tagcnt[$noeud->nodeName], $noeud);
	if(!$this->check_bylevel(1)){
	  self::InProcess(__("Erreur lecture XML tag ").$noeud->nodeName, __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
	}
      }
      else {
	self::InProcess('Tag'.$noeud->nodeName.__(' is not supported. Class ').$clsname.__(' does NOT exist.'), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'error');
    	trigger_error(__CLASS__.sprintf('error %s', __FUNCTION__), E_USER_ERROR);
    	return false;
      }

      if(strtoupper($noeud->nodeName) == 'DESCRIPTION')   $this->description_id=key($this->contrib_data);
    }
    //! debugg detail node
    if(self::$debugg) CipUtility::afficherInfos($noeud);

    if($noeud->nodeType == XML_ELEMENT_NODE && $noeud->hasChildNodes()){
      $p++;
      $enfants = $noeud->childNodes;
      foreach($enfants as $enfant){
	$this->parcourir($enfant, $p);
      }
    }
    return true;
  }




///================================================================== //Action //==================================================================

  /**
    Installateur Commande exe
  */
  function install() {

    fileUtility::_rmdir(DIR_FS_CIP.$this->get_cip_name());

    self::$was_unpacked=$this->read_xml();

    //! Check min
    if (!$this->is_all_right()){
      self::InProcess(__("not clean avant install process"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return false;
    }

    //! sort install tags by priority
    if(isset($this->contrib_data['compare_tag_priority'])) usort($this->contrib_data,'compare_tag_priority');

    //! Check full control
    if (!$this->full_check('install')){
      self::InProcess(__("Erreur durant traitement de cette fonction full_check()"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return false;
    }

    //! backup
    if (!$this->total_backup()){
      self::InProcess(__("Erreur durant traitement de cette fonction total_backup()"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return false;
    }

    //! We passed by all checks. So if an error appears
    foreach ($this->contrib_data as $id=>$tag)
      if ( $tag->do_install() ===false){
	self::InProcess(__("Erreur durant traitement de cette fonction   "),'tag_xml-['.$id.']'. $tag->tag_name.'->do_install()','block');
	break;
      }


    //! If we had a problems at runtime we should remove this CIP.
    if (!self::check_bylevel(1)) $this->remove(true);
    else {
      $this->DeleteContribFull(false, 'ok');

      //! up db etat install cip name
      $this->set_installed();
    }
  }

  /**
  */
  function remove($cleaning=false) {

    $result=$this->read_xml();

    if (!self::check_bylevel(0) /* !$this->is_all_right()*/ and !$cleaning){
      self::InProcess(__("Erreur avant traitement de cette fonction "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return false;
    }

    //! sort install tags by priority
//     usort($this->contrib_data,'compare_tag_priority');


    //! Check full control
    if (!$this->full_check('remove')){
      self::InProcess(__("Erreur durant traitement de cette fonction full_check()"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return;
    }

    if (!$this->total_restore()){
      self::InProcess(__("Erreur durant traitement de cette fonction total_restore()"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return;
    }

    //! check error level
    if(!self::check_bylevel(0)) return false;

    //! We passed by all checks. So if an error appears
    foreach ($this->contrib_data as $id=>$tag)
      if ( $tag->do_remove() ===false){
	self::InProcess(__("Erreur durant traitement de cette fonction   "),'tag_xml-['.$id.']'. $tag->tag_name.'->do_remove()','block');
	break;
      }

    $this->DeleteContribFull(false);

    //! up db etat install cip name
    $this->unset_installed();
  }



  /**
  */
  public function compute_dependencies(){
    $this->was_unpacked=$this->read_xml();
    if (!$this->is_all_right()){
      self::InProcess(__("Erreur durant traitement de cette fonction "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return;
    }
    // sort install tags by priority
    //usort($this->contrib_data,'compare_tag_priority');

    //! Check full control
    if (!$this->full_check('install')){
      self::InProcess(__("Erreur durant traitement de cette fonction full_check()"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return;
    }

    /**
      We passed by all checks. So if an error appears
    */
    foreach ($this->contrib_data as $id=>$tag)
      if($tag->isTagName('description') || $tag->isTagName('depend'))
	if (self::$error=(int)$tag->do_install())  break;

    //! If we had a problems at runtime we should remove this CIP.
    if (self::$error) $this->remove(true);
    else {
	if ($this->was_unpacked() && $this->is_unpacked()) {
	    fileUtility::_rmdir(DIR_FS_CIP.$this->get_cip_name());
	}
    }
  }

///================================================================== //Backup //==================================================================

  private function total_backup() {
    //! prepare backup folder:
    if (!is_dir(self::PATH_BACKUP.self::$cip_name)) {
      if (!@mkdir(self::PATH_BACKUP.self::$cip_name, 0777)){
	self::InProcess(__("write permissins needed text").self::PATH_BACKUP.self::$cip_name, __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'error');
	return false;
      }
      fileUtility::_chmod(self::PATH_BACKUP.self::$cip_name, 0777);
    }

    if ( _cst_bool('ALLOW_FILES_BACKUP')){
      //! Backup Files:
      if (!$this->backup() || !self::check_bylevel(1) /* !$this->is_all_right()*/){
	self::InProcess(__("Erreur apres traitement de cette fonction : backup()"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
	return false;
      }
      //! Backup DataBase:
      if (!CipUtility::sql_backup() || !self::check_bylevel(1)){
	self::InProcess(__("Erreur apres traitement de cette fonction : CipUtility::sql_backup()"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
	return false;
      }
    }

    return true;
  }

  private function total_restore() {
    if (false /*_cst_bool('ALLOW_FILES_BACKUP')*/){
      //! Files restore
      if (!$this->restore() ||  !self::check_bylevel(1)/* !$this->is_all_right()*/){
	self::InProcess(__("Erreur apres traitement de cette fonction restore()"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'error');
	return false;
      }
      //! SQL restore;
      if (!CipUtility::sql_restore() ||  !self::check_bylevel(1) /* !$this->is_all_right()*/){
	self::InProcess(__("Erreur apres traitement de cette fonction CipUtility::sql_restore()"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'error');
	return false;
      }
    }
    return true;
  }



  /**
    on backup
  */
  private function backup() {
    foreach ($this->contrib_data as $id=>$tag)
      if ( $tag->backup_file() ===false){
	self::InProcess(__("Erreur durant traitement de cette fonction   "),'tag_xml-['.$id.']'. $tag->tag_name.'->backup_file()','block');
	return false;
      }
    return true;
  }

  /**
    on remove
  */
  private function restore() {
    foreach ($this->contrib_data as $id=>$tag)
      if ( $tag->restore_file() ===false){
	self::InProcess(__("Erreur durant traitement de cette fonction   "),'tag_xml-['.$id.']'. $tag->tag_name.'->restore_file()','block');
      }
    if(file_exists(self::PATH_BACKUP.self::$cip_name) && !fileUtility::_rmdir(self::PATH_BACKUP.self::$cip_name)){
      self::InProcess(__("Suppression backup impossible   ").self::PATH_BACKUP.self::$cip_name, __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return false;
    }

    return true;
  }


//==================================================================
//conflicts_check
//==================================================================
  private function conflicts_check_for_install($msg='') {
    if (!$this->is_all_right()){
      self::InProcess(__("Erreur avant traitement de cette fonction "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return false;
    }
    foreach ($this->contrib_data as $id=>$tag)
      if ( $tag->conflicts_check_for_install() ===false){
	self::InProcess($msg.__("Erreur durant traitement de cette fonction "),'tag_xml-['.$id.']'. $tag->tag_name.'->'.__FUNCTION__,'block');
	break;
      }
    return true;
  }

  private function conflicts_check_for_remove($msg='') {
    if (!$this->is_all_right()){
      self::InProcess(__("Erreur avant traitement de cette fonction "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return false;
    }
    foreach ($this->contrib_data as $id=>$tag)
      if ( $tag->conflicts_check_for_remove() ===false){
	self::InProcess($msg.__("Erreur durant traitement de cette fonction "),'tag_xml-['.$id.']'. $tag->tag_name.'->'.__FUNCTION__,'block');
	break;
      }
    return true;
  }

//==================================================================
//permissions_check
//==================================================================
  private function permissions_check_for_install($msg='') {
    if (!$this->is_all_right()){
      self::InProcess(__("Erreur is_all_right() init cette fonction "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return false;
    }
    foreach ($this->contrib_data as $id=>$tag)
      if ( $tag->permissions_check_for_install() ===false){
	self::InProcess($msg.__("Erreur durant traitement de cette fonction "),'tag_xml-['.$id.']'. $tag->tag_name.'->'.__FUNCTION__,'block');
	break;
      }

    return true;
  }

  /**
    Control avant reomve cip
  */
  private function permissions_check_for_remove($msg='') {
    if (!$this->is_all_right()){
      self::InProcess(__("Erreur avant traitement de cette fonction "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return false;
    }
    foreach ($this->contrib_data as $id=>$tag)
      if ( $tag->permissions_check_for_remove() ===false){
	self::InProcess($msg.__("Erreur durant traitement de cette fonction "),'tag_xml-['.$id.']'. $tag->tag_name.'->'.__FUNCTION__,'block');
	break;
      }
    return true;
  }

//==================================================================
//Extra:
//==================================================================

  /**
    Checks if we have no error and have a data to work with:
  */
  public function is_all_right() {

    if(!$this->check_bylevel(1))  self::InProcess(__("Erreur self::\$erro à true "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'info');
    elseif(!is_array($this->contrib_data))  self::InProcess(__("Erreur \$this->contrib_data not array "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'info');
    elseif (is_array($this->contrib_data) && count($this->contrib_data)==0)  self::InProcess(__("Erreur \$this->contrib_data array vide "), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'info');
    else return true;

    return false;
//     return ((((int)self::$error) || (!is_array($this->contrib_data)) || (is_array($this->contrib_data) && count($this->contrib_data)==0)) ? false : true);
  }

//   function error($text='') {
//     global $messageStack;
//     if ($text) {
//         if ($this->was_unpacked() && $this->is_unpacked())     fileUtility::_rmdir(DIR_FS_CIP.$this->get_cip_name());
//        /* return self::$error=*/$messageStack->add($text, 'error');
//     }
//   }
  /**
    @return true if we have an error!...
  */
//   function check_error($stage='', $tag_name='', $id='', $text='') {
//
//     trigger_error(__CLASS__.__FUNCTION__.' funciton obsolete, ', E_USER_ERROR);
//
//     if (!is_null($text)) self::$ArrayError[]=$stage." at &#060;<i>".$tag_name."</i>&#062; #".$id.".<br /><strong>".$text."</strong>";
//     return self::$error=true;
//   }


//==================================================================

  /**
    Load tag class /tags/xxx.php
  */
  private static function include_tag_classes() {
    if (defined('TAG_LOADED'))  return null;
    $path=dirname(__FILE__);

    require_once($path .'/ci_tag.class.php');
    require_once($path.'/CipUtility.php');
    define('TAG_LOADED',1);
    $tag_files = glob($path .'/tags/*.php');

    foreach($tag_files as $file) require($file);
    return true;
  }

  function is_Windows() {return ((strtoupper($this->get_os()) == 'WIN') ? true : false);}

  function get_os() {
      if (substr(PHP_OS, 0, 3) == 'WIN')    return 'win';
      elseif (strpos($_SERVER['SERVER_SOFTWARE'], 'Unix'))     return 'unix';
  }

  /**
    @return tag ident
  */
  function getIdent(){
    if(self::$ident!=null) return self::$ident;
    if(isset($this->description_id) && isset( $this->contrib_data[$this->description_id]->data['ident']))
      return self::$ident=$this->contrib_data[$this->description_id]->data['ident'];

    self::InProcess(__("pas de tag de ident (obligatoire)"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
    return false;
  }

  /**
    @return tag version
  */
  function getVersion(){
    if(self::$version!=null) return self::$version;

    if(isset($this->description_id) && isset( $this->contrib_data[$this->description_id]->data['version']))
      return $this->contrib_data[$this->description_id]->data['version'];

    self::InProcess(__("pas de tag de version (obligatoire)"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
    return false;
  }


  /**
    Recup dependence contrib
  */
  function getDependedCips(){
    $cips = array();
    $query = "select * from ".TABLE_CIP_DEPEND." where cip_ident_req='".$this->getIdent()."' and cip_req_type=2";
    $rq = tep_db_query($query);
    while($rs=tep_db_fetch_array($rq)){
      $query = "select * from ".TABLE_CIP." where cip_ident='".$rs['cip_ident']."' and cip_installed=1";
      $rq1 = tep_db_query($query);
      if($rs1=tep_db_fetch_array($rq1)){
        if(file_exists(DIR_FS_CIP.$rs1['cip_folder_name'].".zip")) $cips[] = new CIP($rs1['cip_folder_name'].".zip");
        elseif(is_dir(DIR_FS_CIP.$rs1['cip_folder_name'])) $cips[] = new CIP($rs1['cip_folder_name']);
      }
    }
    return $cips;
  }



  /**
    Lance tous les controls
    @param string type (install|remove)
  */
  private function full_check($type='install'){

    $permissions_check= 'permissions_check_for_'.$type;
    $conflicts_check= 'conflicts_check_for_'.$type;

    //! Check full control
    if (!$this->$permissions_check()){
      self::InProcess(__("Erreur durant traitement de cette fonction permissions_check_for_remove()"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return;
    }
    if (!$this->$conflicts_check()){
      self::InProcess(__("Erreur durant traitement de cette fonction conflicts_check_for_remove()"), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'block');
      return;
    }

    //! check error level
    if(!self::check_bylevel(0)) return false;
    return true;
  }

  /**
    Delete contrib folder and Zip
  */
  private function DeleteContribFull($zip=true, $message='not installable '){
    if ($this->was_unpacked())
      if(!fileUtility::_rmdir(DIR_FS_CIP.self::$cip_name) )
	self::InProcess(__("delete folder ,".$message).self::$cip_name, __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'normal');

    if($zip && !fileUtility::_rmdir(DIR_FS_CIP.$this->get_zip_name()) )
      self::InProcess(__("delete zip , ".$message).$this->get_zip_name(), __CLASS__.'->'.__FUNCTION__.'::'.__LINE__,'normal');

  }


  public static function check_bylevel($level=3){
    return ErrorAndBlockProcess::CtrlForContinue($level);
  }


  public static function InProcess($msg,$origin='',$type='',$level=E_USER_NOTICE){
    return ErrorAndBlockProcess::ChooseAction($msg,$origin,$type,$level);
  }


}

class ErrorAndBlockProcess{

  public static $ArrayError=array();

  public static $level_error=array();

  public static $UniqueId=0;

  public static $error=false;


  public function __construct(){

  }

  public function reset(){
    self::$UniqueId=0;
    self::$level_error=array();
    self::$ArrayError=array();
  }


  /**
    Control niveau d'erreur pour suite ou block script

    @param
      @a int level error control
    @return boolean suite script
  */
  public static function CtrlForContinue($level=3){
    for($i=0; $i<$level; $i++)
      if(isset(self::$level_error[$i])  && in_array(true,self::$level_error[$i])) return false;

    return true;
  }


  /**
    @param
      @a string $msg
      @a string noblock|block
      @a string $origin Function/class
  */
  public static function ChooseAction($msg,$origin='',$type='',$level=E_USER_NOTICE){

    $id=self::UniqueId();
    switch($type){
      case '0':
      case 'error':
	/**
	  Fatal sortie
	*/

	self::$level_error[0][$id]=true;
	self::$ArrayError[$id]='[['.number_format( array_sum(explode(' ', microtime())) - array_sum(CIP::$stamptime), 8, '.', '' ).']]'.__('ERROR :').$origin.':: '.CIP::$cip_name.' '.$msg;
      case '1':
      case 'block':
      /**
	Message type 1, block action d execution mais autorise traitement check, backup, restore
      */
	self::$level_error[1][$id]=true;
	self::$error=true;
	self::$ArrayError[$id]='[['.number_format( array_sum(explode(' ', microtime())) - array_sum(CIP::$stamptime), 8, '.', '' ).']]'.__('FATAL :').$origin.':: '.CIP::$cip_name.' '.$msg;
	return;
      break;
      case '2':
      case 'noblock':
	self::$level_error[2][$id]=true;
	self::$ArrayError[$id]='[['. number_format( array_sum(explode(' ', microtime())) - array_sum(CIP::$stamptime), 8, '.', '' ).']]'.__('NO BLOCK :').' '.$origin.':: '.CIP::$cip_name.' '.$msg;
      break;
      default:
      /**
	Message info
      */
	self::$ArrayError[$id]=__('INFO :').$msg;
	self::$level_error[3][$id]=false;
    }

  }


  private static function UniqueId(){
    return self::$UniqueId ++;
  }
}
?>