<?php
namespace EdgeManager\EDataCapture;

class ENodeConfigure {
    function __construct(
        protected $dbconn,
        protected $no_dup_code,
        protected $post = NULL,
        protected $get = NULL,
    ) {}

    function add_node() {
        pg_query($this -> dbconn, "BEGIN");
        if ($this -> no_dup_code) {
            $exists = pg_query($this -> dbconn, sprintf(
                "SELECT EXISTS(
                    SELECT 1 FROM hf_mes_scada_data_capture_node_configure
                    WHERE code = '%s'
                    AND working_subclass = '%s'
                )", $this -> post -> code, $this -> post -> working_subclass
            ));
        } else {
            $exists = pg_query($this -> dbconn, sprintf(
                "SELECT EXISTS(
                    SELECT 1 FROM hf_mes_scada_data_capture_node_configure
                    WHERE code = '%s'
                )", $this -> post -> code
            ));
        }
        
        if (pg_fetch_assoc($exists)['exists'] === 't') {
            pg_query($this -> dbconn, "ROLLBACK");
            return "REPLICATED";
        }

        $table_name = 'hf_mes_scada_data_capture_node_data_' . $this -> post -> working_subclass;
        // https://www.postgresql.org/docs/current/when-can-parallel-query-be-used.html
        $res[] = pg_query($this -> dbconn, sprintf(
            'CREATE TABLE IF NOT EXISTS "%s" (
                id serial8,
                code text NOT NULL,
                v_string text,
                v_int int,
                v_float float8,
                v_bool bool,
                device_code text NOT NULL,
                parent_device_code text,
                batch text,
                capture_time timestamp NOT NULL DEFAULT NOW()
            )', $table_name
        ));
        $res[] = pg_insert(
            $this -> dbconn,
            'hf_mes_scada_data_capture_node_configure',
            (array) $this -> post
        );
        // 检查一下，如果超表已经有了就不要尝试重复创建了
        $table_exists = pg_query($this -> dbconn, sprintf(
            "SELECT *
            FROM timescaledb_information.hypertables
            WHERE hypertable_name = '%s'
            ", $table_name
        ));
        if (!in_array($table_name, pg_fetch_all_columns($table_exists, 1))) {
            $res[] = $node_count = pg_query($this -> dbconn, "SELECT COUNT(*) from timescaledb_information.data_nodes");
            $node_count = intval(pg_fetch_assoc($node_count)['count']);
            if ($node_count === 0) {
                $res[] = pg_query($this -> dbconn, sprintf("SELECT create_hypertable('\"%s\"', 'capture_time')", $table_name));
            } else {
                $res[] = pg_query($this -> dbconn, sprintf("SELECT create_distributed_hypertable('\"%s\"', 'capture_time', 'code')", $table_name));
                $res[] = pg_query($this -> dbconn, sprintf("add_dimension('\"%s\"', 'device_code', number_partitions => %s)", $node_count));
                $res[] = pg_query($this -> dbconn, sprintf("add_dimension('\"%s\"', 'parent_device_code', number_partitions => %s)", $node_count));
                $res[] = pg_query($this -> dbconn, sprintf("add_dimension('\"%s\"', 'batch', number_partitions => %s)", $node_count));
            }
            
            $res[] = pg_query($this -> dbconn, sprintf(
                'CREATE INDEX ON "%s" (v_string, v_int, v_float, v_bool, capture_time DESC)
                WHERE COALESCE(v_string, v_int::text, v_float::text, v_bool::text) IS NOT NULL
                ', $table_name
            ));
        }

        if (in_array(false, $res)) {
            pg_query($this -> dbconn, "ROLLBACK");
            return false;
        } else {
            pg_query($this -> dbconn, "COMMIT");
            return true;
        }
    }

    function remove_node() {
        pg_query($this -> dbconn, "BEGIN");
        $res[] = pg_delete(
            $this -> dbconn,
            'hf_mes_scada_data_capture_node_configure',
            (array) $this -> post,
        );
        $exists = pg_query($this -> dbconn, sprintf(
            "SELECT EXISTS(
                SELECT 1 FROM hf_mes_scada_data_capture_node_configure WHERE working_subclass = '%s'
            )", $this -> post -> working_subclass
        ));
        if (pg_fetch_assoc($exists)['exists'] == 'f') {
            $res[] = pg_query($this -> dbconn, sprintf(
                'DROP TABLE "hf_mes_scada_data_capture_node_data_%s"',
                $this -> post -> working_subclass
            ));
        }
        
        if (in_array(false, $res)) {
            pg_query($this -> dbconn, "ROLLBACK");
            return false;
        } else {
            pg_query($this -> dbconn, "COMMIT");
            return true;
        }
    }

    function update_node() {
        return pg_update(
            $this -> dbconn,
            'hf_mes_scada_data_capture_node_configure',
            (array) $this -> post,
            ['id' => $this -> post -> id]
        );
    }

    function get_nodes() {
        $res = pg_query($this -> dbconn, "SELECT * FROM hf_mes_scada_data_capture_node_configure");
        return pg_fetch_all($res);
    }

    static function get_working_subclasses($dbconn) {
        $res = pg_query($dbconn, "SELECT DISTINCT ON (working_subclass) working_subclass FROM hf_mes_scada_data_capture_node_configure");
        return pg_fetch_all_columns($res, 0);
    }

    static function get_working_subclasses_by_codes($dbconn, $code) {
        $res = pg_query($dbconn, sprintf(
            "SELECT working_subclass
            FROM hf_mes_scada_data_capture_node_configure
            WHERE code = '%s'",
            $code
        ));
        return pg_fetch_assoc($res);
    }

    function get_codes_by_working_subclasses() {
        $res = pg_query($this -> dbconn, sprintf(
            "SELECT code
            FROM hf_mes_scada_data_capture_node_configure
            WHERE working_subclass = '%s'",
            $this -> get['working_subclass']
        ));
        return pg_fetch_all_columns($res, 0);
    }
}
