<?php
require_once LIB_ROOT . '/dataframe/regression/multipleRegression.php';
require_once LIB_ROOT . '/dataframe/regression/fourinone.php';
require_once LIB_ROOT . '/dataframe/checkdata.php';
require_once LIB_ROOT . '/dataframe/validatedata.php';

/* Multiple regression method 线性回归 */
class multipleRegressionMethod
{
    /* Method name 分析方法内部名称 */
    public static $name = 'multipleRegression';

    /* 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;
        $lang = $dasLang->multipleRegression;

        $xaxis = $settings['xaxis'];
        $yaxis = $settings['yaxis'];

        $check = new checkData();
        $check->setData($dataframe->colData($yaxis), $dataframe->columns[$yaxis], self::$settings['yaxis']['validate']);
        $check->setDataList($dataframe->colsData($xaxis), $dataframe->colsName($xaxis), self::$settings['xaxis']['validate']);

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

        $xs = $dataframe->cols($xaxis, 'number');
        $y  = $dataframe->col($yaxis, 'number');
        $factors = array();
        foreach($xs as $x)
        {
            $factors[] = $x->trimdata;
        }

        $mlr = new MultipleRegression($dataframe, $factors, $y->trimdata);
        $result = array();

        if(!$mlr->checkInvertible()) return array('result' => 'fail', 'message' => $dasLang->common->invertibleError);

        /* Text. */
        $result[] = self::buildFormulaResult($dataframe, $xaxis, $yaxis, $mlr);

        /* Factor. */
        $result[] = self::buildFactorResult($dataframe, $xaxis, $mlr);

        /* Model. */
        $result[] = self::buildModelResult($mlr);

        /* Table. */
        $result[] = self::buildTableResult($dataframe, $xaxis, $mlr);

        /* Test. */
        $test = $mlr->getTest();
        if($test->hasTest) $result[] = self::buildTestResult($dataframe, $xaxis, $yaxis, $test);

        $residualResult = $dataframe->getTextResult($dasLang->lineArregression->residual);

        if($settings['fourInOne'] == 'true')
        {
            $fourInOneResult = array();
            $fourInOneText   = $dataframe->getTextResult($dasLang->multipleRegression->residual);

            $fittedResult = $mlr->fitY();
            $yData        = $y->notNull();
            $fourInOne = new fourInOne($fittedResult, $yData, $dasLang->fourInOne);

            if($fourInOne->checkSD())
            {
                $fourInOneText->children = 1;
                $fourInOneResult[] = $fourInOneText;
                $fourInOneResult[] = $fourInOne->getSubplot();
            }
            else
            {
                $errorResult        = new stdclass();
                $errorResult->type  = 'text';
                $errorResult->data  = array('content' => $dasLang->fourInOne->errorSD);

                $fourInOneText->children = 1;
                $fourInOneResult[]  = $fourInOneText;
                $fourInOneResult[]  = $errorResult;
            }

            $result = array_merge($result, $fourInOneResult);
        }

