<?php

/**
 * Project : Memento Plus
 * Developped at TAEMA, Air Liquide Santé
 * Creation date : August 2004
 * 
 * @author david.han-sze-chuen
School : ISTY 
filename : class_MPSubProperty.inc.php
Description : the MPSubProperty class definition 
 */

/**
 * Role : this class stores some type dependant data about a field's definition.
 * 
 * Example of a property string :
 *                                  "time_type=date;read_only=yes;internal_system_use=true;"
 * 
 * NOTE : <prop_name>=<prop_val>;
 * prop_val is encoded with rawurlencode().
 * 
 * Abilities :
 * - construction based on a "properties" string of a field_conf row
 * - check if the properties string has a good syntax
 * - can generate a properties string : toString()
 * - should check coherence of data because some properties aren't available 
 *                                     for every type of field
 */
class MPSubProperty {
	// //////////////////////////////////////////////////////////////////////////////
	// Definition of local attributes
	// //////////////////////////////////////////////////////////////////////////////
	/**
	 * Known property names : maxlen unique time_type declare hidden dashAfter label read_only internal_system_use highlight_url
	 */
	// ordered by property type
	var $_type_numeric = array("maxlen", "int_size", "decimal_size");
	var $_type_bool = array("declare", "hidden", "dashAfter", "label", "read_only", "unique", "internal_system_use", "highlight_url");
	var $_type_enum = array("time_type" => array("date", "hour", "time"));
	var $_other_type = array("SB_twin_id","hidden_states");
	/**
	 * For a text property.
	 * The max length of a text field is : 0-255
	 * 0=means infinite
	 */
	var $maxlen = null;
	var $maxlen_min = 0;
	var $maxlen_max = 255;

	/**
	 * For a numeric property.
	 * The max number of a int digits is : 0-18   
	 * Note that it's an arbitrary choice
	 * 0=means default database value
	 */
	var $int_size = null;
	var $int_size_min = 0;
	var $int_size_max = 12;

	/**
	 * For a numeric property.
	 * The max number of a decimal digits is : 0-18
	 * Note that it's an arbitrary choice
	 * 0=means default database value
	 */
	var $decimal_size = null;
	var $decimal_size_min = 0;
	var $decimal_size_max = 12;

	/**
	 * For a selectbox. 
	 * If true, each value must be unique.
	 * true/false only
	 */
	var $unique = null;

	/**
	 * For a time field.
	 * time_type = "date"/"hour"/"time"
	 */
	var $time_type = null;

	/**
	 * For any field.
	 * If true, a field value cannot be modified in the edit form.
	 * true/false only
	 */
	var $read_only = null;
	var $declare = null;
	var $hidden = null;
	var $dashAfter = null;
	var $label = null;
	var $hidden_states = null;
	var $hidden_fields = array();

	/**
	 * For any field.
	 * If true, in the field configuration form, a visible warning is printed
	 * to inform the administrator not to modify structural data like length, 
	 * type, or other secondary properties. Modifies are at his own risk.
	 * 
	 * true/false only
	 */
	var $internal_system_use = null;

