<?php
/**
 * CodeIgniter library
 *
 * @category CodeIgniter
 * @license /_licenses/untermStrich/agb_normal.pdf
 * @author Christian Koller
 * @copyright 2009 untermStrich
 * @package libraries
 * @version $Id$
*/

if (!defined('BASEPATH')) { exit('No direct script access allowed'); }

/**
 * Assign values of a stdClass object to the html forms using XAJAX
 *
 * @property    My_Controller           $CI                     The main CI object
 */
class Assign_values
{
    /**
     * Type string
     */
    const T_STRING = 641639823;
    /**
     * Type view only
     */
    const T_VIEW = 5344834;
    /**
     * Type view float only
     */
    const T_VIEW_FLOAT = 326346433;
    /**
     * Type float
     */
    const T_FLOAT = 1844310955;
    /**
     * Type float absolute
     */
    const T_FLOAT_ABS = 1814620954;
    /**
     * Type integer
     */
    const T_INT = 677114532;
    /**
     * Type date (Without time)
     * 
     * Can be either a date string or an UsDate...
     */
    const T_DATE = 172983281;
    /**
     * Type date (Without time)
     *
     * Can be either a time string or an UsTime...
     */
    const T_TIME = 101618271;
    /**
     * Type select
     *
     * This expects, that there exists a value called <b>$from</b><i>_id</i> which holds the id
     * The title is either <b>from</b> or <b>$from</b><i>_name</i>
     */
    const T_SELECT = 816354805;
    const T_SELECT_ADDI = 103364506; //Special for addi list type (US_exmodel::T_LIST)
    /**
     * Type boolean
     */
    const T_BOOL = 16749890;
    /**
     * Type checkboxes
     */
    const T_CHECK = 382543247;
    /**
     * Type radio
     */
    const T_RADIO = 19467294;
    /**
     * Type document
     */
    const T_DOCUMENT = 734921801;
    const T_DIRECTORY_ADDI = 450364107; //Special for addi list type (US_exmodel::T_LIST)
    /**
     * Type image
     *
     * This expects, that there exists a value called <b>$from</b><i>_uri</i>
     */
    const T_IMAGE = 65925279;
    /**
     * Type turnover rate
     *
     * This expects, a float value like 0.2 or 0.19
     */
    const T_PERCENTAGE = 86512540;
    /**
     * Type is a many item field
     * 
     * Parameters to provide:
     *      <ul>
     *          <li>id      string      Name of the value to use as the ID</li>
     *          <li>title   string      Name of the value to use as the title</li>
     *      </ul>
     */
    const T_MANY = 2037716606;
    /**
     * Type markdown
     */
    const T_TEXT_MARKDOWN = 139641823;

    /**
     * Type password
     */
    const T_PASSWORD = 482661467;

    /**
     * Type e-invoice endpoint
     */
    const T_ENDPOINT = 834246255;

    /**
     * Type range
     */
    const T_RANGE = 2078116330;
    
    /**
     * Type ignore
     */
    const T_IGNORE = 30864053;
    
