<?php
require_once LIB_ROOT . '/dataframe/hypothesis/proportion1.php';
require_once LIB_ROOT . '/dataframe/checkdata.php';
require_once LIB_ROOT . '/dataframe/validatedata.php';

/* Proportion1 plot method 基本量统计 */
class proportion1Method
{
    /* Method name 分析方法内部名称 */
    public static $name = 'proportion1';

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

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

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

        $data = array();

        $result = array();

        $dataDesc        = $settings['data'];
        $event           = $settings['event'];
        $sample          = $settings['sample'];
        $sampleCol       = $settings['sampleCol'];
        $method          = $settings['method'];
        $hypotheses      = $settings['hypotheses'];
        $hypothesesRatio = $settings['hypothesesRatio'];
        $cl              = $settings['cl'];
        $alternativeHypo = $settings['alternativeHypo'];

        if($dataDesc == 'sampleData')
        {
            $check = new checkData();
            $check->setDataList($dataframe->colsData($sampleCol), $dataframe->colsName($sampleCol), self::$settings['sampleCol']['validate']);

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

        $textResult = $dataframe->getTextResult($lang->perfanalysis->methods->hypothesis['proportion1'] . ': ' . $dasLang->proportion1->sample . ' ' . $lang->versus . ' ' . $dasLang->proportion1->event);
        $textResult->children = 1;

        $result[] = $textResult;
        $result[] = self::buildDescResult($dataframe, $settings);

        if($hypotheses == 'true') $result[] = self::buildTestResult($dataframe, $settings);

        return $result;
    }

    public static function buildDescResult($dataframe, $settings)
    {
        global $dasLang;
        $lang = $dasLang->proportion1;

        $dataDesc        = $settings['data'];
        $event           = $settings['event'];
        $sample          = $settings['sample'];
        $sampleCol       = $settings['sampleCol'];
        $method          = $settings['method'];
        $hypotheses      = $settings['hypotheses'];
        $cl              = $settings['cl'];
        $alternativeHypo = $settings['alternativeHypo'];

        $data = array();

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

        $summary = self::summaryData($dataframe, $dataDesc, $event, $sample, $sampleCol);
        foreach($summary as $sdata)
        {
            [$event, $sample, $name] = $sdata;
            $data[] = self::buildDescData($dataframe, $event, $sample, $cl, $method, $alternativeHypo, $name);
        }

        $columns = array();
        if(count($data) > 1) $columns[] = $lang->variable;
        $columns[] = $lang->methodTitle;
        $columns[] = $lang->sample;
        $columns[] = $lang->event;
        $columns[] = $lang->sampleP;
        $columns[] = sprintf($lang->CI, $cl);

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

        return $result;
    }

    public static function buildDescData($dataframe, $event, $sample, $cl, $method, $type, $variable = null)
    {
        global $dasLang;
        $lang = $dasLang->proportion1;

        $prop = new Proportion1($dataframe);

        $limits = array('gt' => 'low', 'lt' => 'up', 'noEqual' => 'all');
        $limit  = $limits[$type];

        if($method == 'normalMethod')
        {
            $CI = $prop->normalCI($event, $sample, $cl, $limit);
        }
        else
        {
            $CI = $prop->exactCI($event, $sample, $cl, $limit);
        }

        $data   = array();
        if(!empty($variable)) $data[] = $variable;
        $data[] = $lang->$method;
        $data[] = $sample;
        $data[] = $event;
        $p      = round($event / $sample, $dataframe->decimals);
        $data[] = $p;
        $data[] = "({$CI[0]}, {$CI[1]})";

        return $data;
    }

    public static function buildTestResult($dataframe, $settings)
    {
        global $dasLang;
        $lang = $dasLang->proportion1;

        $dataDesc        = $settings['data'];
        $event           = $settings['event'];
        $sample          = $settings['sample'];
        $sampleCol       = $settings['sampleCol'];
        $method          = $settings['method'];
        $hypotheses      = $settings['hypotheses'];
        $p₀              = $settings['hypothesesRatio'];
        $cl              = $settings['cl'];
        $alternativeHypo = $settings['alternativeHypo'];

        $data = array();

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

        $signs = array('lt' => '<', 'noEqual' => '≠', 'gt' => '>');
        $sign = $signs[$alternativeHypo];

        $result->desc  = sprintf($lang->testDesc, $p₀, $sign, $p₀);

        $summary = self::summaryData($dataframe, $dataDesc, $event, $sample, $sampleCol);
        foreach($summary as $sdata)
        {
            [$event, $sample, $name] = $sdata;
            $data[] = self::buildTestData($dataframe, $event, $sample, $method, $p₀, $alternativeHypo, $name);
        }

        $columns = array();
        if(count($data) > 1) $columns[] = $lang->variable;
        if($method == 'normalMethod') $columns[] = $lang->zValue;
        $columns[] = $lang->pValue;

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

        return $result;
    }

    public static function buildTestData($dataframe, $event, $sample, $method, $p, $type, $variable = null)
    {
        global $dasLang;
        $lang = $dasLang->proportion1;

        $prop = new Proportion1($dataframe);

        $data = array();
        if(!empty($variable)) $data[] = $variable;
        if($method == 'normalMethod')
        {
            [$z, $pValue] = $prop->normalTest($event, $sample, $p, $type);
            $data[] = $z;
        }
        else
        {
            $pValue = $prop->exactTest($event, $sample, $p, $type);
        }

        $data[] = $pValue;

        return $data;
    }

