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

    public $dataframe;

    /**
     * Xbar-S chart σ method.
     * 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-s-chart/methods-and-formulas/estimating-sigma/
     *
     * @param array $cols
     * @param string $type
     * @param bool $round
     * @access public
     * @return array
     */
    public function sigma($cols, $type, $round = true)
    {
        $sdKey = 'sdSub';
        $rowSD = $this->dataframe->rowSD($cols, $sdKey);
        $sub   = $this->subgroup($cols, $type);

        if($sub->sizeFixed)
        {
            $n  = current($sub->subgroup);
            $m  = count($rowSD->data);
            $c4 = $this->dataframe->C₄($n);
            $σ  = $rowSD->sum / ($m * $c4);
        }
        else
        {
            $subgroup = $sub->subgroup;

            $sum1 = 0;
            $sum2 = 0;
            foreach($subgroup as $i => $group)
            {
                if($group < 2) continue;

                $c4 = $this->dataframe->C₄($group);
                $h = $c4 ** 2 / (1 - $c4 ** 2);
                $sdi = $rowSD->data[$i];

                $sum1 += $h * $sdi / $c4;
                $sum2 += $h;
            }
            $σ = $sum1 / $sum2;
        }

        return $round ? round($σ, $this->decimals) : $σ;
    }

    public function xBar($cols, $type, $round = true)
    {
        $result = $this->dataframe->cols($cols, $type);

        $n   = 0;
        $sum = 0;
        foreach($result as $data)
        {
            foreach($data->trimdata as $value) if(is_numeric($value)) $n += 1;
            $sum += $data->sum;
        }

        $xBar = $sum / $n;
        $xBar = $round ? round($xBar, $this->decimals) : $xBar;

        return $xBar;
    }

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

        $sqrtN = sqrt($n);
        $part  = (float)$multiple * $σ / $sqrtN;

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

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

        $c4   = $this->dataframe->C₄($n);
        $c5   = $this->dataframe->C₅($n);
        $part = (float)$multiple * $σ * $c5;

        $result->CL  = $this->sBar($σ, $n, $c4);
        $result->UCL = $result->CL + $part;
        $result->LCL = $result->CL - $part;
        $result->LCL = max(0, $result->LCL);

        return $result;
    }

    /**
     * X bar chart limit line method.
     *
     * @param array $vars
     * @param float $μ
     * @param float $σ
     * @param float $multiple
     * @param float $defaultMultiple
     * @access public
     * @return object
     */
    public function xBarLimit($vars, $μ, $σ, $multiple, $defaultMultiple = 3)
    {
        $type = 'number';
        $sub  = $this->subgroup($vars, $type);

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

        $SLs = array();
        if($sub->sizeFixed)
        {
            $n = current($sub->subgroup);
            foreach($multiples as $m)
            {
                $CLResult = $this->xBarCL($μ, $σ, $n, $m);
                $SLs[$m] = array($CLResult->UCL, $CLResult->LCL);
            }
        }
        else
        {
            foreach($multiples as $m)
            {
                $USLs = array();
                $LSLs = array();
                foreach($sub->subgroup as $n)
                {
                    if($n < 1)
                    {
                        $USLs[] = null;
                        $LSLs[] = null;
                        continue;
                    }

                    $CLResult = $this->xBarCL($μ, $σ, $n, $m);

                    $USLs[] = $CLResult->UCL;
                    $LSLs[] = $CLResult->LCL;
                }
                $SLs[$m] = array($USLs, $LSLs);
            }
        }

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

        return $result;
    }

    /**
     * S chart limit line method.
     *
     * @param array $vars
     * @param float $σ
     * @param float $multiple
     * @param float $defaultMultiple
     * @access public
     * @return object
     */
    public function sLimit($vars, $σ, $multiple, $defaultMultiple = 3)
    {
        $type = 'number';
        $sub  = $this->subgroup($vars, $type);

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

        $SLs = array();
        if($sub->sizeFixed)
        {
            $n = current($sub->subgroup);
            foreach($multiples as $m)
            {
                $CLResult = $this->sCL($σ, $n, $m);
                $SLs[$m] = array($CLResult->UCL, $CLResult->LCL);
            }
            $CL = $this->sBar($σ, $n);
        }
        else
        {
            foreach($multiples as $m)
            {
                $USLs = array();
                $LSLs = array();
                foreach($sub->subgroup as $n)
                {
                    if($n < 2)
                    {
                        $USLs[] = null;
                        $LSLs[] = null;
                        continue;
                    }

                    $CLResult = $this->sCL($σ, $n, $m);

                    $USLs[] = $CLResult->UCL;
                    $LSLs[] = $CLResult->LCL;
                }
                $SLs[$m] = array($USLs, $LSLs);
            }

            $CL = array();
            foreach($sub->subgroup as $n)
            {
                if($n < 2)
                {
                    $CL[] = null;
                    continue;
                }
                $CL[] = $this->sBar($σ, $n);
            }
        }

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

        return $result;
    }

    /**
     * S bar method.
     *
     * @param float $σ
     * @param int $n
     * @param float $c4
     * @access public
     * @return object
     */
    public function sBar($σ, $n, $c4 = null)
    {
        if(empty($c4)) $c4 = $this->dataframe->C₄($n);
        return $c4 * $σ;
    }
}
