<?php
/**
  \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.1.0
  \date  15/12/10, 11:33
  \author oscim <mail aurelien@oscim.fr> <www http://www.oscim.fr>
  \encode UTF-8

  Prise en charge des product

  \note
  Convention nommage alias table:
   \li TABLE_PRODUCTS : 			p
   \li TABLE_PRODUCTS_DESCRIPTION		pd
   \li TABLE_PRODUCTS_TO_CATEGORIES 	p2c
   \li TABLE_CATEGORIES			c

*/


/**
 * \class product
 * \brief   Control init et gestion des data product
 *
 * 	Assure tous les appels vers les class enfants, Data et Modules.
 *  \li Tous les appels vers les methodes de la class productModule sont public \n
 *  	les modules de sont extends de AbstractProduct
 *  \li Tous les appels vers les methodes de la class productData sont static
  *
*/
class product {

  //! @p object
  protected static $_instance;

  public static $modules;

  /**
    Pile des images du porduit
    @param array
  */
  var $pile_img;

  /**
  */
  protected function __construct($full) {
    global $languages_id;
    productData::start();
    if($full) self::start_module();
  }

  protected static function start_module(){
    $pdm=productModule::getInstance();
    self::$modules=$pdm->ret_modules();
    return $pdm;
  }

  public static function getInstance($full=false) {
    if(self::$_instance == null) self::$_instance = new self($full);
    return self::$_instance;
  }

  public static function resetInstance(){
    self::$_instance = null;
    return self::getInstance();
  }

  /**
    Module ACA
  */

  /**
   * \fn ret_modules()
   * \brief Retour tableau des modules type products actif
   * @return plusieurs modules via array(object)
   */
  public function ret_modules(){ self::start_module(); return self::$modules;}
  /**
   * \fn check_action($class='',$actions='')
   * \brief execute la capture des actions par les modlues
   * @param $class string
   * @param $actions array
   */
  public function check_action($class='',$actions=''){ $pdm=self::start_module(); return $pdm->check_action($class,$actions);}
  /**
   * \fn get_header($class='',$actions='')
   * \brief traitement block header des module
   * 		Display block header modules
   * @param $class string
   * @param $actions array
   */
  public function get_header($class='',$actions=''){ $pdm=self::start_module(); return $pdm->get_header($class,$actions);}
  /**
   * \fn after_check_action($class='',$actions='')
   * \brief after_check_action
   * @param $class string
   * @param $actions array
   */
  public function after_check_action($class='',$actions=''){ $pdm=self::start_module(); return $pdm->after_check_action($class,$actions);}
  /**
   * \fn display_view($pID,$class='',$exclude=array())
   * \brief after_check_action
   * @param $pID int
   * @param $class string
   * @param $exclude array
   */
  public function display_view($pID,$class='',$exclude=array()){ $pdm=self::start_module(); return $pdm->display_view($pID,$class,$exclude);}

  /**
   * \fn get_adjust_price($product_array)
   * \brief adjust price products , depend class price, execute by productData
   * @param $product_array array
   */
  public static function get_adjust_price($product_array){ $pdm=self::start_module(); return $pdm->adjust_price($product_array);}
  /**
   * \fn get_option_data($product_array)
   * \brief adjust products, depend class price, execute by productData
   * @param $product_array array
   */
  public static function get_option_data($product_array){ $pdm=self::start_module(); return $pdm->get_option_data($product_array);}

  /**
    Data function
  */

