<?php
/**
 * @author  She Yi [email protected]
 * @copyright HiGrid.net
 * @version 2.1
 * @package higridCharts
 *
 * @abstract
 * A PHP class to work with higridCharts jQuery plugin.
 *
 */
class higridCharts
{
    public 
$version '2.1';
    
/**
     * Stores all the chart options
     * @var array
     */
    
private $coptions = array();
    
/**
     * Stores the connection in case of Db data
     * @var resource
     */
    
private $connhigridhigrid;
    
/**
     * Stores the database type - i.e mysql, postgres etc.
     * @var string
     */
    
private $dbtype;
    
/**
     * Javascript code to be executed aftere the chart render
     * @var string
     */
    
private $jscode;
    
/**
     * index of the series
     * @var integer
     */
    
private $i_serie_index;
    
/**
     * Contain the name of the theme.
     * @var string 
     */
    
private $theme '';
    function 
__construct($db=null) {
        if(
class_exists('hiGridDB') && $db)
            
$interface hiGridDB::getInterface();
        else
            
$interface 'chartarray';
        
$this->conn $db;
        if(
$interface == 'pdo')
        {
            try {
                
$this->conn->setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION);
                
$this->dbtype $this->conn->getAttribute(PDO::ATTR_DRIVER_NAME);
            } catch (
Exception $e) {
                
            }
        } else {
            
$this->dbtype $interface;
        }
        
# Set Default Values
        
$this->coptions['credits']['enabled'] = false;
        
$this->coptions['chart']['renderTo'] = '';
        
$this->coptions['series'] = array();
        
$this->i_serie_index 0;
        
$this->jscode false;
    }
    protected function 
convertVar($value$type)
    {
        switch (
$type)
        {
            case 
'int':
                return (int)
$value;
            case 
'numeric':
                return (float)
$value;
            default :
                return 
$value;
        }
    }
    
/**
     * Return a array representation of the sql query. Also return only the
     * the values of the first column
     * @param string $sql The sql query string
     * @param array $params array of parameters passed to the query
     * @param mixed $limit the number of records to retrieve. if false - all
     * @param number $offset how many record to skip. 0 - none
     * @return array of the values of the first column of the query
     */
    
protected function getSQLSerie($sql$params=null$limit false$offset=0)
    {
        
$retarr = array();
        if(
$this->dbtype != 'chartarray' && $this->conn)
        {
            try {
                if(
$limit && $limit 0) {
                    
$sql hiGridDB::limit($sql$this->dbtype$limit$offset );
                }
                
$sersql hiGridDB::prepare($this->conn$sql$paramstrue);
                
hiGridDB::execute($sersql$params);
                
$xy false;
                
$ncols hiGridDB::columnCount($sersql);
                if(
$ncols 1) {
                    
$xy true;
                }
                for (
$i=0$i $ncols$i++) {
                    
$field hiGridDB::getColumnMeta($i,$sersql);
                    
$typearr[$i] = hiGridDB::MetaType($field$this->dbtype);
                }
                while(
$r hiGridDB::fetch_num($sersql) )
                {
                    
$retarr[] = $xy ? array($this->convertVar($r[0],$typearr[0]) ,$this->convertVar($r[1],$typearr[1])) : $this->convertVar($r[0],$typearr[0]);
                }
                
hiGridDB::closeCursor($sersql);
            } catch (
Exception $e) {
                echo 
$e->getMessage();
                return 
false;
            }
        }
        return 
$retarr;
    }
    
/**
     * Return all the option for the Chart
     * @return array 
     */
    
public function getChartOptions()
    {
        return 
$this->coptions;
    }
    
/**
     * Options regarding the chart area and plot area as well as general chart options.
     *
     * @param mixed $name the option name for the chart. Can be a string or array.
     * When used as array a key value pair should be defined, where the key is the name
     * @param mixed $mixvalue is the value option in case the name is string
     * @return higridCharts instance
     */
    
public function HCsCO($name$mixvalue='')
    {
        if(
$mixvalue == '') {
            if(
is_array($name) && count($name) > ) {
                foreach(
$name as $key =>$val)
                {
                    
$this->coptions['chart'][$key] = $val;
                }
            }
        } else {
            
$name trim($name);
            if(
$name != ''){
                
$this->coptions['chart'][$name] = $mixvalue;
            }
        }
        return 
$this;
    }
    
    