	/**
	 * For text field.
	 * If true, the field title is made linkable to a web destination.
	 * The URL is made with the field value. Some special URL treatments are 
	 * also made on it.
	 * 
	 * true/false only
	 */
	var $highlight_url = null; 
	// //////////////////////////////////////////////////////////////////////////////
	// Methods
	// //////////////////////////////////////////////////////////////////////////////
	/**
	 * * Class object constructor
	 * 
	 * @param string $prop The string representing a MPSubProperty object
	 */
	function MPSubProperty($prop = null) {
		if (trim($prop))
			if ($this->setSubProperties($prop) === false) {
				br();
				death("OBJECT_CONSTRUCTION_ERROR", "Construction of a MPSubProperty object failed because one input parameter was incorrect.");
			} 
		} // end of constructor                                 
		// //////////////////////////////////////////////////////////////////////////////
		/**
		 * Analyse the string parameter, retrieve data and fetch it into the object attributes.
		 * 
		 * @param string $prop 
		 */
		function setSubProperties($prop) {
			global $STRING;
			if (empty($prop)) {
				return false;
			} else {
				// example : "time_type=date;read_only=yes;internal_system_use=true;"
				$parts = explode(";", $prop); // catch the ';'
				foreach($parts as $part_key => $part) {
					if ($part == null) {
						continue;
					} 
					list($prop_name, $prop_val) = explode("=", $part); // catch the '='            
					$prop_val = rawurldecode($prop_val); // the value must be decoded              
					// DEBUG
					// println("name = $prop_name <br> val = $prop_val <br>");
					// is it a good property name ?
					// check value with the type
					if (in_array($prop_name, $this->_type_bool)) { // is it a boolean ?
						switch (strtolower($prop_val)) {
							case '1':
							case $STRING['YES'] :
							case "yes" :
							case "true" :
								$this->$prop_name = true;
								break;
							case '0':
							case $STRING['NO'] :
							case "no" :
							case "false" :
								$this->$prop_name = false;
								break;
							default:
								death("BAD_VALUE", "setSubProperties() : the value of $prop_name isn't 'true' nor 'false'.");
								return false;
						} 
					} elseif (in_array($prop_name, array_keys($this->_type_enum))) { // is it an enumeration ?
						if (in_array($prop_val, $this->_type_enum[$prop_name])) { // is the value in the enumeration ?
							$this->$prop_name = $prop_val; // copy value        
							// DEBUG
							// println("Enum value found : $prop_name = {$this->$prop_name}");
						} else {
							death("BAD_VALUE", "setSubProperties() : the value of $prop_name isn't in the defined enumeration.");
							return false;
						} 
					} elseif (in_array($prop_name, $this->_type_numeric)) { // is it an integer ?
						$val = intval($prop_val); // copy int value        
						// ex: $prop_name = "maxlen", we'll get $maxlen_min, which must be declared in the class
						$min = $prop_name . "_min"; // get the min value
						$min = $this->$min;
						$max = $prop_name . "_max"; // get the max value
						$max = $this->$max; 
						// DEBUG
						// println("int type : value is $val, min/max = $min/$max");
						// check value's range
						if (($val >= $min) && ($val <= $max)) {
							$this->$prop_name = $val;
						} else {
							death("BAD_VALUE", "setSubProperties() : the int value ($val) of $prop_name isn't in the good range[$min, $max].");
							return false;
						} 
					} elseif (in_array($prop_name, $this->_other_type)) 
					{ // is it an other known type ?
						$this->$prop_name = $prop_val; // copy value 
						if ($prop_name=='hidden_states' and !empty($prop_val))
						{

							$prop_val=str_replace("_sep_",";", "$prop_val");
							$this->hidden_fields = unserialize($prop_val); // extrat value for bugdisplay.html
						}
					} else {
						death("BAD_VALUE", "setSubProperties() : '$prop_name' is unknown.");
						return false;
					} 
				} 

				return true;
			} 
		} // end of setSubProperties($prop)                   
		// //////////////////////////////////////////////////////////////////////////////
		/**
		 * * Convert this object into string. Can be read by setSubProperties()
		 * 
		 * @param boolean $toPrint If true, echo the string instead of returning it. If so, the function will return true.
		 * @param boolean $inHTML HTML format
		 * @return mixed A string representation of this object, or true if it has been printed.
		 */
		function toString($toPrint = false, $inHTML = false) {
			$s = "";
			$txt = '';
			$prop_list = array(); 
			// for int properties
			foreach($this->_type_numeric as $foo => $name) {
				if (isset($this->$name)) { // is it set ?
					// no need to encode, it's an int value
					// $val = rawurlencode($this->$name);
					if ($inHTML)
						$prop_list[] = "{$name}={$this->$name}";
					else
						$s .= "{$name}={$this->$name};";
				} 
			} 
			// for TwninBox properties
			foreach($this->_other_type as $foo => $name) {
				if (isset($this->$name)) { // is it set ?
					// no need to encode, it's an int value
					// $val = rawurlencode($this->$name);
					if ($inHTML)
						$prop_list[] = "{$name}={$this->$name}";
					else
						$s .= "{$name}={$this->$name};";
				} 
			} 
			// for bool properties
			foreach($this->_type_bool as $foo => $name) {
				if (isset($this->$name)) { // is it set ?
					// no need to encode, it's either 'true' or 'false'
					if ($inHTML)
						$prop_list[] = "{$name}=" . (($this->$name === true)? 'true':'false');
					else
						$s .= "{$name}=" . (($this->$name === true)? 'true':'false') . ';';
				} 
			} 
			// for enum properties
			foreach($this->_type_enum as $name => $foo) {
				if (isset($this->$name)) { // is it set ?
					$val = rawurlencode($this->$name); // encode enum string				       
					// DEBUG
					// println("print enum val : $name = $val");
					if ($inHTML)
						$prop_list[] = "{$name}={$val}";
					else
						$s .= "{$name}={$val};";
				} 
			} 

			if ($inHTML) {
				$s = textlist($prop_list, $cmdtype = 11, $option = '');
			} 

			if ($toPrint)
				echo $s;
			else
				return $s;
		} // end of toString($toPrint = false, $inHTML = false) 
		// ////////////////////////////////////////////////////////////////////////////
		/**
		 * Convert an associative array into a MPSubProperty string
		 */
		function convert_array_to_string($s) {
			$str_sp = '';
			foreach($s as $k => $v) {
				$str_sp .= "{$k}=" . rawurlencode(stripslashes($v)) . ';';
			} 
			return $str_sp;
		} // end of convert_array_to_string($s) 
		// ////////////////////////////////////////////////////////////////////////////
	} // enf of class MPSubProperty
	/**
	 * Convert a string representing a subproperty into HTML
	 */
	function MPSubProperty_to_html($string) {
		$ob = &new MPSubProperty($string);
		return $ob->toString(false, true);
	} // end of MPSubProperty_to_html($string)

	?>