  /**
   * \fn get_query($id='',$search='',$exclude='',$option='')
   * \brief generation automatique de requetes pour exraire les données des produits.
   * Cet appel est mis en cache afin d'optimiser les requetes, de maniére incremental pour chaque produit, et par produits.
   * @param $id integer id
   * @param $search string champs qui sera recherché dans tous les champs de la db
   * @param $exclude tableau d'ecxlusion de produits par id
   * @param $option array option passé par couple key/values
   * @return object
   */
  public static function get_query($id='',$search='',$exclude='',$option=''){ global $languages_id; return productData::get_query($id,$search,$exclude,$option); }
  /**
   * \fn get_item($id)
   * \brief appel d'un produit par son id, il sera recupere dans la pile du cache, ou via une requet sql
   * @param $id
   * @return object
   */
  public static function get_item($id){ return productData::get_item($id); }
  /**
   * \fn get_product_path($id)
   * \brief generation du cPath d'un produits
   * @param $id int
   * @return string cPath
   */
  public static function get_product_path($id){ return productData::get_product_path($id); }
  /**
   * \fn get_product_attribut_info($id)
   * \brief appel info attribute product , renvoi tableau d'information
   * @param $id int products id
   */
  public static function get_product_attribut_info($id){ return productData::get_product_attribut_info($id); }
  /**
   * \fn get_product_attribut_info($id)
   * \brief retourne le nombre de produits en stock, en fonction de ces caratèristiques,
   *   \li si produit sans attribut alors retour nombre de produits,
   *   \li si produit + attribute, alors retour du stock pour cette association attributs produits
   * @param $id int id produit
   * @return int
   */
  public static function get_products_stock($id,$attributes=array()){ return productData::get_products_stock($id, $attributes); }
  /**
   * \fn get_has_product_attributes($id)
   * \brief true/false si attribut associé a ce produits
   * @param $id int
   */
  public static function get_has_product_attributes($id){ return productData::get_has_product_attributes($id); }
  /**
   * \fn get_product_attribut_price($products_id, $attributes=array())
   * \brief calcul prix produit avec attribute
   * @param $products_id int
   * @param $attributes array
   * @return float
   */
  public static function get_product_attribut_price($products_id, $attributes=array()) {return productData::get_product_attribut_price($products_id, $attributes); }
  /**
   * \fn get_attributes_weight($products_id, $attributes=array())
   * \brief calcul du poids avec attribute
   * @param $products_id int
   * @param $attributes array
   * @return float
   */
  public static function get_attributes_weight($products_id, $attributes=array()) {return productData::get_attributes_weight($products_id, $attributes); }
//   public static function get_product_path($id){ return productData::get_product_path($id); }

  public static function get_extra_product($products_id) {return productData::get_extra_product($products_id); }
}


