<?php
require_once LIB_ROOT . '/dataframe/spc/IMR.php';
require_once LIB_ROOT . '/dataframe/checkdata.php';
require_once LIB_ROOT . '/zendasmath/basic/describe.php';
require_once LIB_ROOT . '/dataframe/validatedata.php';
require_once 'spc.php';

/* IM-R 控制图 */
class IMRMethod
{
    /* Method name 分析方法内部名称 */
    public static $name = 'I-MR';

    /* Method settings 方法设置参数定义 */
    public static $settings = array();

    /* Diagram config 图表配置项 */
    public static $config = array();

    /* Callback for basic statistic method 基本量统计计算回调函数 */
    public static function func($dataframe, $settings)
    {
        global $dasLang;
        global $lang;

        $result = array();

        $type     = 'number';
        $multiple = IMR::formatMultiple($settings['multiple']);
        $mRef     = IMR::formatReference($settings['mRef']);
        $rRef     = IMR::formatReference($settings['rRef']);
        $vars     = $settings['var'];
        $σ        = $settings['sd'];
        $mean     = $settings['mean'];
        $tests    = isset($settings['tests']) ? $settings['tests'] : '';

        $check = new checkData();
        $check->setDataList($dataframe->colsData($vars), $dataframe->colsName($vars), self::$settings['var']['validate']);

        $checkRes = $check->check();
        if(is_string($checkRes)) return ValidateData::result($checkRes);

        foreach($vars as $var)
        {
            $textResult = $dataframe->getTextResult($dataframe->getChartTitle($var, $lang->perfanalysis->methods->control['IMR']));
            $textResult->name = 'var' . $var;

            /* I Chart */
            $iTitle   = $dataframe->getChartTitle($var, $dasLang->IMR->single);
            $iResult  = self::buildIChartResult($dataframe, $var, $multiple, $mean, $σ, $iTitle, $tests, $mRef);

            /* MR Chart  */
            $mrTitle  = $dataframe->getChartTitle($var, $dasLang->IMR->moveRange);
            $mrTest   = (is_array($tests) and in_array('1', $tests)) ? array('1') : array();
            $mrResult = self::buildMRChartResult($dataframe, $var, $multiple, $σ, $mrTitle, $mrTest, $rRef);

            if(!empty($iResult) and !empty($mrResult))
            {
                $textResult->children = 4;
                $result[]             = $textResult;
            }
            if(!empty($iResult))
            {
                $result[] = $iResult;
                if(!empty($tests) && isset($iResult->tests))
                {
                    $result[] = SPC::buildTestsResult($iResult->tests, $dasLang->IMR->single, $vars);
                    unset($iResult->tests);
                }
            }
            if(!empty($mrResult))
            {
                $result[] = $mrResult;
                if(!empty($tests) && isset($mrResult->tests))
                {
                    $result[] = SPC::buildTestsResult($mrResult->tests, $dasLang->IMR->moveRange, $vars);
                    unset($mrResult->tests);
                }
            }
        }

        return $result;
    }

    /**
     * Build I chart result.
     *
     * @param object $dataframe
     * @param string $var
     * @access public
     * @return array
     */
    public static function buildIChartResult($dataframe, $var, $multiple, $mean, $σ, $title, $tests = '', $ref = array())
    {
        global $dasLang;
        $lang = $dasLang->IMR;

        $type            = 'number';
        $defaultMultiple = 3;

        $sliceDF = $dataframe->sliceDataframe($dataframe, $var, $type);
        $imr     = new IMR($sliceDF);
        $data    = $sliceDF->col($var, $type);

        /* 如果数据少于2个，没法算极差，因此直接不算.*/
        if($data->numCount < 2) return array();

        if(!is_numeric($mean)) $mean = Describe::mean($data->trimdata);
        if(!is_numeric($σ)) $σ = $imr->sigma($var,$type);

        /* UCL LCL */
        $limit = $imr->iLimit($mean, $σ, $multiple);

        /* Std ULCLs */
        $stdLimit = $imr->iLimit($mean, $σ, array(1, 2, 3));
        $stdULCLs = $stdLimit->SLs;
        $stdULCLs['C'] = $stdLimit->CL;

        $param = new stdclass();

        $param->lang         = $lang;
        $param->points       = $data->data;
        $param->name         = $sliceDF->columns[$var];
        $param->lineBegin    = 0;
        $param->lineEnd      = count($param->points) - 1;
        $param->CL           = $limit->CL;
        $param->ULCLs        = $limit->SLs;
        $param->title        = $title;
        $param->xTitle       = $lang->observation;
        $param->yTitle       = $lang->single;
        $param->testsResults = SPC::checkTestsRules($data->data, $stdULCLs, $tests);
        $param->ref          = $ref;

        return SPC::buildChartResult($param);
    }

