<?php

/**
 * Smart Reporting Package
 * Version 9.0.0
 * Author : Webuccino
 * All copyrights are preserved to Webuccino
 * URL : https://mysqlreports.com/
 */
ini_set('display_errors', 0);

class srm_dashboard implements dashboard_interface
{
    private $dashboard_connection;

    public function __construct($dashboard_connection)
    {
        $this->dashboard_connection = $dashboard_connection;
    }

/*
 * ===============================================================================
 *               Security methods to ptotect reports and wizard
 * ===============================================================================
 */

    /*
     * @param $report_id report id
     * return public_report , private_report const or False if report dosn't exist
     */

    public function get_report_access_type($report_id)
    {

        if (!is_int($report_id)) {
            return false;
        }

        $reader       = new Reader(tables_prefix . table_resources, $this->dashboard_connection);
        $access_level = $reader->get_property_by_id(column_resources_access_level, $report_id, column_resources_id);

        if ($access_level) {
            return $access_level;
        } else {
            srm_dashboard::log("Report dosn't exist or its access level in Null", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", "error", "report_builder_common", "", json_encode(array("report_id" => $report_id)));
            return false;
        }

    }

    /*
     * @param $report_id report id
     * return public_report , private_report const or False if report dosn't exist
     */

    public function get_report_access_creator($report_id)
    {

        if (!is_int($report_id)) {
            return false;
        }

        $reader           = new Reader(tables_prefix . table_resources, $this->dashboard_connection);
        $resource_creator = $reader->get_property_by_id(column_resources_creator, $report_id, column_resources_id);

        if ($resource_creator) {
            return $resource_creator;
        } else {
            srm_dashboard::log("Report doesn't exist or its access level in Null", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", "error", "report_builder_common", "", json_encode(array("report_id" => $report_id)));
            return false;
        }

    }

    /*
     * @param $report_id report id
     * return array of group IDs who has access to the report
     */

    public function get_private_report_permissions($report_id)
    {

        if (!is_int($report_id)) {
            return false;
        }

        $reader = new Reader(tables_prefix . table_resources_permissions, $this->dashboard_connection);
        return $reader->get_filtered_ids(column_resources_permissions_resource_id, $report_id, column_resources_permissions_group_id, "`" . column_resources_permissions_can_view . "` = 1");
    }

    /*
     *
     * return array of group Ids who has access to the wizard
     */

    public function get_wizard_permissions()
    {
        $reader                 = new Reader(tables_prefix . table_modules_permissions, $this->dashboard_connection);
        $blank_report_module_id = $this->get_blank_report_module_id('Reports');
        return $reader->get_filtered_ids(column_modules_permissions_module_id, $blank_report_module_id, column_modules_permissions_group_id, "`" . column_modules_permissions_can_add_new . "` = 1");
    }

/*
 * ===============================================================================
 *               Connection step in wizard
 * ===============================================================================
 */

    /*
     * @param $connection_string_name a valid connection name saved in DB
     * return Assoc array of connection properties or false if connection dosn't exist.
     */

    public function get_connection_details($connection_string_name)
    {
        $reader                = new Reader(tables_prefix . table_connection_strings, $this->dashboard_connection);
        $connection_db_details = $reader->filter_by_column(column_connection_name, trim($connection_string_name));

        if (is_array($connection_db_details) && !empty($connection_db_details) && count($connection_db_details) == 1) {
            $credentials = srm_decrept_connectionstring($connection_db_details[0][column_connection_string]);
            return array(
                column_connection_name      => $connection_db_details[0][column_connection_name],
                column_connection_db_type   => $connection_db_details[0][column_connection_db_type],
                column_connection_server    => $connection_db_details[0][column_connection_server],
                column_connection_user      => $credentials[column_connection_user],
                column_connection_pass      => $credentials[column_connection_pass],
                column_connection_db        => $connection_db_details[0][column_connection_db],
                column_connection_charset   => $credentials[column_connection_charset],
                column_connection_collation => $credentials[column_connection_collation],
                column_connection_port      => $credentials[column_connection_port]
            );
        } else {
            srm_dashboard::log("Can't get connection details", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", "error", "report_builder_common", "", "");
            return false;
        }

    }

    /*
     * return array Assoc array of properties of default connection
     */

    public function get_default_connection_details()
    {
        return array(
            column_connection_name      => default_connection_name,
            column_connection_db_type   => "MYSQL",
            column_connection_server    => DEFAULT_HOST,
            column_connection_user      => DEFAULT_DBUSER,
            column_connection_pass      => DEFAULT_DBPASS,
            column_connection_db        => DEFAULT_DBNAME,
            column_connection_charset   => "",
            column_connection_collation => "",
            column_connection_port      => ""
        );
    }

    /*
     * return array of saved connection names including the default connection name.
     */

    public function get_all_connection_names()
    {
        $result      = array();
        $reader      = new Reader(tables_prefix . table_connection_strings, $this->dashboard_connection);
        $result["0"] = default_connection_name;
        return array_merge($result, $reader->select_all_names_and_Ids(column_connection_name, column_connection_id, true));
    }

/*
 * ===============================================================================
 *               Groups and Categories steps in wizard
 * ===============================================================================
 */

    /*
     * return array of categories names or empty array if no categories.
     */

    public function get_all_categories_names()
    {
        $reader = new Reader(tables_prefix . table_categories, $this->dashboard_connection);
        return $reader->select_all_names_and_Ids(column_category_name, column_category_id, true);
    }

    /*
     * return array of group names or empty array if no groups.
     */

    public function get_all_groups_names()
    {
        $reader = new Reader(tables_prefix . table_groups, $this->dashboard_connection);
        return $reader->select_all_names_and_Ids(column_group_name, column_group_id, true);
    }

    /*
     * @param $report_id report id
     *
     * return string saved report name
     */

    public function get_existed_name($report_id)
    {

        if (!is_int($report_id)) {
            return false;
        }

        $reader = new Reader(tables_prefix . table_resources, $this->dashboard_connection);
        return $reader->get_property_by_id(column_resources_name, $report_id, column_resources_id);
    }

    public function get_last_report_id()
    {

        $reader = new Reader(tables_prefix . table_resources, $this->dashboard_connection);
        return $reader->get_last_report_id(
            $this->get_blank_report_module_id()
        );
    }

/*
 * ===============================================================================
 *              Creating a new report in Engine
 * ===============================================================================
 */

    /*
     * @param $name report name
     * @param $category_id valid forign key from categories table
     * @param $connection_name saved connection name
     * @param $creator valid forign key from users table
     * @param $access_level either private_report or public_report constant
     * return if success: the inserted record ID or: false if insert failed
     */

    public function save_new_blank_report($name, $category_id, $connection_name, $creator, $access_level = private_report)
    {
        $edited_name   = str_replace(" ", "", trim($name));
        $report_url    = report_base_path . "$edited_name/$edited_name.php";
        $connection_id = (strtolower($connection_name) != strtolower(default_connection_name)) ? $this->get_connection_id(trim($connection_name)) : 0;

        if (!$this->is_report_existed_by_url($report_url)) {

            if (
                $this->is_entity_exist_by_value(table_categories, column_category_id, $category_id) &&
                $this->is_entity_exist_by_value(table_users, column_users_id, $creator)
            ) {

                if (strtolower($connection_name) != strtolower(default_connection_name)) {
                    $resource_details = array(
                        column_resources_name          => $name,
                        column_resources_module_id     => $this->get_blank_report_module_id(),
                        column_resources_category_id   => $category_id,
                        column_resources_creator       => $creator,
                        column_resources_connection_id => $connection_id,
                        column_resources_url           => $report_url,
                        column_resources_access_level  => $access_level,
                        column_resources_created_at    => date('Y-m-d H:i:s')

                    );
                } else {
                    $resource_details = array(
                        column_resources_name         => $name,
                        column_resources_module_id    => $this->get_blank_report_module_id(),
                        column_resources_category_id  => $category_id,
                        column_resources_creator      => $creator,
                        column_resources_url          => $report_url,
                        column_resources_access_level => $access_level,
                        column_resources_created_at   => date('Y-m-d H:i:s')

                    );
                }

                $writer = new Writer(tables_prefix . table_resources, $resource_details, $this->dashboard_connection);
                return $writer->insert();
            } else {
                self::log("Error creating report", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", log_error, "report_builder_common_common", "", json_encode($resource_details));
                throw new Exception('Error creating report.', 10000);
                return false;
            }

        } else {
            self::log("Error creating report, a report with same name already existed", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", log_error, "report_builder_common_common", "", "report_name: " . $name);
            throw new Exception('Error creating report, a report with same name already existed', 10007);
            return false;
        }

    }

    /*
     * @param $blank_report_id report id
     * @param $group_ids array of the group IDs to get Access to the report
     * return int number of added records
     */

    public function save_private_report_permissions($blank_report_id, $group_ids, $rollback = false)
    {

// $group_ids = json_decode($group_ids)->access_groups;

        if ($this->is_entity_exist_by_value(table_groups, column_group_id, $group_ids)) {
            $added_records = array();
            if (empty($group_ids)) {
                return true;
            }

            if ($_SESSION[Session_security_key][srm_access_role] == "admin") {
                foreach ($group_ids as $group_id) {
                    $resource_permission_details = array(
                        column_resources_permissions_resource_id => $blank_report_id,
                        column_resources_permissions_group_id    => $group_id,
                        column_resources_permissions_can_view    => 1
                    );
                    $writer          = new Writer(tables_prefix . table_resources_permissions, $resource_permission_details, $this->dashboard_connection);
                    $added_records[] = $writer->insert();
                }

            } else {
                $resource_permission_details = array(
                    column_resources_permissions_resource_id => $blank_report_id,
                    column_resources_permissions_group_id    => $_SESSION[Session_security_key][srm_access_group],
                    column_resources_permissions_can_view    => 1
                );
                $writer          = new Writer(tables_prefix . table_resources_permissions, $resource_permission_details, $this->dashboard_connection);
                $added_records[] = $writer->insert();
            }

            return count($added_records);
        } else {
            if ($rollback) {
                $this->safely_delete_report($blank_report_id);
            }

            self::log("Report or Groups dosn't exist", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", log_error, "report_builder_common_common", "", json_encode($group_ids));
            throw new Exception("Report or Groups dosn't exist", 10004);
            return false;
        }

    }

    /*
     * @param $report_name report name
     * return bool
     */

    public function is_report_existed_by_name($report_name)
    {
        $edited_name = str_replace(" ", "", trim($report_name));
        $report_url  = report_base_path . "$edited_name/$edited_name.php";
        return $this->is_report_existed_by_url($report_url);
    }

    /*
     * @param $url report URL
     * return bool
     */

    public function is_report_existed_by_url($url)
    {
        $reader = new Reader(tables_prefix . table_resources, $this->dashboard_connection);
        $record = $reader->filter_by_column(column_resources_url, $url, true, column_resources_id);

        if (empty($record) || $record == false) {
            self::log("Report  dosn't exist", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", log_error, "report_builder_common_common", "", json_encode(array("url" => $url)));
            return false;
        } else {
            return $record;
        }

    }

    /*
     * @param $report_id report id
     * return bool
     */

    public function is_report_existed_by_id($report_id)
    {
        $reader = new Reader(tables_prefix . table_resources, $this->dashboard_connection);
        $record = $reader->filter_by_column(column_resources_id, $report_id, true, column_resources_id);

        if (empty($record) || $record == false) {
            self::log("Report dosn't exist", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", log_error, "report_builder_common_common", "", json_encode(array("report_id" => $report_id)));
            return false;
        } else {
            return $record;
        }

    }

    /*
     * @param $blank_report_id report id
     * @param $configuration_session_object Json object of A report configurations
     * return bool
     */

    public function save_resource_configurations($blank_report_id, $configuration_session_object, $rollback = false)
    {
        $resource_config_details = array(
            column_configuration_resource_id => $blank_report_id,
            column_configuration_json        => $configuration_session_object
        );
        $writer = new Writer(tables_prefix . table_resource_configurations, $resource_config_details, $this->dashboard_connection);
        $id     = $writer->insert();

        if ($id) {
            return $id;
        } else {

            if ($rollback) {
                $this->safely_delete_report($blank_report_id);
            }

            self::log("can't save report configurations", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", log_error, "report_builder_common_common", "", $configuration_session_object);
            throw new Exception("Can't save report configurations", 10006);
            return false;
        }

    }

    /*
     * ===============================================================================
     *              Editing an existing report
     * ===============================================================================
     */

    public function edit_blank_report($report_id, $name, $category_id, $connection_name, $creator, $access_level = private_report)
    {
        $edited_name = str_replace(" ", "", trim($name));
        $report_url  = report_base_path . "$edited_name/$edited_name.php";

        if ($connection_name != default_connection_name) {
            $connection_id = $this->get_connection_id(trim($connection_name));
        }

        if (
            is_int($report_id) && $this->is_entity_exist_by_value(table_categories, column_category_id, $category_id) &&
            $this->is_entity_exist_by_value(table_users, column_users_id, $creator) &&
            ($connection_id || $connection_name == default_connection_name)
        ) {

            $resource_details = array(
                column_resources_name         => $name,
                column_resources_module_id    => $this->get_blank_report_module_id(),
                column_resources_category_id  => $category_id,
                // column_resources_creator => $creator,

                column_resources_url          => $report_url,
                column_resources_access_level => $access_level
            );

            if ($connection_name != default_connection_name) {
                $resource_details = array_merge($resource_details, [column_resources_connection_id => $connection_id]);
            }

            $writer = new Writer(tables_prefix . table_resources, $resource_details, $this->dashboard_connection);
            return $writer->update($report_id, column_resources_id);
        } else {

            self::log("Error editing report.", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", log_error, "report_builder_common_common", "", json_encode($resource_details));
            throw new Exception('Error editing report.', 10001);
            return false;
        }

    }

    public function change_private_report_permissions($report_id, $group_ids)
    {

//make sure report exists and groups exists in parent table.

//make sure no prior permissions exists.
        // delete existing permissions

        $writer = new Writer(tables_prefix . table_resources_permissions, array(), $this->dashboard_connection);
        $writer->delete_by_id($report_id, column_resources_permissions_resource_id);

        if (empty($group_ids)) {
            return true;
        } else {
            return $this->save_private_report_permissions($report_id, $group_ids);
        }

    }

    public function edit_resource_configurations($blank_report_id, $new_configuration_session_object)
    {
        $resource_config_details = array(
            column_configuration_resource_id => $blank_report_id,
            column_configuration_json        => $new_configuration_session_object
        );
        $writer = new Writer(tables_prefix . table_resource_configurations, $resource_config_details, $this->dashboard_connection);
        return $writer->update($blank_report_id, column_configuration_resource_id);
    }

    public function load_report_configurations($report_id)
    {
        $reader = new Reader(tables_prefix . table_resource_configurations, $this->dashboard_connection);
        $record = $reader->filter_by_column(column_configuration_resource_id, $report_id, true, column_configuration_json);

        if (empty($record) || $record == false) {
            srm_dashboard::log("Can't load report configuration", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", "error", "report_builder_common", "", json_encode(array("report_id" => $report_id)));
            return false;
        } else {

            $_SESSION[Session_report_Settings_key] = json_decode($record[0][column_configuration_json], true);

            if ($_SESSION[Session_report_Settings_key]["connection_name"] != default_connection_name) {
                $parameters = $this->get_connection_details(trim($_SESSION[Session_report_Settings_key]["connection_name"]));
            } else {
                $parameters = $this->get_default_connection_details();
            }

            $DB_HOST      = isset($parameters["server"]) ? $parameters["server"] : "";
            $DB_USER      = isset($parameters["user"]) ? $parameters["user"] : "";
            $DB_PASSWORD  = isset($parameters["password"]) ? $parameters["password"] : "";
            $DB_NAME      = isset($parameters["db"]) ? $parameters["db"] : "";
            $DB_CHARSET   = isset($parameters["charset"]) ? $parameters["charset"] : "";
            $DB_COLLATION = isset($parameters["collation"]) ? $parameters["collation"] : "";
            $DB_PORT      = isset($parameters["port"]) ? $parameters["port"] : "";
            $dbHandler    = new DatabaseHandler($DB_HOST, $DB_USER, $DB_PASSWORD, $DB_NAME);

            if ($dbHandler) {

                if (Session_Save_Parameters == 1) {
                    $_SESSION[Session_report_Settings_key]["host"]      = $DB_HOST;
                    $_SESSION[Session_report_Settings_key]["user"]      = $DB_USER;
                    $_SESSION[Session_report_Settings_key]["pass"]      = $DB_PASSWORD;
                    $_SESSION[Session_report_Settings_key]["collation"] = $DB_COLLATION;
                    $_SESSION[Session_report_Settings_key]["charset"]   = $DB_CHARSET;
                    $_SESSION[Session_report_Settings_key]["port"]      = $DB_PORT;
                }

                $_SESSION[Session_wizard_key]["validate_key"] = md5("srm_f92024_report_settings_valid_1010");
                $_SESSION[Session_wizard_key]["page_key"]     = 'step_2';
                $_SESSION[Session_wizard_key]["active_pages"] = array(
                    'step_5_1',
                    'step_6'
                );
                $_SESSION[Session_wizard_key]["loaded_config_id"] = $report_id;
            } else {
                srm_dashboard::log("Can't connect to DB to load report configurations", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", "error", "report_builder_common", "", "");
                return false;
            }

            return true;
        }

    }

    public function unload_report_configurations()
    {
        unset($_SESSION[Session_report_Settings_key]);
    }

/*
 * ===============================================================================
 *              Deleting a report and all its permissions
 * ===============================================================================
 */

    /*
     * @param $report_id report id
     *
     */

    public function delete_report_with_permissions($report_id)
    {

        if ($this->is_entity_exist_by_value(table_resources, column_resources_id, $report_id)) {
            $writer = new Writer(tables_prefix . table_resources_permissions, array(), $this->dashboard_connection);
            $writer->delete_by_id($report_id, column_resources_permissions_resource_id);
            $writer = new Writer(tables_prefix . table_resources, array(), $this->dashboard_connection);
            $writer->delete_by_id($report_id, column_resources_id);
        }

    }

    public function safely_delete_report($report_id)
    {

        $writer = new Writer(tables_prefix . table_resources_permissions, array(), $this->dashboard_connection);
        $writer->delete_by_id($report_id, column_resources_permissions_resource_id);
        $writer = new Writer(tables_prefix . table_resource_configurations, array(), $this->dashboard_connection);
        $writer->delete_by_id($report_id, column_configuration_resource_id);
        $writer = new Writer(tables_prefix . table_resources, array(), $this->dashboard_connection);
        $writer->delete_by_id($report_id, column_resources_id);
    }

/*
 * ===============================================================================
 *              Infrastructure internal methods
 * ===============================================================================
 */

    /*
     *
     * return id of blank report in Modules table
     */

    private function get_blank_report_module_id($report = 'Blank Reports')
    {
        $reader = new Reader(tables_prefix . table_modules, $this->dashboard_connection);
        $record = $reader->filter_by_column(column_module_name, $report, true, column_module_id);
        return $record[0][column_module_id];
    }

    private function get_connection_id($searched_connection_name)
    {
        $reader = new Reader(tables_prefix . table_connection_strings, $this->dashboard_connection);
        $record = $reader->filter_by_column(column_connection_name, $searched_connection_name, true, column_connection_id);

        if (isset($record[0][column_connection_id])) {
            return $record[0][column_connection_id];
        } else {
            srm_dashboard::log("Connection name dosn't exist", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", "error", "report_builder_common", "", json_encode(array("searched_connection_name" => $searched_connection_name)));
            return false;
        }

    }

    private function is_entity_exist_by_value($table, $column, $values)
    {
        $reader = new Reader(tables_prefix . $table, $this->dashboard_connection);

        if (!is_array($values)) {
            return $reader->is_entity_exist_by_value($column, $values);
        } else {

            foreach ($values as $value) {

                if (!$reader->is_entity_exist_by_value($column, $value)) {
                    srm_dashboard::log("entity in $table dosn't exist", __FILE__ . "  lINE NO:" . __LINE__, __METHOD__, "", "error", "report_builder_common", "", json_encode(array("table" => $table, "column" => $column, "searched_value" => $value)));
                    return false;
                }

            }

            return true;
        }

    }

    public static function log($message, $file = "", $method = "", $trace = "", $severity = log_default_severity, $module = "report_builder_common", $query = "", $config = "", $levels = log_file_default_levels)
    {

        $edited_trace = (log_stack_trace === 1) ? $trace : "";

        $log_details = array(
            column_created_at      => date('Y-m-d H:i:s'),
            column_log_message     => $message,
            column_log_file        => $file,
            column_log_method      => $method,
            column_log_module      => $module,
            column_log_severity    => $severity,
            column_log_stack_trace => $edited_trace,
            column_log_query       => $query,
            column_log_config      => $config,
            column_log_php         => phpversion(),
            column_log_os          => PHP_OS
        );

//if (in_array("db",log_drivers)) {

//  writer::log($log_details);

//  }
        if (in_array("file", log_drivers)) {
            // Convert JSON data from an array to a string
            $jsonString = json_encode($log_details, JSON_PRETTY_PRINT);
            $path       = str_repeat("../", $levels);
            $path       = (substr(log_file_path, -1) == "/") ? $path . log_file_path : $path . log_file_path . "/";

            if (is_dir($path)) {
                $path .= "builder.log";
            } elseif (is_dir(substr($path, 3))) {
                $path = substr($path, 3) . "builder.log";
            } elseif (is_dir("../" . $path)) {
                $path = "../" . $path . "builder.log";
            } else {
                return false;
            }

            $fp = fopen($path, 'a+');
            fwrite($fp, $jsonString);
            fclose($fp);
        }

    }

}