/**
  @class productData
  Traitement sql des product
*/
class productData
  extends DataStatmentFO
    implements Interfacedata{

  //! @p int
  public static $lg_id;
  //! @p obj res db
  public static $obj_language;
  //! @p array
  public static $cache=array();

  //! @p object cache
  public static $object_data;
  //! @p array cache
  public static $array_data=array();

  //! @p string
  private static $where_query='';


  /**
  */
  public static function start(){
    global $languages_id;
    self::$lg_id=(int)$languages_id;
    $DB=Database::getInstance();
    self::$obj_language = $DB->query("select code from " . TABLE_LANGUAGES . " where languages_id='" .self::$lg_id . "'");
  }


  /**
    Mise en pile de toutes les element des page de cms
  */
  private static function add_cache($id){
    self::$cache[]=$id;
  }

  /**
    Appel et recup des element du cache
  */
  private static function in_cache(){
    return implode("," ,self::$cache);
  }

  /**
    Prepa donnée sortie
  */
  protected static function statment_query($content_query,$exclude='',$search=''){

    $display_lang=self::$obj_language->fetchAssoc();
    if (empty($exclude))$exclude=array();
    $tabl=$product=array();
    while ($content = $content_query->fetchAssoc()) {
      if (!in_array($content['products_name'],$exclude)) {
	$product=$content;
	$product['href']=tep_href_link(FILENAME_PRODUCT_INFO,'products_id=' . $content['products_id'] . '&amp;language=' . $display_lang['code']);
	$product['key']=$content['products_id'];
	$product['id']=$content['products_id'];
	$product['title']=(tep_not_null($content['products_model'])?$content['products_model']:$content['products_name']);
	$product['name']=$content['products_name'];

	$product['extra']=self::get_extra_product($content['products_id']);

	// boolean value If buy possible
	if(!_cst_bool('STOCK_ALLOW_CHECKOUT'))
	  $product['action']['buy']=( ((int)$content['products_quantity']>0 && (int)$content['track_stock']===1) || (int)$content['track_stock']!=1)? true : false;
	else
	  $product['action']['buy']=true;

	/**
	  module aca
	*/
	$product=product::get_option_data($product);

	self::$object_data[$content['products_id']]=$tabl[$content['products_id']]=new objectInfo($product);
	self::$array_data[$content['products_id']]=$product;
	self::add_cache($content['products_id']);
      }
    }

    if((count(self::$object_data)>0))
    foreach(self::$object_data as $k=>$content)
      if (isset($content->name) && !in_array($content->name,$exclude)) {
	if((!empty($search) && strstr($content->name,$search) !=false) || empty($search)) $tabl[$content->id]=$content;
      }

    return $tabl;
  }

  /**
    Ajout constrainte clause where
  */
  protected static function add_where_query($add){ self::$where_query .=' '.$add; }

  /**
  */
  protected static function reset_query() { self::$where_query=''; }



  /**
    Requeteur
  */
  protected static function cstr_query($orderby='', $limit='', $option=''){

    $query="SELECT distinct p.products_id, pd.products_name, pd.products_description, p.products_model, p.products_quantity, p.products_image, pd.products_url, p.products_price,p.track_stock, p.products_tax_class_id, p.products_date_added, p.products_date_available, p.manufacturers_id, pd.products_viewed, p2c.categories_id,  p.products_weight, IF(pv.typeID, pv.typeID, 1)  as type
	  FROM " . TABLE_PRODUCTS . " p left join ".TABLE_PRODUCTS_VIRTUAL." pv on p.products_id = pv.productsID , " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c,  " . TABLE_CATEGORIES . " c
	  WHERE p.products_status = '1'  and pd.products_id = p.products_id and pd.language_id = '" . self::$lg_id  . "' and p2c.products_id=p.products_id and c.categories_id=p2c.categories_id and c.categories_status='1'  " ;

    $query .=self::$where_query;
    $query .=' ORDER BY ' .(!tep_not_null($orderby)? '  p.products_date_added DESC   ' : $orderby) ;
    $query .=' LIMIT '.(!tep_not_null($limit)? '1' : $limit) ;

    return $query;
  }


  /**
   * \brief Appel item
   * @param $id
   * @param $search
   * @param $exclude
   * @param $option
  */
  public static function get_query($id='',$search='', $exclude='',$option=''){
    global $languages_id;

    self::start();
    self::reset_query();
    $DB=Database::getInstance();
    self::$lg_id=(int)$languages_id;
    if(empty($option))$option=array();
    $search=tep_db_prepare_input($search);

    if (count(self::$cache)>0) self::add_where_query(' AND p.products_id NOT IN ('.self::in_cache().') ');
    //! soit id soit sherach name key
    self::add_where_query((tep_not_null($id) && is_numeric($id) ? " AND p.products_id = '" . (int)$id . "' ": (!empty($search)?" AND pd.products_name LIKE '%" . tep_db_input($search) . "%' ":'') ));
    $sql=self::cstr_query((string)@$option['orderby'],(int)@$option['limit'],(array)@$option) ;

    $content_query = $DB->query($sql);

    return self::statment_query($content_query,$exclude,$search);
  }

  /**
    Alias unique ID
  */
  public static function get_item($id){
    $db_list=self::get_query($id);

    if(is_numeric($id) && isset($db_list[(int)$id])){
      return $db_list[$id];
    }else{
      $db_list=self::get_query('',$id);
      foreach($db_list as $item)
	if((string)$id==(string)$item->name)return $item;
    }
    return false;
  }



// Check if product has attributes
  public static function get_has_product_attributes($products_id) {
    $DB=Database::getInstance();

    $attributes_query = $DB->query("select count(*) as count from " . TABLE_PRODUCTS_ATTRIBUTES . " where products_id = '" . (int)$products_id . "'");
    $attributes = $attributes_query->fetchAssoc();
    self::$object_data[(int)$products_id]->has_attributes=($attributes['count'] > 0) ? true : false;
    self::$object_data[(int)$products_id]->count_attributes=$attributes['count'];

    return (bool)self::$object_data[(int)$products_id]->has_attributes;
  }

  /**
    Champs extra product
    Recupere la totalite des element supp
    [extra] => Array
        (
            [MONTANT_PART] => objectInfo Object
                (
                    [label] => le montant d'une part
                    [value] => 5
                    [epf_key] => MONTANT_PART
		    [epf_id] => id epf
                )
	)
  */
  public static function get_extra_product($product_id){
    $array= array();

    if(isset(self::$object_data[(int)$product_id]) && isset(self::$object_data[(int)$product_id]->extra) )$array= self::$object_data[(int)$product_id]->extra;
    else {
      $DB=Database::getInstance();
      $array=array();
      $epf_query = $DB->query("SELECT e.epf_id, e.epf_uses_value_list,e.epf_key, epf_show_in_listing, epf_advanced_search, l.epf_active_for_language , l.epf_label, p2epf.products_extra_fields_value as value FROM " . TABLE_PRODUCTS_TO_PRODUCTS_EXTRA_FIELDS . " p2epf , " . TABLE_PRODUCTS_EXTRA_FIELDS . " e JOIN " . TABLE_PRODUCTS_EXTRA_FIELDS_LABELS . " l ON e.epf_id = l.epf_id  WHERE p2epf.products_extra_fields_id=e.epf_id AND products_id = '" . (int)$product_id . "' AND l.languages_id='".self::$lg_id."'  ");

      while( $e = $epf_query->fetchAssoc() ) {
	if($e['epf_active_for_language']==1) {
	  $name_field = "extra_value" . ($e['epf_uses_value_list'] ? '_id' : '') . $e['epf_id'];
	  $product_query = $DB->query("select " . $name_field . " from " . TABLE_PRODUCTS_DESCRIPTION . " where products_id = '" . (int)$product_id . "' and language_id = '" . self::$lg_id . "'");
	  $field =$product_query->fetchAssoc();

	  $name=$field[$name_field];
	} else {
	  $name = $e['value'];
	}

	$array[$e['epf_key']]=new objectInfo( array(  'label'=>(string)$e['epf_label'],
				      'value' => $name,
				      'epf_key'=>(string)$e['epf_key'],
				      'epf_id'=>(int)$e['epf_id'],
				      'epf_show_in_listing'=>(int)$e['epf_show_in_listing'],
// 				      'epf_advanced_search'=>(int)$e['epf_advanced_search']
				  ) );
      }
      if(!isset(self::$object_data[(int)$product_id]))self::$object_data[(int)$product_id]=new objectInfo(array());
      self::$object_data[(int)$product_id]->extra = $array;
    }

    return $array;
  }

  /**
    Construct a category path to the product
  // TABLES: products_to_categories
  */
  public static  function get_product_path($products_id) {
    $cPath = '';
    if((int)$products_id ==0 )return false;
    if( ($category=self::get_item($products_id)) == false) return false;
    $categories = array();
    tep_get_parent_categories($categories, $category->categories_id);
    $categories = array_reverse($categories);
    $cPath = implode('_', $categories);

    if (tep_not_null($cPath)) $cPath .= '_';
    $cPath .= $category->categories_id;

    if(!is_object(self::$object_data[(int)$products_id])) self::$object_data[(int)$products_id]=new objectInfo(array());
    self::$object_data[(int)$products_id]->cPath=$cPath;

    return $cPath;
  }


  /**
    Return a product's stock
  */
  public static function get_products_stock($products_id, $attributes=array()) {
    $products_id = tep_get_prid($products_id);

    if (sizeof($attributes)>0) {
      return (int) self::get_products_attribute_stock($products_id, $attributes);
    }
    else {
      $stock_values=self::get_item($products_id);
      return ((!$stock_values)? false : (int)$stock_values->products_quantity );
    }
  }

  public static function tep_get_products_name($product_id, $language = '') {
    global $languages_id;

    self::$lg_id=(int)(empty($language))? $language : $languages_id;
    $products_id = tep_get_prid($products_id);
    $stock_values=self::get_item($products_id);
    return $stock_values->products_name;
  }

  /**
   * \fn get_product_attribut_info($pID)
   * \brief Retourn tableau asso des element de pId precisé ou false
   * @param  $pID int l'id du produits
   * @return array/false
  */
  public static function get_product_attribut_info($pID){
    global $page;
    if(!isset(self::$array_data[$pID]) || !is_object(self::$array_data[$pID]) ) self::$array_data[$pID]= new objectInfo(array());
    if(isset(self::$array_data[$pID]->product_attribut_info)) return self::$array_data[$pID]->product_attribut_info ;

    $language_id=$page->the_var('languages_id');
    $products_attributes_query = tep_db_query("select count(*) as total from " . TABLE_PRODUCTS_OPTIONS . " popt, " . TABLE_PRODUCTS_ATTRIBUTES . " patrib where patrib.products_id='" . (int)$pID . "' and patrib.options_id = popt.products_options_id and popt.language_id = '" . (int) $language_id. "'");
    $products_attributes = tep_db_fetch_array($products_attributes_query);
     $products_attributes=  ($products_attributes['total'] > 0)? $products_attributes : array() ;

    return self::$array_data[$pID]->product_attribut_info = $products_attributes;
  }

  /**
    Recuperation price pour attribute
  */
  public static function get_product_attribut_price($products_id, $attributes=array()){
    $attributes_price = 0;

    $uprid=tep_get_uprid($products_id, $attributes);

    if(!isset(self::$array_data[$products_id]) || !is_object(self::$array_data[$products_id])) self::$array_data[$products_id]=new objectInfo(array());

    if(isset(self::$array_data[$products_id]->product_attribut_price) && isset(self::$array_data[$products_id]->product_attribut_price[$uprid]) ) return self::$array_data[$products_id]->product_attribut_price[$uprid] ;

    if (is_array($attributes) && count($attributes)>0) {
      reset($attributes);
      while (list($option, $value) = each($attributes)) {
	$attribute_price_query = tep_db_query("select options_values_price, price_prefix from " . TABLE_PRODUCTS_ATTRIBUTES . " where products_id = '" . (int)$products_id . "' and options_id = '" . (int)$option . "' and options_values_id = '" . (int)$value . "'");
	$attribute_price = tep_db_fetch_array($attribute_price_query);
	if ($attribute_price['price_prefix'] == '+') {
	  $attributes_price += $attribute_price['options_values_price'];
	} else {
	  $attributes_price -= $attribute_price['options_values_price'];
	}
      }
    }

    return self::$array_data[$products_id]->product_attribut_price[$uprid] =$attributes_price;
  }

  /**
   * \brief Calcul du poids
  */
  public static function get_attributes_weight($products_id, $attributes=array()) {
    $attributes_weight = 0;

    $uprid=tep_get_uprid($products_id, $attributes);
    if(isset(self::$array_data[$products_id]->product_attributes_weight) && isset(self::$array_data[$products_id]->product_attributes_weight[$uprid]) ) return self::$array_data[$products_id]->product_attributes_weight[$uprid] ;

    if (is_array($attributes) && count($attributes)>0) {
      reset($attributes);
      while (list($option, $value) = each($attributes)) {
	$attribute_price_query = tep_db_query("select options_values_weight from " . TABLE_PRODUCTS_ATTRIBUTES . " where products_id = '" . (int)$products_id . "' and options_id = '" . (int)$option . "' and options_values_id = '" . (int)$value . "'");
	$attribute_price = tep_db_fetch_array($attribute_price_query);
	$attributes_weight += $attribute_price['options_values_weight'];
      }
    }

    return self::$array_data[$products_id]->product_attributes_weight[$uprid] = $attributes_weight;
  }


  /**
   * \brief Calcul des stock avec attribut , pour un  jeu d'attribut
   * @param [in] $products_id int
   * @param [in] $attributes tableau attribute id array
   * @return int  quantity
  */
  private static function get_products_attribute_stock($products_id, $attributes=array()){
    global $page;

    self::get_query($products_id);
    $uprid=tep_get_uprid($products_id, $attributes);
    if(isset(self::$array_data[$products_id]->products_attribute_stock)  && isset(self::$array_data[$products_id]->product_attribut_price[$uprid])  )
      return self::$array_data[$products_id]->products_attribute_stock[$uprid] ;
    elseif(isset(self::$array_data[$products_id]->products_attribute_stock)  )
      self::$array_data[$products_id]->products_attribute_stock=array();

    $languages_id=$page->the_var('languages_id');
    $DB=Database::getInstance();
    if (is_array($attributes) && count($attributes)>0) {
      $attr_list='';
      $options_list=implode(",",array_keys($attributes));
      $sql="select products_options_id, products_options_track_stock from " . TABLE_PRODUCTS_OPTIONS . " where products_options_id in ($options_list) and language_id= '" . (int)$languages_id . "' order by products_options_id";
      $track_stock_query=$DB->query($sql);
      while($track_stock_array=$track_stock_query->fetchAssoc())
        if ($track_stock_array['products_options_track_stock'])
          $attr_list.=$track_stock_array['products_options_id'] . '-' . $attributes[$track_stock_array['products_options_id']] . ',';

      $attr_list=substr($attr_list,0,strlen($attr_list)-1);
      unset($track_stock_query);


      $stock_query=$DB->query($sql="select products_stock_quantity as quantity from " . TABLE_PRODUCTS_STOCK . " where products_id='". (int)$products_id . "' and products_stock_attributes='$attr_list'");
      $stock=$stock_query->fetchAssoc();
      unset($attr_list);

      self::$array_data[$products_id]->products_attribute_stock[$uprid] = (int)$stock['quantity'];
      return $stock['quantity'];
    }
    return self::$array_data[$products_id]->products_attribute_stock[$uprid] = 0;
  }



}