    /**
     * Build MR chart result.
     *
     * @param object $dataframe
     * @param string $var
     * @access public
     * @return array
     */
    public static function buildMRChartResult($dataframe, $var, $multiple, $σ, $title, $tests = '', $ref = array())
    {
        global $dasLang;
        $lang = $dasLang->IMR;

        $type            = 'number';
        $defaultMultiple = 3;
        $mrKey           = 'mr' . $var;

        $data = $dataframe->col($var, $type);
        /* 如果数据少于2个，没法算极差，因此直接不算.*/
        if($data->numCount < 2) return array();

        $sliceDF   = $dataframe->sliceDataframe($dataframe, $var, $type);
        $imr       = new IMR($sliceDF);
        $imr->addMRData($var);

        $data = $sliceDF->col($mrKey, $type);
        if(!is_numeric($σ)) $σ = $imr->sigma($var, $type);

        /* UCL LCL */
        $limit = $imr->mrLimit($σ, $multiple);

        /* Std ULCLs */
        $stdLimit = $imr->mrLimit($σ, array(1, 2, 3));
        $stdULCLs = $stdLimit->SLs;
        $stdULCLs['C'] = $stdLimit->CL;

        $param = new stdclass();

        $param->lang         = $lang;
        $param->points       = $data->data;
        $param->name         = $sliceDF->columns[$mrKey];
        $param->lineBegin    = 0;
        $param->lineEnd      = count($param->points) - 1;
        $param->CL           = $limit->CL;
        $param->ULCLs        = $limit->SLs;
        $param->title        = $title;
        $param->xTitle       = $lang->observation;
        $param->yTitle       = $lang->moveRange;
        $param->stdULCLs     = $stdULCLs;
        $param->testsResults = SPC::checkTestsRules($data->data, $stdULCLs, $tests);
        $param->ref          = $ref;

        return SPC::buildChartResult($param);
    }

    /**
     * Get settings.
     *
     * @param object $lang
     * @access public
     * @return object
     */
    public static function getSettings()
    {
        global $dasLang;
        $lang = $dasLang->IMR;

        /* Basic settings */
        self::$settings['var']      = array('name' => 'var',      'label' => $lang->var, 'required' => true);
        self::$settings['multiple'] = array('name' => 'multiple', 'label' => $lang->multiple);
        self::$settings['sd']       = array('name' => 'sd',       'label' => $lang->sd);
        self::$settings['mean']     = array('name' => 'mean',     'label' => $lang->mean);
        self::$settings['mRef']     = array('name' => 'mRef',     'label' => $lang->mRef);
        self::$settings['rRef']     = array('name' => 'rRef',     'label' => $lang->rRef);
        self::$settings['tests']    = array('name' => 'tests',    'label' => $dasLang->spc->tests);

        /* Type settings */
        self::$settings['var']      += array('type' => 'list', 'listType' => 'column', 'columnType' => 'number');
        self::$settings['multiple'] += array('type' => 'list', 'listType' => 'number');
        self::$settings['sd']       += array('type' => 'number');
        self::$settings['mean']     += array('type' => 'number');
        self::$settings['mRef']     += array('type' => 'list', 'listType' => 'number');
        self::$settings['rRef']     += array('type' => 'list', 'listType' => 'number');
        self::$settings['tests']    += array('type' => 'list', 'listType' => 'enum', 'enumOptions' => $dasLang->spc->testsRules, 'ui' => 'checkbox-list', 'defaultValue' => array('1'));

        /* Limit settings */
        self::$settings['multiple'] += array('pattern' => "/^[\d]+(\.[\d]+)?$/",                'error' => $lang->errorMultiple);
        self::$settings['sd']       += array('pattern' => "/^([1-9]\d*)(\.[\d]+)?$|^0\.\d+?$/", 'error' => $lang->errorSD);
        self::$settings['mean']     += array('pattern' => "/^[\+\-]?[\d]+(\.[\d]+)?$/",         'error' => $lang->errorMean);
        self::$settings['mRef']     += array('pattern' => "/^[\d]+(\.[\d]+)?$/",                'error' => $lang->errorMRef);
        self::$settings['rRef']     += array('pattern' => "/^[\d]+(\.[\d]+)?$/",                'error' => $lang->errorRRef);

        /* Col grid settings */

        /* More settings */
        self::$settings['multiple'] += array('paramType' => 'more');
        self::$settings['sd']       += array('paramType' => 'more');
        self::$settings['mean']     += array('paramType' => 'more');
        self::$settings['mRef']     += array('paramType' => 'more');
        self::$settings['rRef']     += array('paramType' => 'more');
        self::$settings['tests']    += array('paramType' => 'more');

        /* Data validate */
        self::$settings['var'] += array('validate' => array('continuous', 'number', 'N >= 2'));

        return self::$settings;
    }

    /**
     * Get config.
     *
     * @access public
     * @return object
     */
    public static function getConfig()
    {
        global $dasLang;
        $lang = $dasLang->config;
        self::$config['grid']   = $lang->gridConfig;
        self::$config['legend'] = $lang->legendConfig;

        return self::$config;
    }

    /**
     * Get Setting column type.
     *
     * @param string $index
     * @access public
     * @return string
     */
    public static function columnType($index)
    {
        return self::$settings[$index]['columnType'];
    }

}
