<?php
require_once LIB_ROOT . '/dataframe/regression/correlation.php';
require_once LIB_ROOT . '/dataframe/checkdata.php';
require_once LIB_ROOT . '/dataframe/validatedata.php';
require_once LIB_ROOT . '/dataframe/plotly.php';

/* Correlation method 相关性分析 */
class correlationMethod
{
    /* Method name 分析方法内部名称*/
    public static $name = 'correlation';

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

        $xaxis  = $settings['xaxis'];
        $type   = 'number';
        $cl     = $settings['cl'];
        $method = $settings['type'];

        $chartShow = $settings['chart'];

        $cols = $dataframe->cols($xaxis, $type);

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

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

        /* Chart. */
        $chartResult = new stdclass();
        $chartResult->type  = 'chart';
        $chartResult->title = '';
        $chartResult->data = array();
        $chartResult->data['type'] = 'scatter';

        $data = self::groupData($dataframe, $xaxis);
        if(isset($data['result']) && $data['result'] == 'fail') return $data;

        $rank  = ceil(sqrt(count($data)));
        $chartResult->data['data']   = json_encode($data);
        $chartResult->data['layout'] = array('grid' => array('rows' => $rank, 'columns' => $rank, 'pattern' => 'independent'));

        $legend = $dasLang->config->legendConfig;
        $legend['defaultValue'] = 'false';

        $chartResult->data['config'] = array('legend' => $legend);

        $axisSettings = array('showline' => true, 'zeroline' => true, 'zerolinecolor' => '#ddd', 'showgrid' => false);

        foreach($data as $subplot)
        {
            $index = $subplot['axisIndex'];

            $xaxisKey      = 'xaxis' . $index;
            $xaxisSettings = $axisSettings;

            $yaxisKey      = 'yaxis' . $index;
            $yaxisSettings = $axisSettings;

            if($rank ** 2 - (int)$index < $rank) $xaxisSettings['title'] = array('text' => $subplot['xname'], 'font' => array('size' => 12));
            if(empty($index) or (int)$index % $rank == 1) $yaxisSettings['title'] = array('text' => $subplot['yname'], 'font' => array('size' => 12));

            $chartResult->data['layout'][$xaxisKey] = $xaxisSettings;
            $chartResult->data['layout'][$yaxisKey] = $yaxisSettings;
        }

        /* Text. */
        $textResult = new stdclass();
        $textResult->type = 'table';
        $textResult->title = $lang->type;

        $methodText = $lang->typeEnum[$method];
        $columns   = array();
        $columns[] = array('label' => $lang->form, 'type' => 'text');
        $columns[] = array('label' => $methodText, 'type' => 'text');

        $textResult->data['data'] = array();
        $textResult->data['columns'] = $columns;

        $textResult->desc = sprintf($lang->methodInfo, $methodText);

        /* Table. */
        $tableResult = new stdclass();
        $tableResult->type  = 'table';
        $tableResult->title = $dasLang->correlation->tableTitle;

        $tableData    = array();
        // $tableColumns = array($lang->sample, $lang->N, $lang->correlation, $lang->Pvalue, sprintf($lang->CI, $cl));
        $tableColumns = array($lang->sample, $lang->N, $lang->correlation, $lang->Pvalue);

        foreach($data as $item)
        {
            $corr = new Correlation($dataframe, array($item['x'], $item['y']), $cl);
            $pearson = $method == 'pearson' ? $corr->PearsonCorrelation() : $corr->SpearmanCorrelation();

            // $tableData[] = array($item['name'], $corr->n, $pearson->r, $pearson->p, "($pearson->p_l , $pearson->p_u)");
            $calcP       = $pearson->p == '-' ? 0 : $pearson->p;
            $isCorrelate = (100 - $cl) > ($calcP * 100);

            $pText = $isCorrelate ? "<span style='color: #5a90f7;'>{$pearson->p}</span>" : $pearson->p;
            $tableData[] = array($item['name'], $corr->n, $pearson->r, $pText);
        }

        $tableResult->data = array('data' => $tableData, 'columns' => $tableColumns);

        global $lang;
        $titleResult = $dataframe->getTextResult($dataframe->getChartTitle($settings['xaxis'], $lang->perfanalysis->methods->analysis['correlation']));

