<?php
/*
 * @version $Id: rulecriteria.class.php 19672 2012-11-21 09:12:34Z moyo $
 -------------------------------------------------------------------------
 GLPI - Gestionnaire Libre de Parc Informatique
 Copyright (C) 2003-2012 by the INDEPNET Development Team.

 http://indepnet.net/   http://glpi-project.org
 -------------------------------------------------------------------------

 LICENSE

 This file is part of GLPI.

 GLPI is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 GLPI is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with GLPI. If not, see <http://www.gnu.org/licenses/>.
 --------------------------------------------------------------------------
 */

// ----------------------------------------------------------------------
// Original Author of file: Walid Nouh
// Purpose of file:
// ----------------------------------------------------------------------
if (!defined('GLPI_ROOT')) {
   die("Sorry. You can't access directly to this file");
}

/// Criteria Rule class
class RuleCriteria extends CommonDBChild {

   // From CommonDBChild
   public $items_id  = 'rules_id';
   public $dohistory = true;


   function __construct($rule_type='Rule') {
      $this->itemtype = $rule_type;
   }


   /**
    * Get title used in rule
    *
    * @return Title of the rule
   **/
   static function getTypeName($nb=0) {
      global $LANG;

      if ($nb>1) {
         return $LANG['rulesengine'][6];
      }
      return $LANG['rulesengine'][16];
   }


   function getName($with_comment=0) {

      $rule = new $this->itemtype();
      return Html::clean($rule->getMinimalCriteriaText($this->fields));
   }


   function getSearchOptions() {
      global $LANG;

      $tab = array();
      $tab[1]['table']         = $this->getTable();
      $tab[1]['field']         = 'criteria';
      $tab[1]['name']          = $LANG['rulesengine'][6];
      $tab[1]['massiveaction'] = false;
      $tab[1]['datatype']      = 'string';

      $tab[2]['table']         = $this->getTable();
      $tab[2]['field']         = 'condition';
      $tab[2]['name']          = $LANG['rulesengine'][14];
      $tab[2]['massiveaction'] = false;
      $tab[2]['datatype']      = 'string';

      $tab[3]['table']         = $this->getTable();
      $tab[3]['field']         = 'pattern';
      $tab[3]['name']          = $LANG['rulesengine'][15];
      $tab[3]['massiveaction'] = false;
      $tab[3]['datatype']      = 'string';

      return $tab;
   }


   /**
    * Get all criterias for a given rule
    *
    * @param $ID the rule_description ID
    *
    * @return an array of RuleCriteria objects
   **/
   function getRuleCriterias($ID) {
      global $DB;

      $sql = "SELECT *
              FROM `glpi_rulecriterias`
              WHERE `rules_id` = '$ID'
              ORDER BY `id`";
      $result = $DB->query($sql);

      $rules_list = array();
      while ($rule = $DB->fetch_assoc($result)) {
         $tmp          = new RuleCriteria();
         $tmp->fields  = $rule;
         $rules_list[] = $tmp;
      }

      return $rules_list;
   }


