<?php
/**
 * Scale class
 * 
 * Povides methods related to scale module
 * 
 * @package linea21\core\scale
 * @author $Author$ - linea21 <info@linea21.com>
 * @version $Id$ 
 * @access public
 * @license http://opensource.org/licenses/gpl-3.0.html
 * Scale Management
 */
class scale {
  /* @param
   * */
  var $TDB_SCALE = T_SCALE; // nom de la table.
  var $ID;
  var $DENOMINATION;
  var $ROOT;
  var $SURFACE;
  var $INHABITANTSNUM;
  var $CIN;
  var $EXTRADATA;
  var $COMMENT;
  var $DEPENDENCIES;
  var $DATE_CREA;
  var $STATUT;
  var $LAST_MODIFY;

  var $DEPTH_TABLE = array (); // tableau contenant les profondeurs d'échelles
  var $SON_TABLE = array (); // tableau contenant les fils d'échelles
  var $ALL_REC = array (); // tableau contenant les fils d'échelles
  protected $dispatcher = null;

  public function __construct()
  {
    $this->dispatcher = $GLOBALS['dispatcher'];
  }

  public function __call($method, $arguments)
  {
    $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'scale.extensible_function', array(
      'method'    => $method,
      'arguments' => $arguments
    )));
    if (!$event->isProcessed())
    {
      throw new Exception(sprintf('Call to undefined method %s::%s.', get_class($this), $method));
    }

    return $event->getReturnValue();
  }

  /**
   * scale::CheckDataIntegrity()
   * Vérification des données d'une echelle
   *
   * @access public
   * @param array $table_scale : contient les composants d'une echelle
   * @return boolean si vrai renvoie true sinon message d'erreurs (string)
   */
  function CheckDataIntegrity($table_scale)
  {
  	// Filter data event + return value
  	$r = $this->dispatcher->filter(new sfEvent($this, 'scale.before_datacheck', array('data' => $table_scale)), $table_scale);
  	$table_scale = $r->getReturnValue();

    $notdenomination = _t('scale','object_notdenomination');
    $notnumsurface = _t('scale','object_notnumsurface');
    $notnuminhabitants = _t('scale','object_notnuminhabitants');
    $notroot = _t('scale','object_notroot');

    if (strlen($table_scale[0]) < 2) return $notdenomination;
    if (trim($table_scale[1]) != '' && !is_numeric(sys_number_format($table_scale[1]))) return $notnumsurface;
    if (trim($table_scale[2]) != '' && !is_numeric(sys_number_format($table_scale[2]))) return $notnuminhabitants;
    if (!is_numeric($table_scale[3]) || $table_scale[3] == -1) return $notroot;

    // Notify the beginning of the current method
    $this->dispatcher->notify(new sfEvent($this, 'scale.after_datacheck', array('data' => $table_scale)));

    return true;
  }

  /**
   * scale::getMaxDepth()
   * obtention de la profondeur max d'une échelle ( par rapport a ses filles
   *
   * @access public
   * @param  $id : identifiant de l'échelle courante
   * @param  $sql_object
   * @return array $return_table contennat profondeur et échelle d'exclusion
   */
  function getMaxDepth($id, $sql_object)
  {
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'scale.get_max_depth', array('id' => $id)));

    $this->ID = $id;

    $q = "SELECT scale_dependencies FROM " . $this->TDB_SCALE . " WHERE scale_id='" . $this->ID . "';";
    $result = $sql_object->DBSelect($q);
    $this->DEPENDENCIES = $result[0]['scale_dependencies'];
    array_push($this->DEPTH_TABLE, $this->DEPENDENCIES);
    array_push($this->SON_TABLE, $this->ID);

    $this->getAllRecord($sql_object);
    $this->getScaleDepthAndSon($this->ALL_REC, $this->ID);
    rsort($this->DEPTH_TABLE);

    $return_table["depth"] = MAX_SCALE_LEVEL - ($this->DEPTH_TABLE[0] - ($this->DEPTH_TABLE[(count($this->DEPTH_TABLE)-1)])) - 1;
    $return_table["exclusion"] = $this->SON_TABLE;

    return $return_table;
  }

  /**
   * scale::getScaleDepthAndSon()
   * obtention des fils et profondeur ( récursif ) par rapport à une échelle données
   * stockage dans des tableaux respectifs.
   *
   * @param  $table Ensemble des échelles
   * @param  $id échelle courante
   * @return void
   */
  function getScaleDepthAndSon($table, $id)
  {
  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'scale.get_scale_depth_and_son', array('data' => $table, 'id' => $id)));

    for($i = 0; $i < count($table); $i++) {
      $current_dep = $table[$i]['scale_dependencies'];
      $current_root = $table[$i]['scale_root'];
      $current_id = $table[$i]['scale_id'];

      if ($id == $current_root) {
        if (!in_array($current_dep, $this->DEPTH_TABLE)) array_push($this->DEPTH_TABLE, $current_dep);
        if (!in_array($current_id, $this->SON_TABLE)) array_push($this->SON_TABLE, $current_id);
        $this->getScaleDepthAndSon($table, $current_id);
      }
    }
  }

  /**
   * scale::getAllRecord()
   * Obtention de toutes les échelles.
   *
   * @param  $sql_object
   * @return void
   */
  function getAllRecord($sql_object)
  {

  	// Notify the beginning of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'scale.get_all_record'));

    $q = "SELECT scale_dependencies, scale_id, scale_root FROM " . $this->TDB_SCALE . ";";
    $this->ALL_REC = $sql_object->DBSelect($q);
  }

  /**
   * scale::AddScale()
   * Ajout d'une echelle
   *
   * @access public
   * @param array $table_scale contient les composants d'une echelle
   * @param object $sql_object
   * @return integer $last_id
   */
  function AddScale($table_scale, $sql_object)
  {
  	global $l21auth;

  	// Filter data event + return value
  	$r = $this->dispatcher->filter(new sfEvent($this, 'scale.before_add', array('data' => $table_scale)), $table_scale);
  	$table_scale = $r->getReturnValue();

    $table_scale=$sql_object->DBescape($table_scale);

    if (strlen($table_scale[0]) > 1) {
      $this->DENOMINATION = strip_input(trim($table_scale[0]));
    } else return $notdenomination;
    if (trim($table_scale[1]) == '') {
      $this->SURFACE = 0;
    } else {
      $this->SURFACE = sys_number_format(trim($table_scale[1]));
    }
    if (trim($table_scale[2]) == '') {
      $this->INHABITANTSNUM = 0;
    } else {
      $this->INHABITANTSNUM = sys_number_format(trim($table_scale[2]));
    }
    if (is_numeric($table_scale[3])) {
      $this->ROOT = $table_scale[3];
    }
    $this->CIN = strip_input(trim($table_scale['cin'], false));
    $this->EXTRADATA = strip_input(trim($table_scale['extradata'], false));
    $this->COMMENT = strip_input(trim($table_scale[4], true));

    if ($table_scale[5] != '') {
      strtoupper($table_scale[5]);
      switch ($table_scale[5]) {
        case 'P':
          $this->STATUT = $table_scale[5];
          break;
        case 'D':
          $this->STATUT = $table_scale[5];
          break;
        default:
          $this->STATUT = 'P';
          break;
      }
    } else $this->STATUT = 'P';
    // On Determine le rang de l'échelle
    $q = "SELECT scale_dependencies FROM " . $this->TDB_SCALE . " WHERE scale_id=" . $this->ROOT . ";";
    $result = $sql_object->DBSelect($q);
    $this->DEPENDENCIES = $result[0]['scale_dependencies'] + 1;

    $q = "INSERT INTO " . $this->TDB_SCALE . " (scale_denomination, scale_surface, scale_inhabitantsnumber, scale_cin, scale_extradata, scale_root, scale_comment, " . "scale_dependencies, scale_statut, scale_date_crea) " . "VALUES('" . $this->DENOMINATION . "', " . $this->SURFACE . ", " . $this->INHABITANTSNUM . ", '" . $this->CIN . "', '" . $this->EXTRADATA . "', ". $this->ROOT . ", '" . $this->COMMENT . "', " . $this->DEPENDENCIES . ", '" . $this->STATUT . "', NOW());";
    $last_id = $sql_object->DBInsert ($q, 1);
    
    // we log add action
    if(is_numeric($last_id))	logfile(LOG_MAINFILE, array('[action] add scale', 'ID='.$last_id, 'by_id='.$l21auth->GetSessionElement('id'), 'by_login='.$l21auth->GetSessionElement('login')));
    

    // Notify the end of the current method
    $this->dispatcher->notify(new sfEvent($this, 'scale.after_add', array('data' => $table_scale, 'id' => $last_id)));

    return $last_id;
  }

  /**
   * scale::ModifyScale()
   * modification d'une echelle
   *
   * @access public
   * @param int $ID identifiant de l'echelle
   * @param object $sql_object
   * @param array $table_scale contient les composants d'une echelle
   * @return bool $result
   */
  function ModifyScale($ID, $table_scale, $sql_object)
  {
  	// Filter data event + return value
  	$r = $this->dispatcher->filter(new sfEvent($this, 'scale.before_modify', array('data' => $table_scale, 'id' => $ID)), $table_scale);
  	$table_scale = $r->getReturnValue();

    $table_scale=$sql_object->DBescape($table_scale);

    if (is_numeric($ID)) {
      $this->ID = $ID;
    }
    if ($table_scale[0] != '') {
      $this->DENOMINATION = strip_input(trim($table_scale[0]));
    }
    if (trim($table_scale[1]) == '') {
      $this->SURFACE = 0;
    } else {
      $this->SURFACE = sys_number_format(trim($table_scale[1]));
    }
    if (trim($table_scale[2]) == '') {
      $this->INHABITANTSNUM = 0;
    } else {
      $this->INHABITANTSNUM = sys_number_format(trim($table_scale[2]));
    }
    if (is_numeric($table_scale[3])) {
      $this->ROOT = $table_scale[3];
    }
    
    $this->CIN = strip_input(trim($table_scale['cin'], false));
    $this->EXTRADATA = strip_input(trim($table_scale['extradata'], false));
    
    $this->COMMENT = strip_input(trim($table_scale[4], true));

    if ($table_scale[5] != '') {
      strtoupper($table_scale[5]);
      switch ($table_scale[5]) {
        case 'P':
          $this->STATUT = $table_scale[5];
          break;
        case 'D':
          $this->STATUT = $table_scale[5];
          break;
        default:
          $this->STATUT = 'P';
          break;
      }
    }
    // On Determine le rang de l'échelle
    $q = "SELECT scale_dependencies FROM " . $this->TDB_SCALE . " WHERE scale_id=" . $this->ROOT . ";";
    $result = $sql_object->DBSelect($q);
    // Si ce n'est pas l'échelle racine on assigne sinon =-1
    $current_depth= (empty($result)) ? -1 : $result[0]['scale_dependencies'];
    $this->DEPENDENCIES = $current_depth + 1;
    // mise à jour du niveau des informations relatives à l'échelle
    $q = "UPDATE  " . $this->TDB_SCALE . " set scale_denomination='" . $this->DENOMINATION . "', scale_surface=" . $this->SURFACE . ", scale_inhabitantsnumber=" . $this->INHABITANTSNUM . ", scale_cin='" . $this->CIN . "', scale_extradata='" . $this->EXTRADATA . "', scale_root=" . $this->ROOT . ", scale_comment='" . $this->COMMENT . "', scale_dependencies=" . $this->DEPENDENCIES . ", scale_statut='" . $this->STATUT . "', scale_last_modify=NOW() WHERE scale_id=" . $this->ID . ";";
    $result = $sql_object->DBQuery($q);
    // si la nouvelle échelle root diffère de la précédente, update récursif des dépendances des échelles filles
    if ($table_scale[6] != $this->ROOT) {
      $this->getAllRecord($sql_object);
      $tabledepth = $this->update_all_dependencies($this->ALL_REC, $this->DEPENDENCIES, $this->ID, $sql_object);
    }

    // Notify the end of the current method
    $this->dispatcher->notify(new sfEvent($this, 'scale.after_modify', array('data' => $table_scale, 'id' => $this->ID)));

    return true;
  }

  /**
   * scale::update_all_dependencies()
   * Mise à jour de l'ensemble des échelles filles par rapport à ul'échelle courante.
   *
   * @param  $table
   * @param  $depth
   * @param  $id
   * @param  $sql_object
   * @return void
   */
  function update_all_dependencies($table, $depth, $id, $sql_object)
  {
  	// Notify the end of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'scale.update_all_dependencies', array('data' => $table, 'id' => $id, 'depth' => $depth)));

    $table_depth = array();
    for($i = 0; $i < count($table); $i++) {
      $current_dep = $table[$i]['scale_dependencies'];
      $current_root = $table[$i]['scale_root'];
      $current_id = $table[$i]['scale_id'];

      if ($id == $current_root) {
        $q = "UPDATE  " . $this->TDB_SCALE . " SET scale_dependencies='" . ($depth + 1) . "' WHERE scale_id='" . $current_id . "';";
        $result = $sql_object->DBQuery($q);
        $this->update_all_dependencies($table, $depth + 1, $current_id, $sql_object);
      }
    }
  }

  /**
   * scale::StateScale()
   * modification du statut d'une échelle
   *
   * @access public
   * @param int $id identifiant de l'echelle
   * @param string $state (facultatif) 'P' Public/'D' Draft
   * @param object $sql_object
   * @return bool $result
   */
  function StateScale($ID, $state, $sql_object)
  {
  	// Notify the end of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'scale.change_state', array('id' => $ID, 'state' => $state)));

    if (is_numeric($ID)) {
      $this->ID = $ID;
    }
    if ($state != '') {
      strtoupper($state);
      switch ($state) {
        case 'P':
          $this->STATUT = $state;
          break;
        case 'D':
          $this->STATUT = $state;
          break;
        default:
          $this->STATUT = $state;
          break;
      }
    } else $this->STATUT = 'P';
    $q = "UPDATE  " . $this->TDB_SCALE . " set scale_statut='" . $this->STATUT . "', scale_last_modify=NOW() WHERE scale_id=" . $this->ID . ";";
    $result = $sql_object->DBQuery($q);
    return $result;
  }
  
  
  /**
   * get_affected_ressources()
   * get number of affected ressources by modules
   * @param integer $ID
   * @param object $sql_object
   * @param array $affected
   * @return array
   */
  function get_affected_ressources($ID, $sql_object, $affected = array()) {
  	
  	// we init array if needed
  	if(count($affected) == 0) {
  		$affected['news']=0;
  		$affected['project']=0;
  		$affected['publication']=0;
  		$affected['indicator']=0;
  	}
  	$affected['total'] = 0;
  	
  	if (is_numeric ( $ID )) {
  		$this->ID = $ID;
  	}
  	
  	// Notify the end of the current method
  	$this->dispatcher->notify ( new sfEvent ( $this, 'scale.get_affected_ressources', array ('id' => $ID ) ) );
  	
  	$query_news = "SELECT news_id FROM " . T_NEWS . " WHERE  news_scale=" . $this->ID . " AND news_statut <> 'E';";
  	$result = $sql_object->DBQuery ( $query_news );
  	$affected['news'] += $sql_object->DBaffectedRow () ;
  	
  	$query_project = "SELECT project_id FROM " . T_PROJECT . " WHERE  project_scale_id=" . $this->ID . " AND project_statut <> 'E';";
  	$result = $sql_object->DBQuery ( $query_project );
  	$affected['project'] += $sql_object->DBaffectedRow ();
  	
  	$query_publication = "SELECT publi_id FROM " . T_PUBLI . " WHERE  publi_scale=" . $this->ID . " AND publi_statut <> 'E';";
  	$result = $sql_object->DBQuery ( $query_publication );
  	$affected['publication'] += $sql_object->DBaffectedRow ();
  	
  	$query_workshop = "SELECT sdiv_id FROM " . T_SDI_VALUE. " WHERE  sdiv_scale=" . $this->ID . " AND sdiv_statut <> 'E';";
  	$result = $sql_object->DBQuery ( $query_workshop );
  	$affected['indicator'] += $sql_object->DBaffectedRow ();
  	
  	
  	foreach ($affected as $el) {
  		$affected['total'] += $el;
  	}
  	
  	return $affected;
  	
  }

  /**
   * scale::DeleteScale()
   * suppression d'une echelle
   *
   * @access public
   * @param int $ID identifiant de l'echelle
   * @param string $type 'MASS_DELETE'
   * 'MASS_DELETE' toutes les ressources associées à l'échelle sont rendues inactives
   * 'MASS_MODIFY' remplacement de l'ancienne échelle par $ID_new
   * @param int $ID_new nouvel id de rattachement
   * @param object $sql_object
   * @return integer $affected // nombre de ressources affectées par les changements
   */
  function DeleteScale($ID, $sql_object, $type, $ID_new = -1)
  {
  	global $l21auth;
  	
  	// Notify the end of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'scale.delete', array('id' => $ID, 'type' => $type, 'new_id' => $ID_new)));

    $affected = 0;
    $this->ID = $ID;
    if ($type == 'MASS_MODIFY') {
      if ($ID_new != -1 && is_numeric($ID_new)) {
        $q = "UPDATE  " . $this->TDB_SCALE . " set scale_statut='E', scale_last_modify=NOW() WHERE scale_id=" . $this->ID . ";";
        $result = $sql_object->DBQuery($q);
        if ($result) {
          $q = "SELECT scale_dependencies FROM " . $this->TDB_SCALE . " WHERE scale_id=" . $ID_new . ";";
          $result = $sql_object->DBSelect($q);
          $dependencies = $result[0]['scale_dependencies'];
          $q = "UPDATE  " . $this->TDB_SCALE . " set scale_root=" . $ID_new . " WHERE scale_root=" . $this->ID . ";";
          $result = $sql_object->DBQuery($q);
          // modification récursive des dépendances.
          $this->getAllRecord($sql_object);
          $this->update_all_dependencies($this->ALL_REC, $dependencies, $ID_new, $sql_object);
          // mise à jour des ressources.
          $q_news = "UPDATE  " . T_NEWS . " set news_scale=" . $ID_new . " WHERE  news_scale=" . $this->ID . ";";
          $result = $sql_object->DBQuery($q_news);
          $affected += $sql_object->DBaffectedRow();
          $q_project = "UPDATE  " . T_PROJECT . " set project_scale_id=" . $ID_new . " WHERE  project_scale_id=" . $this->ID . ";";
          $result = $sql_object->DBQuery($q_project);
          $affected += $sql_object->DBaffectedRow();
          $q_publication = "UPDATE  " . T_PUBLI . " set publi_scale=" . $ID_new . " WHERE  publi_scale=" . $this->ID . ";";
          $result = $sql_object->DBQuery($q_publication);
          $affected += $sql_object->DBaffectedRow();
          $q_sdi = "UPDATE  " . T_SDI_VALUE . " set sdiv_scale=" . $ID_new . " WHERE  sdiv_scale=" . $this->ID . ";";
          $result = $sql_object->DBQuery($q_sdi);
          $affected += $sql_object->DBaffectedRow();
        }
      }
    }
    if ($type == 'MASS_DELETE') {
      $this->getAllRecord($sql_object);
      $this->getScaleDepthAndSon($this->ALL_REC, $this->ID);

      $update_bdd_scale = '';
      $update_bdd_news = '';
      $update_bdd_publi = '';
      $update_bdd_sdi = '';
      for($i = 0; $i < count($this->SON_TABLE); $i++) {
        $update_bdd_scale .= " OR scale_id='" . $this->SON_TABLE[$i] . "'";
        $update_bdd_news .= " OR news_scale='" . $this->SON_TABLE[$i] . "'";
        $update_bdd_publi .= " OR publi_scale='" . $this->SON_TABLE[$i] . "'";
        $update_bdd_sdi .= " OR sdiv_scale='" . $this->SON_TABLE[$i] . "'";
        $update_bdd_project .= " OR project_scale_id='" . $this->SON_TABLE[$i] . "'";
      }
      // Effacement de l'échelle et ses fils
      $q = "UPDATE  " . $this->TDB_SCALE . " set scale_statut='E', scale_last_modify=NOW() WHERE scale_id='" . $this->ID . "'";
      $q .= $update_bdd_scale;
      $q .= ";";

      $result = $sql_object->DBQuery($q);

      if ($result == 1) {
        $q_news = "UPDATE  " . T_NEWS . " SET news_statut='E' WHERE  news_scale='" . $this->ID . "'";
        $q_news .= $update_bdd_news;
        $q_news .= ";";

        $result = $sql_object->DBQuery($q_news);
        $affected += $sql_object->DBaffectedRow();

        $q_project = "UPDATE  " . T_PROJECT . " SET project_statut='E' WHERE  project_scale_id='" . $this->ID . "'";
        $q_project .= $update_bdd_project;
        $q_project .= ";";

        $result = $sql_object->DBQuery($q_project);
        $affected += $sql_object->DBaffectedRow();

        $q_publication = "UPDATE  " . T_PUBLI . " SET publi_statut='E' WHERE  publi_scale='" . $this->ID . "'";
        $q_publication .= $update_bdd_publi;
        $q_publication .= ";";

        $result = $sql_object->DBQuery($q_publication);
        $affected += $sql_object->DBaffectedRow();

        $q_sdi = "UPDATE  " . T_SDI_VALUE . " SET sdiv_statut='E' WHERE  sdiv_scale='" . $this->ID . "'";
        $q_sdi .= $update_bdd_sdi;
        $q_sdi .= ";";

        $result = $sql_object->DBQuery($q_sdi);
        $affected += $sql_object->DBaffectedRow();
      }
    }
    
    // we log delete action
    if($result)	logfile(LOG_MAINFILE, array('[action] delete scale ('.$type.')', 'ID='.$ID, 'ID_new='.$ID_new, 'affected_rows='.$affected, 'by_id='.$l21auth->GetSessionElement('id'), 'by_login='.$l21auth->GetSessionElement('login')));
    
    
    return $affected;
  }
}

?>