        $result = array($titleResult, $textResult, $tableResult);

        if($chartShow == 'show')
        {
            $textResult = $dataframe->getTextResult($dasLang->correlation->chartTitle);
            $textResult->children = 1;

            $result[] = $textResult;
            $result[] = $chartResult;
        }

        return $result;
    }

    public static function groupData($dataframe, $xaxis)
    {
        global $dasLang;
        global $config;
        $type  = 'number';
        $datas = array();
        $cols  = $dataframe->cols($xaxis, $type);
        $cols  = array_values($cols);

        foreach($cols as $xindex => $x)
        {
            foreach($cols as $yindex => $y)
            {
                if($xindex < $yindex)
                {
                    if($x->numCount + $y->numCount < 6) return array('result' => 'fail', 'message' => $dasLang->correlation->tooFewData);

                    if(count($x->trimdata) !== count($y->trimdata)) return array('result' => 'fail', 'message' => $dasLang->correlation->lineEqualError);

                    $xname = $x->name;
                    $yname = $y->name;

                    $xdata = $x->trimdata;
                    $ydata = $y->trimdata;

                    $xdataNotNull = array();
                    $ydataNotNull = array();
                    foreach($xdata as $i => $xvalue)
                    {
                        $yvalue = $ydata[$i];
                        if(is_numeric($xvalue) && is_numeric($yvalue))
                        {
                            $xdataNotNull[] = $xvalue;
                            $ydataNotNull[] = $yvalue;
                        }
                    }
                    $data = array('name' => $xname . ' - ' . $yname, 'xname' => $xname, 'yname' => $yname, 'x' => $xdataNotNull, 'y' => $ydataNotNull, 'mode' => 'markers', 'type' => 'scatter', 'marker' => array('size' => $config->default->pointSize));
                    $data = getHoverTemplateXY($data, array('xname' => $xname, 'yname' => $yname, 'custom' => getOrderCustom($xdataNotNull)));
                    $datas[] = $data;
                }
            }
        }

        /* set lower triangular matrix position index */
        /* 计算填充下三角矩阵的位置索引 */
        // $rank  = ceil(sqrt(count($data)));
        $rank  = count($xaxis) - 1;
        $index = 0;
        for($xindex = 1; $xindex <= $rank; $xindex++)
        {
            for($yindex = 1; $yindex <= $rank; $yindex++)
            {
                if($xindex <= $yindex)
                {
                    $pos = $rank * ($yindex - 1) + $xindex;
                    $pos = $pos == 1 ? '' : $pos;
                    $datas[$index]['xaxis']     = 'x' . $pos;
                    $datas[$index]['yaxis']     = 'y' . $pos;
                    $datas[$index]['axisIndex'] = $pos;
                    $index++;
                }
            }
        }

        return $datas;
    }

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

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

        /* Type settings */
        self::$settings['type']  += array('type' => 'enum', 'enumOptions' => $lang->typeEnum, 'columnType' => 'any', 'defaultValue' => 'pearson');
        self::$settings['xaxis'] += array('type' => 'list', 'listType' => 'column', 'columnType' => 'number');
        self::$settings['cl']    += array('type' => 'number', 'columnType' => 'number', 'defaultValue' => 95.00);
        self::$settings['chart'] += array('type' => 'enum', 'enumOptions' => $lang->chartEnum, 'defaultValue' => 'show');

        /* Limit settings */
        self::$settings['xaxis'] += array('listLength' => '2,5');
        self::$settings['cl']    += array('min' => 0.0001, 'max' => 99.9999, 'error' => $lang->errorCL);

        /* Col grid settings */
        self::$settings['type']  += array('col' => 4);
        self::$settings['chart'] += array('col' => 4);

        /* More settings */
        self::$settings['type']  += array('paramType' => 'more');
        self::$settings['cl']    += array('paramType' => 'more');
        self::$settings['chart'] += array('paramType' => 'more');

        /* Data validate */
        self::$settings['xaxis'] += 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;
        self::$config['grid']   = $lang->gridConfig;
        self::$config['legend'] = $lang->legendConfig;

        return self::$config;
    }
}