   /**
    * Try to match a definied rule
    *
    * @param $criterion RuleCriteria object
    * @param $field the field to match
    * @param $criterias_results
    * @param $regex_result
    *
    * @return true if the field match the rule, false if it doesn't match
   **/
   static function match(RuleCriteria &$criterion, $field, &$criterias_results, &$regex_result) {

      $condition = $criterion->fields['condition'];
      $pattern   = $criterion->fields['pattern'];
      $criteria  = $criterion->fields['criteria'];

      //If pattern is wildcard, don't check the rule and return true
      //or if the condition is "already present in GLPI" : will be processed later
      if ($pattern == Rule::RULE_WILDCARD || $condition == Rule::PATTERN_FIND) {
         return true;
      }

      // Input are slashed protected, not output.
      if (is_array($field)) {
         $field = Toolbox::stripslashes_deep($field);
      } else {
         // Trim for remove keyboard errors
         $field = stripslashes(trim($field));
      }

      $pattern = trim($pattern);

      if ($condition != Rule::REGEX_MATCH && $condition != Rule::REGEX_NOT_MATCH) {
         //Perform comparison with fields in lower case
         $field   = Toolbox::strtolower($field);
         $pattern = Toolbox::strtolower($pattern);
      }

      switch ($condition) {
         case Rule::PATTERN_EXISTS :
            return (!empty($field));

         case Rule::PATTERN_DOES_NOT_EXISTS :
            return (empty($field));

         case Rule::PATTERN_IS :
            if (is_array($field)) {
               // Special case (used only by UNIQUE_PROFILE, for now)
               if (in_array($pattern, $field)) {
                  $criterias_results[$criteria] = $pattern;
                  return true;
               }
            } else if ($field == $pattern) {
               $criterias_results[$criteria] = $pattern;
               return true;
            }
            return false;

         case Rule::PATTERN_IS_NOT :
            if ($field != $pattern) {
               $criterias_results[$criteria] = $pattern;
               return true;
            }
            return false;

         case Rule::PATTERN_UNDER :
            // If criteria begin with _ strip it
            if ($criteria[0] == '_') {
               $criteria = substr($criteria, 1);
            }
            $table  = getTableNameForForeignKeyField($criteria);
            $values = getSonsOf($table, $pattern);
            if (isset($values[$field])) {
               return true;
            }
            return false;

         case Rule::PATTERN_NOT_UNDER :
            // If criteria begin with _ strip it
            if ($criteria[0] == '_') {
               $criteria = substr($criteria, 1);
            }
            $table  = getTableNameForForeignKeyField($criteria);
            $values = getSonsOf($table, $pattern);
            if (isset($values[$field])) {
               return false;
            }
            return true;

         case Rule::PATTERN_END :
            $value = "/".$pattern."$/";
            if (preg_match($value, $field) > 0) {
               $criterias_results[$criteria] = $pattern;
               return true;
            }
            return false;

         case Rule::PATTERN_BEGIN :
            if (empty($pattern)) {
               return false;
            }
            $value = strpos($field,$pattern);
            if (($value !== false) && $value == 0) {
               $criterias_results[$criteria] = $pattern;
               return true;
            }
            return false;

         case Rule::PATTERN_CONTAIN :
            if (empty($pattern)) {
               return false;
            }
            $value = strpos($field,$pattern);
            if (($value !== false) && $value >= 0) {
               $criterias_results[$criteria] = $pattern;
               return true;
            }
            return false;

         case Rule::PATTERN_NOT_CONTAIN :
            if (empty($pattern)) {
               return false;
            }
            $value = strpos($field,$pattern);
            if ($value === false) {
               $criterias_results[$criteria] = $pattern;
               return true;
            }
            return false;

         case Rule::REGEX_MATCH :
            $results = array();
            // Permit use < and >
            $pattern = Toolbox::unclean_cross_side_scripting_deep($pattern);
            if (preg_match($pattern."i",$field,$results)>0) {
               // Drop $result[0] : complete match result
               array_shift($results);
               // And add to $regex_result array
               $regex_result[] = $results;
               $criterias_results[$criteria] = $pattern;
               return true;
            }
            return false;

         case Rule::REGEX_NOT_MATCH :
            // Permit use < and >
            $pattern = Toolbox::unclean_cross_side_scripting_deep($pattern);
            if (preg_match($pattern."i", $field) == 0) {
               $criterias_results[$criteria] = $pattern;
               return true;
            }
            return false;

         case Rule::PATTERN_IS_EMPTY :
         case Rule::PATTERN_FIND :
            // Global criteria will be evaluated later
            return true;
      }
      return false;
   }


   /**
    * Return the condition label by giving his ID
    *
    * @param $ID condition's ID
    * @param $itemtype itemtype
    * @param $criterion
    *
    * @return condition's label
   **/
   static function getConditionByID($ID, $itemtype, $criterion='') {

      $conditions = self::getConditions($itemtype, $criterion);
      if (isset($conditions[$ID])) {
         return $conditions[$ID];
      }
      return "";
   }


   /**
    * @param $itemtype itemtype
    * @param $criterion
    *
    * @return array of criteria
   **/
   static function getConditions($itemtype, $criterion='') {
      global $LANG;

      $criteria =  array(Rule::PATTERN_IS              => $LANG['rulesengine'][0],
                         Rule::PATTERN_IS_NOT          => $LANG['rulesengine'][1],
                         Rule::PATTERN_CONTAIN         => $LANG['search'][2],
                         Rule::PATTERN_NOT_CONTAIN     => $LANG['rulesengine'][3],
                         Rule::PATTERN_BEGIN           => $LANG['rulesengine'][4],
                         Rule::PATTERN_END             => $LANG['rulesengine'][5],
                         Rule::REGEX_MATCH             => $LANG['rulesengine'][26],
                         Rule::REGEX_NOT_MATCH         => $LANG['rulesengine'][27],
                         Rule::PATTERN_EXISTS          => $LANG['rulesengine'][31],
                         Rule::PATTERN_DOES_NOT_EXISTS => $LANG['rulesengine'][32]);

      $extra_criteria = call_user_func(array($itemtype,'addMoreCriteria'),$criterion);

      foreach ($extra_criteria as $key => $value) {
         $criteria[$key] = $value;
      }
      /// Add Under criteria if tree dropdown table used
      $item = new $itemtype();
      $crit = $item->getCriteria($criterion);

      if (isset($crit['type']) && $crit['type'] == 'dropdown') {
         $crititemtype = getItemtypeForTable($crit['table']);
         if (($item = getItemForItemtype($crititemtype))
             && $item instanceof CommonTreeDropdown) {
            $criteria[Rule::PATTERN_UNDER]     = $LANG['search'][3];
            $criteria[Rule::PATTERN_NOT_UNDER] = $LANG['search'][7];
         }
      }

      return $criteria;
   }


   /**
    * Display a dropdown with all the criterias
   **/
   static function dropdownConditions($itemtype, $params=array()) {
      global $LANG;

      $p['criterion']        = '';
      $p['allow_conditions'] = array();
      $p['value']            = '';

      foreach ($params as $key => $value) {
         $p[$key] = $value;
      }
      $elements = array();
      foreach (self::getConditions($itemtype, $p['criterion']) as $pattern => $label) {
         if (empty($p['allow_conditions'])
             || (!empty($p['allow_conditions']) && in_array($pattern,$p['allow_conditions']))) {
            $elements[$pattern] = $label;
         }
      }
      return Dropdown::showFromArray('condition', $elements, array('value' => $p['value']));
   }

}

?>
