<?php
require_once dirname(__DIR__) . '/base/hypothesis.php';
require_once dirname(dirname(__DIR__)) . '/zendasmath/distribution/stdnormal.php';
require_once dirname(dirname(__DIR__)) . '/zendasmath/distribution/hypergeometric.php';

/**
 * Proportion2
 */
class proportion2 extends hypothesis
{
    public $event1;

    public $event2;

    public $sample1;

    public $sample2;

    public $p1;

    public $p2;

    public $dataframe;

    public function __construct($dataframe, $event1, $event2, $sample1, $sample2)
    {
        $this->event1  = $event1;
        $this->event2  = $event2;
        $this->sample1 = $sample1;
        $this->sample2 = $sample2;

        $this->p1 = $event1 / $sample1;
        $this->p2 = $event2 / $sample2;

        parent::__construct($dataframe);
    }

    /**
     * Get data in same col.
     * success1 represents the success of the col1Data, success2/fail2 => success/fail of the col2Data.
     *
     * @access public
     * @return array
     */
    public static function inSameColData($column1Data, $column2Data)
    {
        $column1Values  = array_count_values($column1Data);
        $column1Keys    = array_keys($column1Values);
        $column2Values  = array_count_values($column2Data);
        $column2Keys    = array_keys($column2Values);

        if(count($column1Keys) == 1) $success1 = $column1Keys[0];
        else $success1 = $column1Keys[0] > $column1Keys[1] ? $column1Keys[0] : $column1Keys[1];

        $fail2   = $column2Keys[0] < $column2Keys[1] ? $column2Keys[0] : $column2Keys[1];
        $sam1    = $column2Values[$fail2];
        $eve1    = 0;

        $success2 = $column2Keys[0] > $column2Keys[1] ? $column2Keys[0] : $column2Keys[1];
        $sam2     = $column2Values[$success2];
        $eve2     = 0;

        foreach($column2Data as $key => $value)
        {
            if($value == $fail2 and $column1Data[$key] == $success1) $eve1 ++;
            if($value == $success2 and $column1Data[$key] == $success1) $eve2 ++;
        }

        return  array($success1, $success2, $fail2, $eve1, $eve2, $sam1, $sam2);
    }

    /**
     * Get data not in same col.
     *
     * @access public
     * @return array
     */
    public static function notSameColData($column1Data, $column2Data)
    {
        $allValues  = array_count_values(array_merge($column1Data, $column2Data));
        $allKeys    = array_keys($allValues);

        $column1Values  = array_count_values($column1Data);
        $column1Keys    = array_keys($column1Values);
        $column2Values  = array_count_values($column2Data);
        $column2Keys    = array_keys($column2Values);

        if(count($allKeys) == 1)
        {
            $success = $fail = $allKeys[0];
        }
        else
        {
            $success = $allKeys[0] > $allKeys[1] ? $allKeys[0] : $allKeys[1];
            $fail    = $allKeys[0] < $allKeys[1] ? $allKeys[0] : $allKeys[1];
        }

        $sam1 = count($column1Data);
        $eve1 = isset($column1Values[$success]) ? $column1Values[$success] : 0;
        $sam2 = count($column2Data);
        $eve2 = isset($column2Values[$success]) ? $column2Values[$success] : 0;

        return array($success, $fail, $eve1, $eve2, $sam1, $sam2);
    }

    /**
     * Describe information of proportion2.
     *
     * @param bool $round
     * @access public
     * @return object
     */
    public function describe($round = true)
    {
        $p1 = $this->dataframe->roundDigit($this->p1, $round);
        $p2 = $this->dataframe->roundDigit($this->p2, $round);

        $result = new stdclass();
        $result->desc1 = array($this->sample1, $this->event1, $p1);
        $result->desc2 = array($this->sample2, $this->event2, $p2);

        return $result;
    }