    protected $CI;
    protected $list;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->CI = CI_Controller::get_instance();
        $this->reset();
    }

    /**
     * Reset this object
     *
     * @return  void
     */
    public function reset()
    {
        $this->list = array();
    }

    /**
     * Add a new assign info
     *
     * @param   string  $from   Value name
     * @param   string  $to     Optional Field name without prefix (Else it takes the value name)
     * @param   integer $type   Optional Type of field - One of Assign_values::T_*
     * @param   array   $params Optional Parameters for the defined type (See the description at Assign_values::T_*)
     * @return  void
     */
    public function add($from, $to=null, $type=self::T_STRING, array $params=array())
    {
        $obj = new stdClass();
        $obj->from = $from;
        if ($to===null) {
            $obj->to = $from;
        } else {
            $obj->to = $to;
        }
        $obj->type = $type;
        $obj->params = $params;
        array_push($this->list, $obj);
    }

    /**
     * Assign values to the input fields
     *
     * @param   string          $prefix                 Prefix to add to fields
     * @param   stdClass        $values                 The value object
     * @param   boolean         $require_all_values     Optinal flag to ignore missing values in data object
     * @return  void
     */
    public function assign_all_values($prefix, stdClass $values, $require_all_values=true)
    {
        foreach ($this->list as $item) {
            $from = $item->from;
            if($require_all_values === false && !property_exists($values, $from)) continue;
            switch ($item->type) {
                case self::T_STRING:
                    if (!property_exists($values, $from)) { trigger_error('Assign: String value "'.$from.'" missing in $values'); break;}
                    $this->CI->xajax->assign($prefix.$item->to, 'value', $values->$from!==null ? $values->$from : '' );
                    break;
                case self::T_PASSWORD:
                    if (!property_exists($values, $from)) { trigger_error('Assign: String value "'.$from.'" missing in $values'); break;}
                    $value = US_exmodel::decrypt_password($values->$from);
                    $this->CI->xajax->assign($prefix.$item->to, 'value', $value );
                    break;
                case self::T_ENDPOINT:
                    if (!property_exists($values, $from)) { trigger_error('Assign: String value "'.$from.'" missing in $values'); break;}
                    if(!empty($values->$from)) {
                        $parts = explode(':', $values->$from);
                        if(count($parts)==2) {
                            $this->CI->xajax->assign($prefix.$item->to.'_type', 'value', $parts[0] );
                            $this->CI->xajax->assign($prefix.$item->to, 'value', $parts[1] );
                        } else {
                            $this->CI->xajax->assign($prefix.$item->to, 'value', $parts[0] );
                        }
                    }
                    break;
                case self::T_TEXT_MARKDOWN:
                    if (!property_exists($values, $from)) { trigger_error('Assign: String value "'.$from.'" missing in $values'); break;}
                    $this->CI->xajax->assign($prefix.$item->to, 'value', $values->$from!==null ? $values->$from : '' );
                    $this->CI->xajax->script('$("#'.$prefix.$item->to.'").change();');
                    break;
                case self::T_VIEW:
                    if (!property_exists($values, $from)) { trigger_error('Assign: String value "'.$from.'" missing in $values'); break;}
                    $this->CI->xajax->assign($prefix.$item->to, 'innerHTML', $values->$from ? $values->$from : '' );
                    break;
                case self::T_VIEW_FLOAT:
                    if (!property_exists($values, $from)) { trigger_error('Assign: String value "'.$from.'" missing in $values'); break;}
                    $this->CI->xajax->assign($prefix.$item->to, 'innerHTML', float_to_usnumber($values->$from) );
                    break;
                case self::T_FLOAT:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Float value "'.$from.'" missing in $values'); break;}
                    $this->CI->xajax->assign($prefix.$item->to, 'value', str_replace('&nbsp;', ' ', float_to_usnumber($values->$from)) );
                    break;
                case self::T_FLOAT_ABS:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Float value "'.$from.'" missing in $values'); break;}
                    $this->CI->xajax->assign($prefix.$item->to, 'value', str_replace('&nbsp;', ' ', float_to_usnumber(abs($values->$from))) );
                    break;
                case self::T_INT:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Integer value "'.$from.'" missing in $values'); break;}
                    $this->CI->xajax->assign($prefix.$item->to, 'value', intval($values->$from) );
                    break;
                case self::T_SELECT:
                    $from_id = $from.'_id';
                    $from_name = $from.'_name';
                    if (!property_exists($values, $from_id)) { trigger_error('Assign: Select value "'.$from_id.'" missing in $values'); break;}
                    if (property_exists($values, $from)) {
                        $from_name_val = $values->$from;
                    } else if (property_exists($values, $from_name)) {
                        $from_name_val = $values->$from_name;
                    } else {
                        trigger_error('Assign: Missing select value - either of '.$from.' or '.$from_name.' in $values'); break;
                    }
                    $this->CI->xajax->valOrNew($prefix.$item->to, $values->$from_id, $from_name_val);
                    break;
                case self::T_RADIO:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Radio value "'.$from.'" missing in $values'); break;}
                    $val = ($values->$from !== null) ? $values->$from : 0;
                    $this->CI->xajax->assign($prefix.$item->to.$val, 'checked',  'checked');
                    $this->CI->xajax->script('$("#'.$prefix.$item->to.$val.'").change();');
                    break;
                case self::T_SELECT_ADDI:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Addi select value "'.$from.'" missing in $values'); break;}
                    $this->CI->xajax->valOrNew($prefix.$item->to, $values->$from, $values->$from);
                    break;                    
                case self::T_BOOL:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Boolean value "'.$from.'" missing in $values'); break;}
                    if ($values->$from) {
                        $this->CI->xajax->assign($prefix.$item->to, 'checked',  'checked');
                    }
                    break;
                case self::T_CHECK:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Check value "'.$from.'" missing in $values'); break;}
                    $this->CI->xajax->assign($prefix.$item->to.$values->$from, 'checked', 'checked');
                    break;
                case self::T_DATE:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Date value "'.$from.'" missing in $values'); break;}
                    $date = (is_object($values->$from)) ? $values->$from : new UsDate($values->$from);
                    $this->CI->xajax->assign($prefix.$item->to, 'value', $date->us_date() );
                    break;
                case self::T_TIME:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Time value "'.$from.'" missing in $values'); break;}
                    $date = (is_object($values->$from)) ? $values->$from : new UsTime($values->$from);
                    $this->CI->xajax->assign($prefix.$item->to, 'value', $date->us_stime() );
                    break;
                case self::T_DOCUMENT:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Document value "'.$from.'" missing in $values'); break;}
                    $from_path = $from.'_path';
                    $this->CI->xajax->assign($prefix.$item->to, 'innerHTML', filelink_html(isset($values->$from_path) ? $values->$from_path : $values->$from) );
                    $this->CI->xajax->assign($prefix.$item->to.'__hidden', 'value', $values->$from ); //Set to hidden, important for duplicating an record
                    break;
                case self::T_IMAGE:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Url value "'.$from.'" missing in $values'); break;}
                    if ($values->$from) {
                        $from_uri = $from.'_uri';
                        if (!property_exists($values, $from_uri)) { trigger_error('Assign: Url (_url) value "'.$from_uri.'" missing in $values'); break;}
                        $this->CI->xajax->assign($prefix.$item->to, 'innerHTML', img_html($values->$from_uri) );
                        $this->CI->xajax->assign($prefix.$item->to.'__hidden', 'value', $values->$from ); //Set to hidden, important for duplicating an record
                    } else {
                        $this->CI->xajax->assign($prefix.$item->to, 'innerHTML', '' );
                    }
                    break;
                case self::T_DIRECTORY_ADDI:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Document value "'.$from.'" missing in $values'); break;}
                    $this->CI->xajax->assign($prefix.$item->to, 'value', $values->$from );
                    $this->CI->xajax->assign($prefix.$item->to.'_link', 'innerHTML', filelink_html($values->$from) );
                    break;                    
                case self::T_MANY:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Many value(s) "'.$from.'" missing in $values'); break;}
                    $params_id = $item->params['id'];
                    $params_title = $item->params['title'];
                    $item_string = ' ';
                    foreach ($values->$from as $item_values) {
                        $class = isset($item_values->class) ? $item_values->class : '';
                        $item_string .= manylist_elem_html($prefix.$item->to, $item_values->$params_title, $item_values->$params_id, $class);
                    }
                    $this->CI->xajax->script('$("#'.$prefix.$item->to.'").html("'.$item_string.'");');
                    $this->CI->xajax->script('basicForm.manyField.highlight_top($("#'.$prefix.$item->to.'"));');
                    break;
                case self::T_PERCENTAGE:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Percentage value "'.$from.'" missing in $values'); break;}
                    $this->CI->xajax->assign($prefix.$item->to, 'value', float_to_usnumber($values->$from*100) );
                    break;
                case self::T_RANGE:
                    if (!property_exists($values, $from)) { trigger_error('Assign: Range value "'.$from.'" missing in $values'); break;}
                    $val = ($values->$from !== null) ? $values->$from : 0;
                    $this->CI->xajax->script('$("#'.$prefix.$item->to.'").val('.$val.').change();');
                    break;
                case self::T_IGNORE:
                    break;
                default:
                    basic_error('Unknown type '.$item->type, null, __CLASS__.'::'.__METHOD__);
            }
        }
    }

    /**
     * Assign values as derived values
     *
     * Get values within javascript using:
     * <code>$('#the_field_id').data('parent');</code>
     * And the input type using:
     * <code>$('#the_field_id').data('type');</code>
     *
     * @param   string      $prefix Prefix to add to fields
     * @param   stdClass    $values The value object
     * @return  void
     */
    public function assign_derive_values($prefix, stdClass $values)
    {
        foreach ($this->list as $item) {
            $from = $item->from;
            switch ($item->type) {
                case self::T_STRING:
                case self::T_PASSWORD:
                    $val = $values->$from;
                    break;
                case self::T_TEXT_MARKDOWN:
                    $val = $values->$from;
                    break;
                case self::T_DOCUMENT:
                    $val = $values->$from;
                    break;
                case self::T_FLOAT:
                    $val = float_to_usnumber($values->$from);
                    break;
                case self::T_INT:
                    $val = intval($values->$from);
                    break;
                case self::T_SELECT:
                    $from_id = $from.'_id';
                    $from_name = $from.'_name';
                    if (property_exists($values, $from)) {
                        $from_name_val = $values->$from;
                    } else if (property_exists($values, $from_name)) {
                        $from_name_val = $values->$from_name;
                    } else {
                        basic_error('Missing: Either of '.$from.' or '.$from_name.' in '.print_r($values, true), null, __CLASS__.'::'.__METHOD__);
                    }
                    $val = array(
                        $values->$from_id,
                        $from_name_val
                    );
                    break;
                case self::T_BOOL:
                    $val = ($values->$from) ? true : false;
                    break;
                case self::T_CHECK:
                    basic_error('T_CHECK Not implemented', null, __CLASS__.'::'.__METHOD__);
                    break;
                case self::T_DATE:
                    $date = (is_object($values->$from)) ? $values->$from : new UsDate($values->$from);
                    $val = $date->us_date();
                    break;
                case self::T_TIME:
                    $date = (is_object($values->$from)) ? $values->$from : new UsTime($values->$from);
                    $val = $date->us_stime();
                    break;
                case self::T_IMAGE:
                    $from_uri = $from.'_uri';
                    $val = array(
                        $values->$from,
                        $values->$from_uri
                    );
                    break;
                case self::T_MANY:
                    $params_id = $item->params['id'];
                    $params_title = $item->params['title'];
                    $val = array();
                    foreach ($values->$from as $item_values) {
                        $val[$item_values->$params_id] = $item_values->$params_title;
                    }
                    break;
                case self::T_PERCENTAGE:
                    basic_error('T_PERCENTAGE Not implemented', null, __CLASS__.'::'.__METHOD__);
                    break;
                default:
                    basic_error('Unknown type '.$item->type, null, __CLASS__.'::'.__METHOD__);
            }
            $this->CI->xajax->script('$("#'.$prefix.$item->to.'").data("parent", '.us_json_encode($val, true).')');
        }
    }

} // END class Assign_values
