<?php
require_once dirname(__DIR__) . '/base/analysis.php';
require_once dirname(dirname(__DIR__)) . '/zendasmath/basic/describe.php';
require_once dirname(dirname(__DIR__)) . '/zendasmath/distribution/normal.php';


class empirical extends analysisBase
{
    public $points;

    public $mean;

    public $std;

    public $normal;

    public $n;

    public $rate;

    /**
     * 构造方法。
     *
     * The construct function.
     *
     * @access public
     * @return void
     */
    public function __construct($dataframe, $points)
    {
        parent::__construct($dataframe);

        sort($points);
        $this->points = $points;
        $this->mean   = Describe::mean($this->points);
        $this->std    = Describe::standard($this->points);
        $this->normal = new normal($this->mean, $this->std);
        $this->n      = count($this->points);
        $this->rate   = 10;
    }

    /**
     * Get limit.
     *
     * @access public
     * @return array
     */
    public function limit()
    {
        $u     = 2.326;
        $min   = $this->mean - ($this->std * $u);
        $max   = $this->mean + ($this->std * $u);

        return array($min, $max);
    }

    /**
     * Get exp line data.
     *
     * @access public
     * @return array
     */
    public function exp()
    {
        list($min, $max) = $this->limit();
        $ystep = 100 / $this->n;

        $xlines = array();
        $ylines = array();
        foreach($this->points as $index => $value)
        {
            if($index === 0 && $min < $value)
            {
                if($min < $value)
                {
                    $xlines[] = $min;
                    $ylines[] = (float)$index * $ystep;
                }
                else
                {
                    $min = $value;
                }
            }

            $xlines[] = $value;
            $xlines[] = $value; // Reapeat value push.
            $ylines[] = (float)$index * $ystep;
            $ylines[] = (float)($index + 1) * $ystep;

            if($index === $this->n - 1)
            {
                if($max > $value)
                {
                    $xlines[] = $max;
                    $ylines[] = (float)($index + 1) * $ystep;
                }
                else
                {
                    $max = $value;
                }
            }
        }

        return array($xlines, $ylines);
    }

    /**
     * Get fit line data.
     *
     * @access public
     * @return array
     */
    public function fit()
    {
        list($min, $max) = $this->limit();

        $unit     = ($max - $min) / (100 * $this->rate);
        $xpoints  = array();
        $ypoints  = array();
        $expoints = array();

        for($point = $min; $point <= $max; $point += $unit)
        {
            $xpoints[] = $point;
            $ypoints[] = ($this->normal->cdf($point+$unit) - $this->normal->cdf($point)) * $this->n;
        }
        $normalSum = array_sum($ypoints);
        $midSum = 0;
        foreach($ypoints as $ypoint)
        {
            $midSum += $ypoint;
            $expoints[] = $midSum / $normalSum * 100;
        }

        return array($xpoints, $expoints);
    }

    /**
     * Get percentage points.
     *
     * @access public
     * @return array
     */
    public function percentage($xpoints, $expoints, $percent)
    {
        $percentX = 0;
        $percentY = 0;

        for($index = 1; $index <= 100 * $this->rate; $index++)
        {
            if($index + 1 < 100 * $this->rate && $expoints[$index] <= $percent && $expoints[$index + 1] > $percent)
            {
                $percentX = $xpoints[$index + 1];
                $percentY = round($expoints[$index + 1]);
            }
        }

        return array($percentX, $percentY);
    }
}
