<?php
namespace EdgeManager\EDataCapture;
use \Workerman\Connection\AsyncTcpConnection;

class EDataCapture {
    function __construct(
        protected $dbconn,
        protected $no_dup_code,
        protected $relay_device_status,
        protected $post = NULL,
        protected $get = NULL,
        public $check_res = NULL,
        protected $working_subclass = NULL,
        protected $code_type = [],
        protected $data = [],
        protected $status = array(
            1 => 'IDLE',
            2 => 'RUN',
            3 => 'FINISH',
            4 => 'TROUBLE',
            5 => 'PAUSE',
            6 => 'OFFLINE')
    ) {
        if (!is_null($this -> post)) {
            if(isset($this -> post -> param -> working_subclass)){
                if (!in_array(
                    $this -> post -> param -> working_subclass,
                    ENodeConfigure::get_working_subclasses($this -> dbconn)
                )) {
                    $this -> check_res = 'WRONG_WORKING_SUBCLASS';
                    return;
                } else {
                    $this -> working_subclass =  $this -> post -> param -> working_subclass;
                }
            }else{
                if ($this -> no_dup_code) {
                    $this -> check_res = 'WRONG_WORKING_SUBCLASS';
                    return;
                }
                $working_subclass = ENodeConfigure::get_working_subclasses_by_codes($this -> dbconn, $this -> post -> param -> data[0] -> code);
                $this -> working_subclass = $working_subclass['working_subclass'];
            }
    
            $res = pg_fetch_all(pg_query($this -> dbconn, sprintf(
                "SELECT code, type, category
                FROM hf_mes_scada_data_capture_node_configure
                WHERE working_subclass = '%s'",
                $this -> working_subclass
            )));
            
            $code_type = &$this -> code_type;
            array_walk($res, function($v, $k) use (&$code_type) {
                $code_type[$v['code']] =  array('type' => $v['type'], 'category' => $v['category']);
            });

            foreach ($this -> post -> param -> data as &$row) {
                if (($code_type[$row -> code]['type']) === 'float' and is_int($row -> value))
                    $row -> value = (float) number_format((float) $row -> value, 1, '.', '');
                $check_func = 'is_' . $code_type[$row -> code]['type'];
                if (!$check_func($row -> value)) {
                    $this -> check_res = 'MISMATCH_TYPE';
                    return;
                }

                if (!isset($row -> device_code)) {
                    $this -> check_res = 'NO_DEVICE_CODE';
                    return;
                }
                if($this -> relay_device_status && $code_type[$row -> code]['category'] === 'DEVICE_STATUS'){
                    if(!is_int($row -> value) && !in_array($row -> value , $this->status)){
                        $this -> check_res = 'MISMATCH_TYPE';
                        return;
                    }
                    $task_data = array(
                        'action' => 'set_device_status',
                        'param'   => array(
                            "device_code" => $row -> parent_device_code,
                            "status" => is_int($row -> value) ? $this->status[$row -> value] : $row -> value,
                            "errcode" => $row -> errcode ?? NULL,
                            "msg" => $row -> msg ?? NULL,
                        ),
                    );
                    $task_connection = new AsyncTcpConnection('Text://127.0.0.1:1888');
                    
                    $task_connection -> send(json_encode($task_data));
                    $task_connection -> onMessage = function(AsyncTcpConnection $task_connection, $task_result){
                        $task_connection -> close();
                    };
                    // 执行异步连接
                    $task_connection->connect();
                }

                $this -> data[$code_type[$row -> code]['type']][] = [
                    'code' => $row -> code,
                    'value' => $row -> value,
                    'device_code' => $row -> device_code,
                    'parent_device_code' => $row -> parent_device_code ?? NULL,
                    'batch' => $row -> batch ?? NULL
                ];
            }
            unset($row);
        }
    }

    function set_node_data() {
        foreach ($this -> data as $type => $value) {
            foreach (array_chunk($value, 6710885, true) as $chunk) {
                $sql_head = sprintf(
                    'INSERT INTO "hf_mes_scada_data_capture_node_data_%s" (code, v_%s, device_code, batch)
                    VALUES',
                    $this -> working_subclass,
                    $type
                );
                foreach ($chunk as $row) {
                    $sql_values[] = sprintf(
                        "('%s', '%s', '%s', '%s')",
                        $row['code'],
                        $row['value'] === false ? 'f' : $row['value'],
                        $row['device_code'],
                        $row['parent_device_code'] ?? NULL,
                        $row['batch'] ?? NULL
                    );
                }
                $res[] = pg_query($this -> dbconn, $sql_head . implode(',', $sql_values));
                unset($row, $sql_values);
            }
            unset($chunk);
        }
        unset($code, $value);
        return true;
    }

    function get_node_data() {
        // 先把code和name的对应关系拿到（快于OUTER JOIN）
        $res = pg_fetch_all(pg_query($this -> dbconn, sprintf(
            "SELECT code, name
            FROM hf_mes_scada_data_capture_node_configure
            WHERE working_subclass = '%s'",
            $this -> get['working_subclass']
        )));

        $code_name = [];
        array_walk($res, function(&$v, $k) use (&$code_name) {
            $code_name[$v['code']] = $v['name'];
        });
        
        $sql_cmd = sprintf(
            'SELECT id, code, COALESCE(v_string, v_int::text, v_float::text, v_bool::text) AS value, device_code, batch, capture_time
            FROM "hf_mes_scada_data_capture_node_data_%s"
            WHERE capture_time >= \'%s\' AND capture_time <= \'%s\'',
            $this -> get['working_subclass'],
            date("Y-m-d H:i:s", $this -> get['start_time'] / 1000),
            date("Y-m-d H:i:s", $this -> get['end_time'] / 1000)
        );

        if (isset($this -> get['code']))
            $sql_cmd .= sprintf(" AND code = '%s'", $this -> get['code']);

        $res = pg_fetch_all(pg_query($this -> dbconn, $sql_cmd));

        if (count($res) > 2e6)
            return "TOO_MANY";

        array_walk($res, function(&$v, $k) use ($code_name) {
            $v['name'] = $code_name[$v['code']];
            if (in_array($v['value'], ['true', 'false']))
                $v['value'] = $v['value'] === 'true' ? true : false;
            if (is_numeric($v['value'])) {
                if (str_contains($v['value'], '.'))
                    $v['value'] = (float) $v['value'];
                else
                    $v['value'] = (int) $v['value'];
            }
        });
        
        return $res;
    }
}