        return $result;
    }

    public static function checkData($x, $y)
    {
        $yCount = count($y);
        if($yCount == 0) return false;
        foreach($x as $sub)
        {
            if(count($sub) != $yCount) return false;
        }
        return true;
    }

    /**
     * Build formula result.
     *
     * @param object $dataframe
     * @param array $xaxis
     * @param string $yaxis
     * @param object $mlr
     * @access public
     * @return object
     */
    public static function buildFormulaResult($dataframe, $xaxis, $yaxis, $mlr)
    {
        global $dasLang;
        $lang = $dasLang->multipleRegression;

        $xNames = array();
        foreach($xaxis as $x)
        {
            $name     = $dataframe->columns[$x];
            $xNames[] = $name;
        }
        $formula = $mlr->getFourmula($xNames, $dataframe->columns[$yaxis]);

        $result        = new stdclass();
        $result->type  = 'text';
        $result->title = $lang->textTitle;
        $result->data  = array('content' => $formula);

        return $result;
    }

    /**
     * Build factor result.
     *
     * @param object $dataframe
     * @param object $mlr
     * @access public
     * @return object
     */
    public static function buildFactorResult($dataframe, $xaxis, $mlr)
    {
        global $dasLang;
        $lang = $dasLang->multipleRegression;

        $result        = new stdclass();
        $result->type  = 'table';
        $result->title = $lang->factorTitle;

        $factor       = $mlr->getFactor();
        $result->data = array();
        $arr          = array();
        $arr[]        = array($lang->common, $factor->coef[0], $factor->se[0], $factor->t[0], $factor->p[0], $factor->vif[0]);

        foreach($xaxis as $index => $x)
        {
            $name  = $dataframe->columns[$x];
            $arr[] = array($name, $factor->coef[$index + 1], $factor->se[$index + 1], $factor->t[$index + 1], $factor->p[$index + 1], $factor->vif[$index + 1]);
        }

        $result->data['data'] = $arr;

        $result->data['columns']   = array();
        $result->data['columns'][] = array('label' => $lang->item, 'type' => 'text');
        $result->data['columns'][] = array('label' => $lang->factor, 'type' => 'number');
        $result->data['columns'][] = array('label' => $lang->factorError, 'type' => 'number');
        $result->data['columns'][] = array('label' => 'T', 'type' => 'number');
        $result->data['columns'][] = array('label' => 'P', 'type' => 'number');
        $result->data['columns'][] = array('label' => $lang->factorAnova, 'type' => 'number');

        return $result;
    }

    /**
     * Build model result.
     *
     * @param object $mlr
     * @access public
     * @return object
     */
    public static function buildModelResult($mlr)
    {
        global $dasLang;
        $lang = $dasLang->multipleRegression;

        $result = new stdclass();
        $result->type  = 'table';
        $result->title = $lang->modelTitle;

        $result->data = array();
        $model = $mlr->getModel();

        $row = array($model->s, $model->rsq . ' %', $model->rsqAdj . ' %', $model->rsqPre . ' %');

        $result->data['data'] = array($row);

        $result->data['columns']   = array();
        $result->data['columns'][] = array('label' => 'S', 'type' => 'number');
        $result->data['columns'][] = array('label' => 'R-Sq', 'type' => 'number');
        $result->data['columns'][] = array('label' => $lang->RsqAdjust, 'type' => 'number');
        $result->data['columns'][] = array('label' => $lang->RsqPre, 'type' => 'number');

        return $result;
    }

    /**
     * Build table result.
     *
     * @param object $dataframe
     * @param object $mlr
     * @access public
     * @return object
     */
    public static function buildTableResult($dataframe, $xaxis, $mlr)
    {
        global $dasLang;
        $lang = $dasLang->multipleRegression;

        $result = new stdclass();
        $result->type  = 'table';
        $result->title = $lang->tableTitle;

        $result->data = array();
        $table = $mlr->getAnova();
        $arr   = array();
        $arr[] = array($lang->regression, $table->df, $table->ssRegr, $table->msRegr, $table->fRegr, $table->pRegr);

        foreach($xaxis as $index => $x)
        {
            $name  = $dataframe->columns[$x];
            $arr[] = array($name, $table->itemDf[$index], $table->itemSS[$index], $table->itemMS[$index], $table->itemF[$index], $table->itemP[$index]);
        }

        $arr[] = array($lang->deviation, $table->dfError, $table->ssError, $table->msError, '', '');

        if($table->hasSame)
        {
            $arr[] = array($lang->lostFit, $table->dfLOF, $table->ssLOF, $table->msLOF, $table->fLOF, $table->pLOF);
            $arr[] = array($lang->pureError, $table->dfPE, $table->ssPE, $table->msPE, '', '');
        }

        $arr[] = array($lang->total, $table->dfTotal, $table->ssTotal, '', '', '');

        $result->data['data'] = $arr;

        $result->data['columns']   = array();
        $result->data['columns'][] = array('label' => $lang->source, 'type' => 'text');
        $result->data['columns'][] = array('label' => $lang->freedom, 'type' => 'number');
        $result->data['columns'][] = array('label' => 'SS', 'type' => 'number');
        $result->data['columns'][] = array('label' => 'MS', 'type' => 'number');
        $result->data['columns'][] = array('label' => 'F', 'type' => 'number');
        $result->data['columns'][] = array('label' => 'P', 'type' => 'number');

        return $result;
    }

    public static function buildTestResult($dataframe, $xaxis, $yaxis, $test)
    {
        global $dasLang;
        $lang = $dasLang->multipleRegression;

        $result        = new stdclass();
        $result->type  = 'table';
        $result->title = $lang->testTitle;

        if(!empty($test->observed))
        {
            $cols = array_merge($xaxis, array($yaxis));
            $points = array();
            foreach($cols as $col) $points[$col] = $test->observed;
            $result->extra = getHighlight($points);
        }

        $result->data = array();
        $arr = array();
        foreach($test->observed as $index => $value)
        {
            $arr[] = array($value, $test->value[$index], $test->fit[$index], $test->residual[$index], $test->stdResid[$index]);
        }
        $result->data['data'] = $arr;

        $result->data['columns']   = array();
        $result->data['columns'][] = array('label' => $lang->observed, 'type' => 'number');
        $result->data['columns'][] = array('label' => $dataframe->columns[$yaxis], 'type' => 'number');
        $result->data['columns'][] = array('label' => $lang->fitValue, 'type' => 'number');
        $result->data['columns'][] = array('label' => $lang->residual, 'type' => 'number');
        $result->data['columns'][] = array('label' => $lang->sdResidual, 'type' => 'number');

        return $result;
    }

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

        /* Basic settings */
        self::$settings['xaxis']     = array('name' => 'xaxis',     'label' => $lang->xaxis, 'required' => true);
        self::$settings['yaxis']     = array('name' => 'yaxis',     'label' => $lang->yaxis, 'required' => true);
        self::$settings['fourInOne'] = array('name' => 'fourInOne', 'label' => $lang->fourInOne);

        /* Type settings */
        self::$settings['xaxis']     += array('type' => 'list', 'listType' => 'column');
        self::$settings['yaxis']     += array('type' => 'column');
        self::$settings['fourInOne'] += array('type' => 'enum', 'enumOptions' => $lang->fourInOneEnum, 'defaultValue' => 'true');

        /* Limit settings */
        self::$settings['yaxis']     += array('distinct' => 'xaxis');

        /* Col grid settings */
        self::$settings['fourInOne'] += array('col' => 3);

        /* More settings */

        /* Data validate */
        self::$settings['xaxis'] += array('validate' => array('continuous', 'number', 'notCommon', 'rowEqual'));
        self::$settings['yaxis'] += array('validate' => array('continuous', 'number', 'notCommon', 'rowEqual'));

        return self::$settings;
    }

    /**
     * Get config.
     *
     * @access public
     * @return object
     */
    public static function getConfig()
    {
        global $dasLang;
        $lang = $dasLang->config;

        //return self::$config;
    }

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