    public static function summaryData($dataframe, $dataDesc, $event, $sample, $cols)
    {
        global $dasLang;
        $lang = $dasLang->proportion1;

        if($dataDesc == 'summary') return array(array($event, $sample, null));

        $sliceDF = $dataframe->sliceDataframe($dataframe, $cols, 'any');
        $datas = $sliceDF->cols($cols, 'any');

        $result = array();
        foreach($datas as $data)
        {
            $values = array_count_values($data->notNull());
            $keys   = array_keys($values);
            asort($keys);

            $event  = $values[end($keys)];
            $sample = array_sum($values);
            $name   = count($datas) > 1 ? $data->name : null;
            $result[] = array($event, $sample, $name);
        }

        return $result;
    }

    public static function checkData($dataframe, $cols)
    {
        global $dasLang;
        $lang = $dasLang->proportion1;

        $check = checkNullColumns($dataframe, $cols, $dasLang->common->errorLine);
        if($check['result'] == 'fail') return $check;

        $sliceDF = $dataframe->sliceDataframe($dataframe, $cols, 'any');
        $datas = $sliceDF->cols($cols, 'any');

        $allData = array();
        foreach($datas as $data)
        {
            $allData = array_merge($allData, $data->notNull());
        }

        $values = array_count_values($allData);

        if(count($values) > 2) return array('result' => 'fail', 'message' => $lang->errorEventAll);

        return array('result' => 'success');
    }

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

        /* Basic settings */
        self::$settings['data']            = array('name' => 'data',            'label' => $lang->data);
        self::$settings['sample']          = array('name' => 'sample',          'label' => $lang->sample,          'required' => true);
        self::$settings['sampleCol']       = array('name' => 'sampleCol',       'label' => $lang->sampleCol,       'required' => true);
        self::$settings['event']           = array('name' => 'event',           'label' => $lang->event,           'required' => true);
        self::$settings['cl']              = array('name' => 'cl',              'label' => $lang->cl,              'required' => true);
        self::$settings['hypotheses']      = array('name' => 'hypotheses',      'label' => $lang->hypotheses);
        self::$settings['hypothesesRatio'] = array('name' => 'hypothesesRatio', 'label' => $lang->hypothesesRatio, 'required' => true);
        self::$settings['alternativeHypo'] = array('name' => 'alternativeHypo', 'label' => $lang->alternativeHypo);
        self::$settings['method']          = array('name' => 'method',          'label' => $lang->methodTitle);

        /* Type settings */
        self::$settings['data']            += array('type' => 'enum', 'enumOptions' => array('sampleData' => $lang->sampleData, 'summary' => $lang->summary), 'defaultValue' => 'sampleData');
        self::$settings['sample']          += array('type' => 'number', 'columnType' => 'number');
        self::$settings['sampleCol']       += array('type' => 'list', 'listType' => 'column', 'columnType' => 'any');
        self::$settings['event']           += array('type' => 'number', 'columnType' => 'number');
        self::$settings['cl']              += array('type' => 'number', 'columnType' => 'number', 'defaultValue' => 95.00);
        self::$settings['hypotheses']      += array('type' => 'enum', 'columnType' => 'any', 'enumOptions' => $lang->hypothesesEnum, 'defaultValue' => 'false');
        self::$settings['hypothesesRatio'] += array('type' => 'number', 'columnType' => 'number');
        self::$settings['alternativeHypo'] += array('type' => 'enum', 'ui' => 'select', 'enumOptions' => $lang->alternativeHypoEnum, 'defaultValue' => 'noEqual');
        self::$settings['method']          += array('type' => 'enum', 'ui' => 'select', 'enumOptions' => array('exactMethod' => $lang->exactMethod, 'normalMethod' => $lang->normalMethod), 'defaultValue' => 'exactMethod');

        /* Limit settings */
        self::$settings['sample']          += array('conditions' => array('data' => 'summary'), 'pattern' => "/^[1-9]([0-9]{1,7})?$/", 'error' => $lang->errorSample, 'gt' => 'event');
        self::$settings['sampleCol']       += array('conditions' => array('data' => 'sampleData'));
        self::$settings['event']           += array('conditions' => array('data' => 'summary'), 'pattern' => "/^[\d]+$/", 'error' => $lang->errorEvent);
        self::$settings['cl']              += array('min' => 0.0001, 'max' => 99.9999, 'error' => $lang->errorCL);
        self::$settings['hypothesesRatio'] += array('min' => 0.00000001, 'max' => 0.999999, 'pattern' => "/^(([1-9]{1}\\d*)|(0{1}))(\\.(\\d){0,8})?$/", 'error' => $lang->errorRatio, 'conditions' => array('hypotheses' => 'true'));
        self::$settings['alternativeHypo'] += array('conditions' => array('hypotheses' => 'true'));

        /* Col grid settings */
        self::$settings['data']            += array('col' => 6);
        self::$settings['hypotheses']      += array('col' => 6);

        /* More settings */
        self::$settings['cl']              += array('paramType' => 'more');
        self::$settings['hypotheses']      += array('paramType' => 'more');
        self::$settings['hypothesesRatio'] += array('paramType' => 'more');
        self::$settings['alternativeHypo'] += array('paramType' => 'more');
        self::$settings['method']          += array('paramType' => 'more');

        /* Data validate */
        self::$settings['sampleCol'] += array('validate' => array('continuous', 'columnUnique <= 2'));

        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'];
    }
}
