<?php
//require_once dirname(__DIR__) . '/base/hypothesis.php';
require_once dirname(dirname(__DIR__)) . '/das/methods/vendor/autoload.php';
require_once dirname(dirname(__DIR__)) . '/zendasmath/basic/combination.php';
require_once dirname(dirname(__DIR__)) . '/zendasmath/basic/describe.php';
require_once dirname(dirname(__DIR__)) . '/dataframe/regression/polynomial.php';
require_once dirname(dirname(__DIR__)) . '/dataframe/plotly.php';

class Scatter
{
    public $dataframe;

    public $xaxis;

    public $yaxises;

    public $lang;

    public $groups;

    public $errorLiner;

    public function __construct($dataframe, $xaxis, $yaxises, $lang)
    {
        $this->dataframe = $dataframe;
        $this->xaxis     = $xaxis;
        $this->yaxises   = $yaxises;
        $this->lang      = $lang;

        $this->groups     = array();
        $this->errorLiner = array();
    }

    public function initGroups()
    {
        $xdata = $this->dataframe->col($this->xaxis, 'number')->data;
        foreach($this->yaxises as $yaxis)
        {
            $ydata = $this->dataframe->col($yaxis, 'number')->data;

            $this->groups[$yaxis] = array();
            $group         = new stdclass();
            $group->y      = $yaxis;
            $group->titles = $this->dataframe->columns[$this->xaxis];
            $group->xdata  = $xdata;
            $group->ydata  = $ydata;

            $this->groups[$yaxis][] = $group;
        }
    }

    public function setGroups($typeVar)
    {
        $this->groups = array();
        $groupArr = array();
        $typeArr  = array();
        foreach($typeVar as $var)
        {
            $column     = $this->dataframe->col($var, 'any');
            $typeArr[]  = $column->data;
            $groupArr[] = array_keys(array_count_values(Describe::notNull($column->data)));
        }

        if(count($groupArr) > 1)
        {
            $combination  = new Combination($groupArr);
            $combinations = $combination->getCombination();
        }
        else
        {
            $combinations = array_map(fn($val) => array($val), $groupArr[0]);
        }

        $xNotNullData = Describe::notNull($this->dataframe->col($this->xaxis, 'number')->data);

        $xData = $this->dataframe->col($this->xaxis, 'number')->data;
        foreach($this->yaxises as $yaxis)
        {
            $this->groups[$yaxis] = array();

            $yData = $this->dataframe->col($yaxis, 'number')->data;
            foreach($combinations as $combination)
            {
                $titles = $combination;

                $xdata = array();
                $ydata = array();
                $numCount = 0;

                foreach($xData as $xkey => $xvalue)
                {
                    $judge = true;

                    if(!Describe::checkNotNull($xvalue)) $judge = false;
                    if(!Describe::checkNotNull($yData[$xkey])) $judge = false;
                    foreach($titles as $index => $title)
                    {
                        if(!Describe::checkNotNull($typeArr[$index][$xkey])) $judge = false;
                        if($typeArr[$index][$xkey] != $title) $judge = false;
                    }

                    if($judge)
                    {
                        $numCount ++;
                        $xdata[] = $xvalue;
                        $ydata[] = $yData[$xkey];
                    }
                }

                if($numCount)
                {
                    $group = new stdclass();
                    $group->y = $yaxis;
                    $group->titles = $titles;
                    $group->N = $numCount;
                    $group->xdata = $xdata;
                    $group->ydata = $ydata;

                    $this->groups[$yaxis][] = $group;
                }
            }
        }
    }

    public function getGroupResult($fit, $xName, $yName)
    {
        global $dasLang;
        $result = new stdclass();
        $result->type  = 'chart';
        $result->title = '';

        $result->data = array();
        $result->data['type'] = 'scatter';
        $result->yaxisName = array();

        $datas = array();
        foreach($this->yaxises as $yaxis)
        {
            $ys     = $this->groups[$yaxis];
            foreach($ys as $y)
            {
                $name = $this->dataframe->columns[$yaxis] . ' - ' . (is_array($y->titles) ? implode(',', $y->titles) : $y->titles);

                $xdata = $y->xdata;
                $ydata = $y->ydata;
                if($fit == 'show')
                {
                    $check = $this->checkData(Describe::notNull($xdata), Describe::notNull($ydata));
                    if(empty($xdata) or count($xdata) <= 2) $check = 0;
                    if(!$check)
                    {
                        $error = new stdclass();
                        $error->name = $name;
                        $this->errorLiner[] = $error;
                    }
                    else
                    {
                        $points = array();
                        foreach($xdata as $key => $xvalue) $points[] = array($xvalue, $ydata[$key]);

                        $regr = new Polynomial($this->dataframe, array($xdata, $ydata), 1);
                        $xpoints = array(min($xdata), max($xdata));
                        $ypoints = array($regr->evaluate(min($xdata)), $regr->evaluate(max($xdata)));
                        $data    = array('name' => $this->lang->matching . ':' . $name, 'x' => $xpoints, 'y' => $ypoints, 'mode' => 'lines', 'type' => 'scatter');
                        $datas[] = $data;
                    }
                }

                $data = array('x' => $xdata, 'y' => $ydata, 'name' => $name, 'mode' => 'markers', 'type' => 'scatter', 'marker' => array('size' => $this->dataframe->pointSize));
                $data = getHoverTemplateXY($data, array('xname' => $this->dataframe->columns[$this->xaxis], 'yname' => $this->dataframe->columns[$y->y], 'extra' => $name, 'custom' => getOrderCustom($y->xdata)));
                $datas[] = $data;
            }
            $result->yaxisName[] = $this->dataframe->columns[$yaxis];
        }

        $result->xaxisName      = !empty($xName) ? $xName : $this->dataframe->columns[$this->xaxis];
        $result->yaxisName      = $yName;
        $result->data['data']   = json_encode($datas);
        $result->data['layout'] = array('xaxis' => array('title' => $result->xaxisName), 'yaxis' => array('title' => $result->yaxisName));

        $grid   = $dasLang->config->gridConfig;
        $legend = $dasLang->config->legendConfig;
        $legend['defaultValue'] = 'true';
        $result->data['config'] = array('grid' => $grid, 'legend' => $legend);

        return $result;

    }

    public function checkErrorLiner()
    {
        return !empty($this->errorLiner);
    }

    public function buildErrorLinerResult()
    {
        $html = "<h4>{$this->lang->errorLiner}</h4>";

        $errors = '';
        $count  = 0;
        foreach($this->errorLiner as $error)
        {
            $errors .= $error->name . ";";
            //$count ++;
            //if($count % 4 == 0) $errors .= "\n";
        }
        $html .= '<pre>' . $errors . '</pre>';

        $textResult = new stdclass();

        $textResult->type  = 'text';
        $textResult->title = '';
        $textResult->data  = array();
        $textResult->data['content'] = $html;
        $textResult->data['type']    = 'html';
        return $textResult;
    }

    public static function checkData($x, $y)
    {
        $countX = array_unique($x);
        $countY = array_unique($y);

        return count($countX) != 1 and count($countY) != 1;
    }

}