    /**
     * CI of proportion2.
     *
     * @param float $cl
     * @param bool $round
     * @access public
     * @return object
     */
    public function CI($cl, $round = true)
    {
        if($this->p1 == 0 and $this->p2 == 0) return array('-', '-');

        $α = 1 - $cl / 100;

        $standardNormal = new standardNormal();
        $p = 1 - $α / 2;
        $z = $standardNormal->inverse($p);

        $part1 = $this->p1 * (1 - $this->p1) / $this->sample1;
        $part2 = $this->p2 * (1 - $this->p2) / $this->sample2;
        $part3 = $z * sqrt($part1 + $part2);

        $uci = $this->p1 - $this->p2 + $part3;
        $lci = $this->p1 - $this->p2 - $part3;

        $uci = $this->dataframe->roundDigit($uci, $round);
        $lci = $this->dataframe->roundDigit($lci, $round);

        return array($lci, $uci);
    }

    /**
     * Deviation of proportion2.
     *
     * @param bool $round
     * @access public
     * @return object
     */
    public function deviation($round = true)
    {
        $deviation = $this->p1 - $this->p2;
        $deviation = $this->dataframe->roundDigit($deviation, $round);

        return $deviation;
    }

    /**
     * Normal test of proportion2.
     *
     * @param string $type > ≠ <
     * @param string $testMethod independence merge
     * @param float $hypoDeviation
     * @param bool $round
     * @access public
     * @return object
     */
    public function normalTest($type, $testMethod, $hypoDeviation, $round = true)
    {
        $zValue = '-';
        $pValue = '-';

        $d  = $hypoDeviation;
        $p0 = ($this->event1 + $this->event2) / ($this->sample1 + $this->sample2);

        $standardNormal = new standardNormal();

        if($testMethod == 'm' and $d == 0)
        {
            $part1 = $p0 * (1 - $p0);
            $part2 = 1 / $this->sample1 + 1 / $this->sample2;
            $zValue = ($this->p1 - $this->p2) / sqrt($part1 * $part2);
        }
        else
        {
            $part1 = $this->p1 * (1 - $this->p1) / $this->sample1;
            $part2 = $this->p2 * (1 - $this->p2) / $this->sample2;

            if($part1 + $part2 != 0) $zValue = ($this->p1 - $this->p2 - $d) / sqrt($part1 + $part2);
        }

        if(is_numeric($zValue))
        {
            $cdf = $standardNormal->cdf($zValue);

            if($type == 'gt') $pValue = 1 - $cdf;
            if($type == 'ne') $pValue = 2 * (1 - $cdf);
            if($type == 'lt') $pValue = $cdf;

            if($pValue > 1) $pValue = 2 - $pValue;

            $zValue = $this->dataframe->roundDigit($zValue, $round);
            $pValue = $this->dataframe->roundDigit($pValue, $round);
        }

        return array($zValue, $pValue);
    }

    /**
     * Fisher test of proportion2.
     *
     * @param string $type > ≠ <
     * @param string $testMethod independence merge
     * @param float $hypoDeviation
     * @param bool $round
     * @access public
     * @return object
     */
    public function fisherTest($type, $testMethod, $hypoDeviation, $round = true)
    {
        $result = '-';
        $N  = $this->sample1 + $this->sample2;
        $K  = $this->event1 + $this->event2;
        $n  = $this->sample1;
        $x1 = $this->event1;

        $hypergeo = new zHypergeometric($N, $K, $n);;
        // TODO 超几何分布的众数计算不准确

        if($type == 'lt') $result = $hypergeo->cdf($x1);
        if($type == 'gt') $result = 1 - $hypergeo->cdf($x1 - 1);

        if($type == 'ne')
        {
            /*
            if($x1 < $mode)
            {
                $y = floor($mode) == $mode ? $mode + 1 : ceil($mode);
                $pu = $hypergeo->cdf($y - 1);
                $pl = 1 - $hypergeo->cdf($x1);
                $result = $pl + $pu;
            }

            if($x1 == $mode) $result = 1;

            if($x1 > $mode)
            {
                $y = floor($mode) == $mode ? $mode - 1 : max(1, floor($mode));
                $pu = $hypergeo->cdf($x1 - 1);
                $pl = 1 - $hypergeo->cdf($y);
                $result = $pl + $pu;
            }
             */
            // TODO 众数需要再计算
            $result = '-';
        }

        $result = $this->dataframe->roundDigit($result, $round);

        return $result;
    }
}