/**
     * Set event listeners for the chart.
     *
     * @param string $name The name of the event, Can be click, load, redraw, selection
     * See documentation for more details
     * @param string $jscode The javascript code associated with this event
     * @return higridCharts  instance
     */
    
public function HCsCE($name$jscode)
    {
        
$name trim($name);
        if(
$name != ''){
            
$this->coptions['chart']['events'][$name] = "js:".$jscode;
        }
        return 
$this;
    }
    
/**
     * Set array containing the default colors for the chart's series.
     * When all colors are used, new colors are pulled from the start again.
     * Defaults to:
     * array('#4572A7', '#AA4643', '#89A54E', '#80699B', '#3D96AE', '#DB843D', '#92A8CD', '#A47D7C',     '#B5CA92')
     * @param array $avalue values to be set for the colors
     * @return higridCharts instance
     */
    
public function setColors($avalue){
        if(
is_array($avalue) && count($avalue) > 0){
            
$this->coptions['colors'] = $avalue;
        }
        return 
$this;
    }
    
/**
     * Set HTML labels that can be positioined anywhere in the chart area.
     *
     * @param mixed $name the option name for the label. Can be a string or array.
     * When used as array a key value pair should be defined, where the key is the name
     * @param mixed $mixvalue a value in case the name is a string
     * @return higridCharts instance
     */
    
public function setLabels($name$mixvalue=''){
        if(
$mixvalue == '') {
            if(
is_array($name) && count($name) > ) {
                foreach(
$name as $key =>$val)
                {
                    
$this->coptions['labels'][$key] = $val;
                }
            }
        } else {
            
$name trim($name);
            if(
$name != ''){
                
$this->coptions['labels'][$name] = $mixvalue;
            }
        }
        return 
$this;
    }
    
/**
     * Set a language object. The default language is English. For detailed info on the
     * object rehfer to the documentation
     *
     * @param mixed $name the option name for the language. Can be a string or array.
     * When used as array a key value pair should be defined, where the key is the name
     * @param mixed $mixvalue a value in case the name is a string
     * @return higridCharts instance
     */
    
public function setLanguage($name$mixvalue=''){
        if(
$mixvalue == '') {
            if(
is_array($name) && count($name) > ) {
                foreach(
$name as $key =>$val)
                {
                    
$this->coptions['lang'][$key] = $val;
                }
            }
        } else {
            
$name trim($name);
            if(
$name != ''){
                
$this->coptions['lang'][$name] = $mixvalue;
            }
        }
        return 
$this;
    }
    
/**
     * Set the legend. The legend is a box containing a symbol and name for
     * each series item or point item in the chart.
     *
     * @param mixed $name the option name for the legend. Can be a string or array.
     * When used as array a key value pair should be defined, where the key is the name
     * @param mixed $mixvalue a value option in case the name is a string
     * @return higridCharts instance
     */
    
public function HCsL($name$mixvalue=''){
        if(
$mixvalue == '') {
            if(
is_array($name) && count($name) > ) {
                foreach(
$name as $key =>$val)
                {
                    
$this->coptions['legend'][$key] = $val;
                }
            }
        } else {
            
$name trim($name);
            if(
$name != ''){
                
$this->coptions['legend'][$name] = $mixvalue;
            }
        }
        return 
$this;
    }
    
/**
     * Set the loading options which control the appearance of the loading
     * screen that covers the plot area on chart operations
     *
     * @param mixed $name the option name for the loading. Can be a string or array.
     * When used as array a key value pair should be defined, where the key is the name
     * @param mixed $mixvalue a value option in case the name is a string
     * @return higridCharts instance
     */
    
public function setLoading($name$mixvalue ''){
        if(
$mixvalue == '') {
            if(
is_array($name) && count($name) > ) {
                foreach(
$name as $key =>$val)
                {
                    
$this->coptions['loading'][$key] = $val;
                }
            }
        } else {
            
$name trim($name);
            if(
$name != ''){
                
$this->coptions['loading'][$name] = $mixvalue;
            }
        }
        return 
$this;
    }
    
