<?php
require_once dirname(__DIR__) . '/base/spcchart.php';
/**
 * IMR
 */
class IMR extends spcChart
{
    public $decimals;

    public $dataframe;

    /**
     * SPC I chart σ method;
     *
     * @param string $col
     * @param string $type
     * @param bool $round
     * @access public
     * @return array
     */
    public function sigma($col, $type, $round = true)
    {
        $d₂     = $this->dataframe->D₂(2); // https://zhuanlan.zhihu.com/p/335476050
        $mrBar  = $this->mrBar($col, $type, false);

        $result = $mrBar / $d₂;
        return $round ? round($result, $this->decimals) : $result;
    }

    /**
     * I chart center line method.
     *
     * @param float $xBar
     * @param float $σ
     * @param int $n
     * @param float $multiple
     * @access public
     * @return object
     */
    public function iCL($xBar, $σ, $multiple)
    {
        $result = new stdclass();

        $part  = (float)$multiple * $σ;

        $result->CL  = $xBar;
        $result->UCL = $xBar + $part;
        $result->LCL = $xBar - $part;

        return $result;
    }
    /**
     * MR chart center line method.
     *
     * @param float $σ
     * @param float $multiple
     * @access public
     * @return object
     */
    public function mrCL($σ, $multiple)
    {
        $result = new stdclass();

        // https://support.minitab.com/zh-cn/minitab/21/help-and-how-to/quality-and-process-improvement/control-charts/how-to/variables-charts-for-subgroups/xbar-r-chart/methods-and-formulas/unbiasing-constants-d2-d3-and-d4
        $d2   = $this->dataframe->D₂(2);
        $d3   = $this->dataframe->D₃(2);
        $part = (float)$multiple * $σ * $d3;

        $result->CL  = $d2 * $σ;
        $result->UCL = $result->CL + $part;
        $result->LCL = $result->CL - $part;
        $result->LCL = max(0, $result->LCL);

        return $result;
    }

    /**
     * I chart limit line method.
     *
     * @param float $μ
     * @param float $σ
     * @param float $multiple
     * @param float $defaultMultiple
     * @access public
     * @return object
     */
    public function iLimit($μ, $σ, $multiple, $defaultMultiple = 3)
    {
        $type = 'number';

        $multiples = $multiple;
        if(!in_array($defaultMultiple, $multiple)) $multiples[] = $defaultMultiple;

        $SLs = array();
        foreach($multiples as $m)
        {
            $CLResult = $this->iCL($μ, $σ, $m);
            $SLs[$m] = array($CLResult->UCL, $CLResult->LCL);
        }

        $result       = new stdclass();
        $result->CL   = $μ;
        $result->ULCL = $SLs[$defaultMultiple];
        $result->SLs  = $SLs;

        return $result;
    }

    /**
     * MR chart limit line method.
     *
     * @param float $σ
     * @param float $multiple
     * @param float $defaultMultiple
     * @access public
     * @return object
     */
    public function mrLimit($σ, $multiple, $defaultMultiple = 3)
    {
        $type = 'number';

        $multiples = $multiple;
        if(!in_array($defaultMultiple, $multiple)) $multiples[] = $defaultMultiple;

        $SLs = array();
        foreach($multiples as $m)
        {
            $CLResult = $this->mrCL($σ, $m);
            $SLs[$m]  = array($CLResult->UCL, $CLResult->LCL);
            $CL       = $CLResult->CL;
        }

        $result       = new stdclass();
        $result->CL   = $CL;
        $result->ULCL = $SLs[$defaultMultiple];
        $result->SLs  = $SLs;

        return $result;
    }

    /**
     * SPC MR bar method;
     * https://zhuanlan.zhihu.com/p/335476050
     *
     * @param array $cols
     * @param string $type
     * @param bool $round
     * @access public
     * @return array
     */
    public function mrBar($col, $type, $round = true)
    {
        $mr = $this->mr($col, $type);

        if(empty($mr)) return null;

        $mergeMr = array();
        foreach($mr as $sub)
        {
            $mergeMr = array_merge($mergeMr, $sub);
        }

        $n = count($mergeMr);

        $result = array_sum($mergeMr) / $n;
        return $round ? round($result, $this->decimals) : $result;
    }

    /**
     * SPC MR method;
     * https://zhuanlan.zhihu.com/p/335476050
     *
     * @param string $col
     * @param string $type
     * @param bool $round
     * @access public
     * @return array
     */
    public function mr($col, $type)
    {
        $result = $this->dataframe->col($col, $type);

        $arr  = $result->data;
        $n    = $result->numCount;

        if($n < 2) return null;

        $result = array();
        $mr     = array();
        foreach($arr as $i => $item)
        {
            if($i == 0) continue;
            $pre = $arr[$i - 1];
            $cur = $item;
            if(is_numeric($pre) && is_numeric($cur))
            {
                $mr[] = abs($item - $arr[$i - 1]);
            }
            else
            {
                $result[] = $mr;
                $mr = array();
            }
        }

        if(!empty($mr)) $result[] = $mr;

        return $result;
    }

    /**
     * Add MR data to dataframe.
     *
     * @param object $dataframe
     * @param string $key
     * @access public
     * @return object
     */
    public function addMRData($var)
    {
        global $dasLang;
        $key = 'mr' . $var;

        $type = 'number';
        $mrs = $this->mr($var, $type);

        $mrIndex = 0;
        $data = [];
        foreach($mrs as $i => $mr)
        {
            $data[$mrIndex] = null;
            $mrIndex += 1;
            foreach($mr as $mrValue)
            {
                $data[$mrIndex] = $mrValue;
                $mrIndex += 1;
            }

            if(count($mr) == 0 && $i + 1 == count($mrs))
            {
                $data[$mrIndex] = null;
                $mrIndex += 1;
            }
        }

        return self::addData($this->dataframe, $key, $dasLang->IMR->range, $data);
    }
}
