<?php
/**
 * Column
 */
class column
{
    /**
     * Data
     *
     * @var array
     * @access public
     */
    public $data;

    /**
     * Origin data
     *
     * @var array
     * @access public
     */
    public $originData;

    /**
     * Min value
     *
     * @var null|float
     * @access public
     */
    public $min;

    /**
     * Max value
     *
     * @var null|float
     * @access public
     */
    public $max;

    /**
     * Sum value
     *
     * @var int|float
     * @access public
     */
    public $sum;

    /**
     * Count of values
     *
     * @var int|float
     * @access public
     */
    public $numCount;

    /**
     * Name
     *
     * @var string
     * @access public
     */
    public $name;

    /**
     * Is numeric
     *
     * @var bool
     * @access public
     */
    public $isNumeric;

    /**
     * Is int
     *
     * @var bool
     * @access public
     */
    public $isInt;

    /**
     * Has zero
     *
     * @var bool
     * @access public
     */
    public $haveZero;

    /**
     * Has negative value
     *
     * @var bool
     * @access public
     */
    public $haveNegative;

    /**
     * Has string value
     *
     * @var bool
     * @access public
     */
    public $haveString;

    /**
     * Is empty
     *
     * @var bool
     * @access public
     */
    public $isEmpty;

    /**
     * Column data
     *
     * @var array
     * @access public
     */
    public $colData;

    /**
     * Trimed data
     *
     * @var array
     * @access public
     */
    public $trimdata;

    /**
     * Construct
     *
     * @param  object      $dataframe
     * @param  int         $index
     * @param  string      $type any|number|nopercentstring
     * @param  string|bool $filter
     * @access public
     * @return void
     */
    public function __construct($dataframe, $index, $type = 'any', $filter = true)
    {
        global $config;
        $decimals = $config->default->decimals;

        $this->max      = NULL;
        $this->min      = NULL;
        $this->sum      = 0;
        $this->numCount = 0;
        $this->name     = $dataframe->columns[$index];

        $this->data       = array();
        $this->originData = array();
        $isInt            = true;
        $haveZero         = false;
        $haveNegative     = false;
        $haveString       = false;
        $isEmpty          = true;
        $colData          = array();

        foreach($dataframe->data as $row)
        {
            if(!array_key_exists($index, $row) || (is_callable($filter) && !$filter($row))) continue;

            $originVal = $val = $row[$index];
            if($val === null) $val = '';

            $val = self::formatString($val);

            if(!preg_match("/^[0-9]*$/",$val)) $isInt = false;
            if(is_numeric($val) and $val == '0') $haveZero = true;
            if(is_numeric($val) and (float)$val < 0) $haveNegative = true;
            if(!is_numeric($val) and $val !== NULL and !empty($val)) $haveString = true;
            if((empty($val) && $val == '0') || !empty($val)) $isEmpty = false;
            $numVal = self::cast2Number($val);
            if($numVal !== NULL)
            {
                $numVal = round($numVal, $decimals);
                if($numVal > $this->max or $this->max === NULL) $this->max = $numVal;
                if($numVal < $this->min or $this->min === NULL) $this->min = $numVal;

                $this->sum += $numVal;
                $this->numCount++;
            }

            $this->data[]       = self::setData($numVal, $originVal, $type);
            $this->originData[] = $originVal;
            $this->isNumeric    = count($dataframe->data) == $this->numCount;
            $this->isInt        = $isInt;
            $this->haveZero     = $haveZero;
            $this->haveNegative = $haveNegative;
            $this->haveString   = $haveString;
            $this->isEmpty      = $isEmpty;
        }

        $this->trimdata = self::trimNull($this->data);
    }

    static public function formatString($str)
    {
        $str = trim($str);
        $str = str_replace(' ', '', $str);

        return $str;
    }

    static public function setData($numVal, $originVal, $type)
    {
        if($type == 'any') return $originVal;
        if($type == 'number') return $numVal;
        if($type == 'nopercentstring') return (string)$numVal;
    }

    /**
     * Cast string to number
     *
     * @param  string $str
     * @param  string $type float|string
     * @static
     * @access public
     * @return float|null
     */
    static public function cast2Number($str, $type = 'float')
    {
        if($str === null) return null;
        $str = self::trimPercent($str);

        $result = is_numeric($str) ? $str : null;
        if($result === null and $type == 'float') return null;

        $result = $type == 'float' ? (float)$result : (string)$result;

        return $result;
    }

    /**
     * Trim percent
     *
     * @param  string $str
     * @static
     * @access public
     * @return string
     */
    static public function trimPercent($str)
    {
        if(strpos($str, '%') !== false)
        {
            $afterStr = trim($str, '%');
            $afterStr = is_numeric($afterStr) ? ($afterStr /= 100) : $str;
        }
        else
        {
            $afterStr = $str;
        }

        return $afterStr;
    }

    /**
     * Get data that is not null
     *
     * @access public
     * @return array
     */
    public function notNull()
    {
        $arr = array_filter($this->data, function($v) {return (empty($v) && $v == '0') || !empty($v);});
        return array_values($arr);
    }

    static public function trimNull($data)
    {
        foreach($data as $index => $value)
        {
            if($value === null) continue;
            $value = trim($value);
            if(is_string($value) and ctype_space($value)) $data[$index] = null;

            /* 判断空格是否只由全角空格、半角空格、中英文空格等组成。*/
            if(preg_match('/^[\s　]*$/', $value)) $data[$index] = null;
        }

        $last = end($data);
        while($last === null)
        {
            array_pop($data);
            $last = end($data);
        }

        return $data;
    }
}