/**
     * Set the plot options for the chart.
     * The plotOptions is a wrapper object for config objects for each series type.
     * The config objects for each series can also be overridden for each
     * series item as given in the series array
     * @param mixed $name the name of tyhe option as per documentation
     * @param array $avalue array of options = key value pair
     * @return higridCharts
     */
    
public function HCsPO($name$avalue=''){
        if(
$avalue == '') {
            if(
is_array($name) && count($name) > ) {
                foreach(
$name as $key =>$val)
                {
                    
$this->coptions['plotOptions'][$key] = $val;
                }
            }
        } else {
            
$name trim($name);
            if(
$name != ''){
                if(
is_array($avalue) && count($avalue) > 0){
                    
$this->coptions['plotOptions'][$name] = $avalue;
                }
            }
        }
        return 
$this;
    }
    
/**
     * Set the subtitle of the chart
     * 
     * @param mixed $name the option name for the loading. Can be a string or array.
     * When used as array a key value pair should be defined, where the key is the name
     * @param mixed $mixvalue a value option in case the name is a string
     * @return higridCharts instance
     */
    
public function HCsST($name$mixvalue=''){
        if(
$mixvalue == '') {
            if(
is_array($name) && count($name) > ) {
                foreach(
$name as $key =>$val)
                {
                    
$this->coptions['subtitle'][$key] = $val;
                }
            }
        } else {
            
$name trim($name);
            if(
$name != ''){
                
$this->coptions['subtitle'][$name] = $mixvalue;
            }
        }
        return 
$this;
    }
    
/**
     * Set the main title of the chart
     *
     * @param mixed $name the option name for the loading. Can be a string or array.
     * When used as array a key value pair should be defined, where the key is the name
     * @param mixed $mixvalue a value option in case the name is a string
     * @return higridCharts instance
     */
    
public function HCsT($name$mixvalue=''){
        if(
$mixvalue == '') {
            if(
is_array($name) && count($name) > ) {
                foreach(
$name as $key =>$val)
                {
                    
$this->coptions['title'][$key] = $val;
                }
            }
        } else {
            
$name trim($name);
            if(
$name != ''){
                
$this->coptions['title'][$name] = $mixvalue;
            }
        }
        return 
$this;
    }
    
/**
     * Set options for the tooltip that appears when the user hovers over a series or point
     * 
     * @param mixed $name the option name for the loading. Can be a string or array.
     * When used as array a key value pair should be defined, where the key is the name
     * @param mixed $mixvalue a value option in case the name is a string
     * @return higridCharts instance
     */
    