/**
  \class AbstractProduct
  \brief Force mise en forme via class absctarction des modules de produits, type products
*/
abstract class AbstractProduct {
    // Force la classe étendue é définir cette méthode
    abstract protected function display_view($pID,$class='');
    abstract protected function load_db_values($pID);
    abstract protected function get_header($action='');
    // méthode commune
//     public function printOut() { }
}



/**
  \class productModule
  \brief Traitement des modules type products
*/
class productModule
  extends AbstractAcaModule
    implements InterfaceAcaGene{

  /**
    flag de la class
    @param string
  */
  public $name;
  /**
    Les modules actif
    @param string
  */
  public $modules;

  static public $_pidVirtual_c=array();

  protected static $_instance;

  /**
  */
  protected function __construct() {
    global $language, $page;
    $this-> name=__CLASS__;
    $this->type_flag=1;
    $this-> products_id='';
    $this-> image_handler='';

    $this->modules=array();
    $this->pile_img=array();
    $list_mod=array();

    foreach(parent::initialise_type('MODULE_ACAPRO_INSTALLED','products') as $class){
      $cl[$class]=new $class ();
      $list_mod[$class] = $cl[$class]->sort_order;
      // test flag type module, si aucun, produist base
      if(!isset($cl[$class]->flag_type_virtual)) $cl[$class]->flag_type_virtual=0;
      // incremente tableau module unqiuement si flag ok
      if($this->control_type_mod($cl[$class]->flag_type_virtual)) $list_mod[$class] = $cl[$class]->sort_order;
    }

    asort($list_mod);
    foreach($list_mod as $class=>$s){
      $this->modules[$class] =$cl[$class];
    }
    unset($cl);unset($list_mod);

    return $this->modules;
  }


  public static function getInstance() {
    if(self::$_instance == null) self::$_instance = new self();
    return self::$_instance;
  }

  public static function resetInstance(){
    self::$_instance = null;
    return self::getInstance();
  }

  /**
    Get data modified/add by module
  */
  public function get_option_data($product_array){
    if(isset($this->modules) && is_array($this->modules))
    foreach ($this->modules as $key=>$module) {
      if ( $module->enabled && (method_exists($module, 'get_option_data' ))) {
	$product_array=$this->modules[$key]->get_option_data($product_array);
      }
    }
    return $product_array;
  }

  /**
    Get price modified by module
    Unqiuement pour les module qui definissent le flag price
  */
  public function adjust_price(&$product_array){
//     $product_array = $product_array_master;
    if(isset($this->modules) && is_array($this->modules))
    foreach ($this->modules as $key=>$module) {
      if ( $module->enabled && isset($module->price)   && (method_exists($module, 'adjust_price' ))) {
	$product_array=$this->modules[$key]->adjust_price($product_array);
      }
    }
    return $product_array;
  }


 /**
  * \fn  display_view($pID,$class='',$exclude=array() )
    @brief Affiche module elemennt html
    Block principal d'affichage, liste ou vue des élément. Block principal de page
    @param $pID int le Id du produits
    @param $class string  le nom de la class appelé, ou vide pour toutes les class enfants
    @param $exclude array
  */
  public function display_view($pID,$class='',$exclude=array() ){
    global  $page;
    if (!empty($class)) {
      if (isset($this->modules[$class]) && $this->modules[$class]->enabled and (method_exists($class, 'display_view' ))){
        $this->modules[$class]->load_db_values($pID);
        return $this->modules[$class]->display_view($pID);
      }
    } else {
      $c=array();
      if(isset($this->modules) && is_array($this->modules))
      foreach ($this->modules as $key=>$module) {
        if ( !in_array($key,$exclude) && ($module->enabled)  and (method_exists($module, 'display_view' ))) {
          $this->modules[$key]->load_db_values($pID);
          $c[$key]=$this->modules[$key]->display_view($pID);
        }
      }
      return $c;
    }
  }

  /**
    @brief Affiche module display_view mini
    @param   cID int le Id du customers
    @param   class string le nom de la class appelé, ou vide pour toutes les class enfants
  */
  public function display_view_min($cID,$class=''){
    global  $page;
    if (!empty($class)) {
      if (isset($this->modules[$class]) && $this->modules[$class]->enabled and (method_exists($module, 'display_view_min' ))){
        $this->modules[$class]->load_db_values($cID);
        return $this->modules[$class]->display_view_min($cID);
      }
    } else {
       $c='';
      foreach ($this->modules as $key=>$module) {
        if (($module->enabled)  and (method_exists($module, 'display_view_min' ))) {
          $this->modules[$key]->load_db_values($cID);
          $c .=$this->modules[$key]->display_view_min($cID);
        }
      }
      return $c;
    }
  }

  /**
   * \fn display_titre($cID,$format='$s')
   * \brief  Affiche bock titre client notifié
   * @param $cID
   *  @param $format string format for sprintf
  */
  public function display_titre($cID,$format='$s'){
      $c='';
      foreach ($this->modules as $key=>$module) {
        if (($module->enabled)  and (method_exists($module, 'display_view_min' ))) {
          $this->modules[$key]->load_db_values($cID);
          $c .=$this->modules[$key]->display_titre($format);
        }
      }
      return $c;
  }




/** Specifique Module */


  /**
  * \brief Activation/ descative les modules en focntion du type de produits
  * @param $flag string le type falg de modules
  * @return boolean
  */
  private function control_type_mod($flag){
    if(!isset($this->type_flag) ) $this->load_type_product();
    if(in_array($flag,explode(',',$this->type_flag) )|| $flag==0) return true;
    else return false;
  }

  /**
    Recup db type flag
    @return int, Id du type ou 1
  */
  private function load_type_product(){
    if(!isset($_GET['products_id'])) return ;

    if(isset(productData::$array_data[(int)$_GET['products_id']]) )  return productData::$array_data[(int)$_GET['products_id']];

    $sql = "select * from ".TABLE_PRODUCTS_VIRTUAL." where productsID=".(int)$_GET['products_id'];
    $result = tep_db_query($sql);
    if (tep_db_num_rows($result) > 0) { // this product is in the virtual table
      $virtual = tep_db_fetch_array($result);
      $this->type_flag= $virtual['typeID'];
    }
    else $this->type_flag=1;
    productData::$array_data[(int)$_GET['products_id']] = $this->type_flag;
    tep_db_free_result($result);
  }




}
?>