public function HCsTT($name$mixvalue=''){
        if(
$mixvalue == '') {
            if(
is_array($name) && count($name) > ) {
                foreach(
$name as $key =>$val)
                {
                    if(
$key=='formatter'$val "js:".$val;
                    
$this->coptions['tooltip'][$key] = $val;
                }
            }
        } else {
            
$name trim($name);
            if(
$name != ''){
                if(
$name=='formatter'$mixvalue "js:".$mixvalue;
                
$this->coptions['tooltip'][$name] = $mixvalue;
            }
        }
        return 
$this;
    }
    
/**
     * Set the X axis or category axis. Normally this is the horizontal axis,
     * though if the chart is inverted this is the vertical axis.
     * In case of multiple axes, the xAxis node is an array of configuration objects.
     *
     * @param mixed $name the option name for the loading. Can be a string or array.
     * When used as array a key value pair should be defined, where the key is the name
     * @param mixed $mixvalue a value option in case the name is a string
     * @return higridCharts instance
     */
    
public function HCsX($name$mixvalue=''){
        if(
$mixvalue == '') {
            if(
is_array($name) && count($name) > ) {
                foreach(
$name as $key =>$val)
                {
                    
$this->coptions['xAxis'][$key] = $val;
                }
            }
        } else {
            
$name trim($name);
            if(
$name != ''){
                
$this->coptions['xAxis'][$name] = $mixvalue;
            }
        }
        return 
$this;
    }
    
/**
     * Set the Y axis or value axis. Normally this is the vertical axis, though
     * if the chart is inverted this is the horiontal axis. In case of multiple
     * axes, the yAxis node is an array of configuration objects.
     *
     * @param mixed $name the option name for the loading. Can be a string or array.
     * When used as array a key value pair should be defined, where the key is the name
     * @param mixed $mixvalue a value option in case the name is a string
     * @return higridCharts instance
     */
    
public function HCsY($name$mixvalue=''){
        if(
$mixvalue === '') {
            if(
is_array($name) && count($name) > ) {
                foreach(
$name as $key =>$val)
                {
                    
$this->coptions['yAxis'][$key] = $val;
                }
            }
        } else {
            
$name trim($name);
            if(
$name != ''){
                
$this->coptions['yAxis'][$name] = $mixvalue;
            }
        }
        return 
$this;
    }
    
/**
     * Set options for the Exporting module
     *
     * @param mixed $name the option name for the loading. Can be a string or array.
     * When used as array a key value pair should be defined, where the key is the name
     * @param mixed $mixvalue a value option in case the name is a string
     * @return higridCharts instance
     */
    
public function HCsE($name$mixvalue=''){
        if(
$mixvalue === '') {
            if(
is_array($name) && count($name) > ) {
                foreach(
$name as $key =>$val)
                {
                    
$this->coptions['exporting'][$key] = $val;
                }
            }
        } else {
            
$name trim($name);
            if(
$name != ''){
                
$this->coptions['exporting'][$name] = $mixvalue;
            }
        }
        return 
$this;
    }
    
/**
     * Set  collection of options for buttons and menus appearing in the
     * exporting module.
     *
     * @param mixed $name the option name for the loading. Can be a string or array.
     * When used as array a key value pair should be defined, where the key is the name
     * @param mixed $mixvalue a value option in case the name is a string
     * @return higridCharts instance
     */
    
public function setNavigation($name$mixvalue=''){
        if(
$mixvalue === '') {
            if(
is_array($name) && count($name) > ) {
                foreach(
$name as $key =>$val)
                {
                    
$this->coptions['navigation'][$key] = $val;
                }
            }
        } else {
            
$name trim($name);
            if(
$name != ''){
                
$this->coptions['navigation'][$name] = $mixvalue;
            }
        }
        return 
$this;
    }
    
/**
     * Add a data to the series with a given name. If the name exists the data will
     * be overwritten. Data can be added via array, sql query or javascript function
     *
     * @param string $name the name of the chart. This will be displayed in the chart
     * @param mixed $value can be array, sql query or java script function.
     * @param array $params parameters passed to the query in case of SQL data
     * @param mixed $limit if set to number the number of records to retrieve
     * @param integer $offset how many records to skip in case of sql.
     * @return higridCharts
     */
    
public function HCaS($name$value$params =  null$limit=false$offset=0)
    {
        
$datafunc false;
        if(
$name != '') {
            if(
is_string($value)) {
                if(
strpos($value,'js:')===0) {
                    
$datafunc true;
                    
$mixvalue $value;
                } else {
                    
$mixvalue $this->getSQLSerie($value$params$limit$offset);
                }
            } else {
                
$mixvalue $value;
            }
            if(
is_array($mixvalue) || $datafunc)
            {
                
$f=false;
                foreach(
$this->coptions['series'] as $index => $serie){
                    if(
strtolower($serie['name']) == strtolower($name)){
                        
$f=$index;
                        break;
                    }
                }
                if( 
$f!==false ){
                    if(
$datafunc) {
                        
// function
                        
$this->coptions['series'][$f]['data'] = $mixvalue;
                    } else {
                        if(empty(
$mixvalue)) {
                            
$this->coptions['series'][$f]['data'] = $mixvalue;
                        } else {
                            foreach(
$mixvalue as $val){
                                
$val = (is_numeric($val)) ? (float)$val $val;
                                
$this->coptions['series'][$f]['data'][] = $val;
                            }
                        }
                    }
                } else {
                    
$this->coptions['series'][$this->i_serie_index]['name'] = $name;
                    if(
$datafunc) {
                        
$this->coptions['series'][$this->i_serie_index]['data'] = $mixvalue;
                    } else {
                        if(empty (
$mixvalue)) {
                            
$this->coptions['series'][$this->i_serie_index]['data'] = $mixvalue;
                        } else {
                            foreach(
$mixvalue as $val){
                                
$val = (is_numeric($val)) ? (float)$val $val;
                                
$this->coptions['series'][$this->i_serie_index]['data'][] = $val;
                            }
                        }
                    }
                    
$this->i_serie_index++;
                }
            }
        }
        return 
$this;
    }
    
/**
     * Set a various options for a serie.
     *
     * @param string $name the name for the serie
     * @param mixed $option can be a array or string. If array a key value pair
     * should be used, where key is the properti value is the optinvalue
     * @param mixed $value the value of the option value in case the option is a string
     * @return higridCharts
     */
    
public function setSeriesOption($name=''$option=''$value=''){
        
$name trim($name);
        if(
$name !== '' && $option){
            
$f=false;
            foreach(
$this->coptions['series'] as $index => $serie){
                if(
strtolower($serie['name']) == strtolower($name)){
                    
$f=$index;
                    break;
                }
            }
            if( 
$f !== false ){
                if(
is_array($option) && count($option)>0) {
                    foreach(
$option as $key => $val) {
                        
$this->coptions['series'][$f][$key] = $val;
                    }
                } else {
                    
$this->coptions['series'][$f][$option] = $value;
                }
            }
        }
        return 
$this;
    }
    
/**
     * Put a javascript code after all things are created. The method is executed
     * only once when the chart is created.
     * @param string $code - javascript to be executed
     */
    
public function setJSCode($code) {
        if(
strlen($code)>0) {
            
$this->jscode 'js:'.$code;
        }
        return 
$this;
    }
    
/**
     * Set a theme - Can be grid, gray, dark-blue, dark-green
     * @param string $theme the name of the theme
     * @return higridCharts 
     */
    
public function setTheme($theme '')
    {
        if(
$theme && strlen($theme)>0) {
            
$this->theme $theme;
        } else {
            
$this->theme '';
        }
        return 
$this;
    }
    
/**
     * Main method which construct the chart based on the options set
     * with the previous methods
     *
     * @param string $div_id the id of the chart element in the DOM. If empty
     * the default name 'jqchart' is used.
     * @param boolean $createlem if set to true a div element is created. If the
     * option is set to false the previous option should be set in order to render
     * the chart to a existing element.
     * @param mixed $width set the width of the chart. If  a number is used the
     * width is created in pixels. Have sense only if $createlem is true
     * @param <type> $height set the height of the chart. If  a number is used the
     * height is created in pixels. Have sense only if $createlem is true
     * @param string $chart the name which is used when a javascript chart object
     * is created. Can be used later to refer to the chart. The default
     * name is 'chart'
     *
     * @return string
     */
    
public function HCoP($div_id='',$createlem=true$width='800',$height='400'$chart='chart'){
        if(
$div_id == ''$div_id 'jqchart';
        
$this->coptions['chart']['renderTo'] = $div_id;
        
$width is_numeric($width) ? $width.'px' $width;
        
$height is_numeric($height) ? $height.'px' $height;
        
$dim "width:".$width.";height:".$height.";margin: 0 auto;";
        
$s "";
        if(
$createlem)
        {
            
$s .= '<div id="'.$div_id.'" style="'.$dim.'"></div>';
        }
        
$s .= '<script type="text/javascript">';
        
$s .= 'jQuery(document).ready(function(){';
        if(
$this->theme && strlen($this->theme)>0) {
            if(
strpos($this->theme,'.js') === false) {
                
$themeFile $this->theme.".js";
            } else {
                
$themeFile $this->theme;
            }
            try {
                
$theme file_get_contents($themeFile);
                if(
$theme !== false) {
                    
$s .= $theme;
                }
            } catch (
Exception $e) {
            }
        }
        if(isset (
$this->coptions['lang']))
        {
            
$s .= 'Highcharts.setOptions({lang:'.hgGridcommon::encode($this->coptions["lang"]).'});';
            unset(
$this->coptions['lang']);
        }
        
$s .= 'var '.$chart.' = new Highcharts.Chart('.hgGridcommon::encode($this->coptions).');';
        if(
$this->jscode) {
            
$s .= hgGridcommon::encode($this->jscode);
        }
        
$s .= '});';
        
$s .= '</script>';
        return 
$s;
    }
}
?>