<?php

class database {

		/**
	 * Amount of queries made
	 *
	 * @since 1.2.0
	 * @var int
	 */
	public $num_queries = 0;

	/**
	 * Count of rows returned by previous query
	 *
	 * @since 0.71
	 * @var int
	 */
	public $num_rows = 0;

	/**
	 * Count of affected rows by previous query
	 *
	 * @since 0.71
	 * @var int
	 */
	var $rows_affected = 0;

	/**
	 * The ID generated for an AUTO_INCREMENT column by the previous query (usually INSERT).
	 *
	 * @since 0.71
	 * @var int
	 */
	public $insert_id = 0;

	/**
	 * Last query made
	 *
	 * @since 0.71
	 * @var string
	 */
	var $last_query;

	/**
	 * Results of the last query made
	 *
	 * @since 0.71
	 * @var array|null
	 */
	var $last_result;

	/**
	 * MySQL result, which is either a resource or boolean.
	 *
	 * @since 0.71
	 * @var mixed
	 */
	protected $result;

	/**
	 * Cached column info, for sanity checking data before inserting
	 *
	 * @since 4.2.0
	 * @var array
	 */
	protected $col_meta = array();

	/**
	 * Calculated character sets on tables
	 *
	 * @since 4.2.0
	 * @var array
	 */
	protected $table_charset = array();

	/**
	 * Whether text fields in the current query need to be sanity checked.
	 *
	 * @since 4.2.0
	 * @var bool
	 */
	protected $check_current_query = true;

	/**
	 * Saved info on the table column
	 *
	 * @since 0.71
	 * @var array
	 */
	protected $col_info;

	/**
	 * Log of queries that were executed, for debugging purposes.
	 *
	 * @since 1.5.0
	 * @since 2.5.0 The third element in each query log was added to record the calling functions.
	 * @since 5.1.0 The fourth element in each query log was added to record the start time.
	 * @since 5.3.0 The fifth element in each query log was added to record custom data.
	 *
	 * @var array[] {
	 *     Array of queries that were executed.
	 *
	 *     @type array ...$0 {
	 *         Data for each query.
	 *
	 *         @type string $0 The query's SQL.
	 *         @type float  $1 Total time spent on the query, in seconds.
	 *         @type string $2 Comma separated list of the calling functions.
	 *         @type float  $3 Unix timestamp of the time at the start of the query.
	 *         @type array  $4 Custom query data.
	 *     }
	 * }
	 */
	var $queries;

	/**
	 * The number of times to retry reconnecting before dying.
	 *
	 * @since 3.9.0
	 * @see wpdb::check_connection()
	 * @var int
	 */
	protected $reconnect_retries = 5;

	/**
	 * WordPress table prefix
	 *
	 * You can set this to have multiple WordPress installations
	 * in a single database. The second reason is for possible
	 * security precautions.
	 *
	 * @since 2.5.0
	 * @var string
	 */
	public $prefix = '';

	/**
	 * WordPress base table prefix.
	 *
	 * @since 3.0.0
	 * @var string
	 */
	public $base_prefix;

	/**
	 * Whether the database queries are ready to start executing.
	 *
	 * @since 2.3.2
	 * @var bool
	 */
	var $ready = false;

	/**
	 * A textual description of the last query/get_row/get_var call
	 *
	 * @since 3.0.0
	 * @var string
	 */
	public $func_call;

	/**
	 * Flag to ensure we don't run into recursion problems when checking the collation.
	 *
	 * @since 4.2.0
	 * @see wpdb::check_safe_collation()
	 * @var bool
	 */
	private $checking_collation = false;

	/**
	 * Whether MySQL is used as the database engine.
	 *
	 * Set in WPDB::db_connect() to true, by default. This is used when checking
	 * against the required MySQL version for WordPress. Normally, a replacement
	 * database drop-in (db.php) will skip these checks, but setting this to true
	 * will force the checks to occur.
	 *
	 * @since 3.3.0
	 * @var bool
	 */
	public $is_mysql = null;

	/**
	 * A list of incompatible SQL modes.
	 *
	 * @since 3.9.0
	 * @var array
	 */
	protected $incompatible_modes = array(
		'NO_ZERO_DATE',
		'ONLY_FULL_GROUP_BY',
		'STRICT_TRANS_TABLES',
		'STRICT_ALL_TABLES',
		'TRADITIONAL',
	);

	/**
	 * Whether to use mysqli over mysql.
	 *
	 * @since 3.9.0
	 * @var bool
	 */
	public $use_mysqli = false;

	/**
	 * Whether we've managed to successfully connect at some point
	 *
	 * @since 3.9.0
	 * @var bool
	 */
	private $has_connected = false;

	public $connection;
	private $db_name;
	private $db_user;
	private $db_pass;
	private $db_host;

	public function __construct () {
		$this->db_name = DB_NAME;
		$this->db_user = $this->set_user();
		$this->db_pass = DB_PASS;
		$this->db_host = DB_HOST;

		// Use ext/mysqli if it exists unless WP_USE_EXT_MYSQL is defined as true
		if ( function_exists( 'mysqli_connect' ) ) {
			$this->use_mysqli = true;
		}

		$this->run();
	}

	public function run() {
		$updating = (isset($_GET['update']) && strtolower($_GET['update']) == 1 && $_GET['auth'] == AUTHENTICATE && isset($_GET['auth']) ) ? true : false;
		$session = Session::getInstance();
		if($updating && !$session->updated) {
			$this->create_db();
		}
		$this->create_connection();
		if($this->connection && $updating && !$session->updated) {
			$this->create_tables();
		}
		if($updating) {
			$session->updated = true;
		}
	} //run()

	private function set_user() {
		global $DB_USER;
		if(is_array($DB_USER)) {
			$users = $DB_USER;
			$length = _count($DB_USER) - 1;
			$key = rand(0,$length);
			return $users[$key];
		}
		return $DB_USER;
	}

	private function create_db() {
		$link = mysqli_connect($this->db_host, $this->db_user, $this->db_pass);

		if(! $link) :
			die ('Error in database connection');
			exit();
		endif;

		$sql = "CREATE DATABASE IF NOT EXISTS ".$this->db_name;
		if (mysqli_query($link, $sql)) {
		    // Database created successfully
		} else {
		    echo "Error creating database: " . mysqli_error($link);
		}
	} //create_db()

	private function create_connection() {
		$this->is_mysql = true;

		/*
		 * Deprecated in 3.9+ when using MySQLi. No equivalent
		 * $new_link parameter exists for mysqli_* functions.
		 */
		$new_link     = defined( 'MYSQL_NEW_LINK' ) ? MYSQL_NEW_LINK : true;
		$client_flags = defined( 'MYSQL_CLIENT_FLAGS' ) ? MYSQL_CLIENT_FLAGS : 0;

		if ( $this->use_mysqli ) {
			$this->connection = mysqli_init();

			$host    = $this->db_host;
			$port    = null;
			$socket  = null;
			$is_ipv6 = false;

			$host_data = $this->parse_db_host( $this->db_host );
			if ( $host_data ) {
				list( $host, $port, $socket, $is_ipv6 ) = $host_data;
			}

			/*
			 * If using the `mysqlnd` library, the IPv6 address needs to be
			 * enclosed in square brackets, whereas it doesn't while using the
			 * `libmysqlclient` library.
			 * @see https://bugs.php.net/bug.php?id=67563
			 */
			if ( $is_ipv6 && extension_loaded( 'mysqlnd' ) ) {
				$host = "[$host]";
			}

			if ( DEVMODE ) {
				mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
				mysqli_real_connect( $this->connection, $host, $this->db_user, $this->db_pass, null, $port, $socket, $client_flags );
			} else {
				// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
				@mysqli_real_connect( $this->connection, $host, $this->db_user, $this->db_pass, null, $port, $socket, $client_flags );
			}

			if ( $this->connection->connect_errno ) {
				$this->connection = null;

				/*
				 * It's possible ext/mysqli is misconfigured. Fall back to ext/mysql if:
				 *  - We haven't previously connected, and
				 *  - WP_USE_EXT_MYSQL isn't set to false, and
				 *  - ext/mysql is loaded.
				 */
				$attempt_fallback = true;

				if ( $this->has_connected ) {
					$attempt_fallback = false;
				} elseif ( ! function_exists( 'mysql_connect' ) ) {
					$attempt_fallback = false;
				}

				if ( $attempt_fallback ) {
					$this->use_mysqli = false;
					return $this->create_connection();
				}
			}
		} else {
			if ( DEVMODE ) {
				$this->connection = mysql_connect( $this->db_host, $this->db_user, $this->db_pass, $new_link, $client_flags );
			} else {
				// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
				$this->connection = @mysql_connect( $this->db_host, $this->db_user, $this->db_pass, $new_link, $client_flags );
			}
		}

		if ( $this->connection ) {

			$this->has_connected = true;

			$this->ready = true;
			$this->select_db( $this->db_name, $this->connection );

			return true;
		}

		return false;
	} //create_connection()



	/**
	 * Selects a database using the current database connection.
	 *
	 * The database name will be changed based on the current database
	 * connection. On failure, the execution will bail and display an DB error.
	 *
	 * @since 0.71
	 *
	 * @param string        $db  MySQL database name
	 * @param resource|null $dbh Optional link identifier.
	 */
	public function select_db( $db, $connection = null ) {
		if ( is_null( $connection ) ) {
			$connection = $this->connection;
		}
		$session = Session::getInstance();
		if(!$session->tested) {
			$testResult = $this->test_db($db, $connection);
			if(!$testResult) {
				$this->create_db();
				$this->create_connection();
				$this->create_tables();
				$app = new app;
				$app->run_update();
			}
		}

		if ( $this->use_mysqli ) {
			$success = mysqli_select_db( $connection, $db );
		} else {
			$success = mysql_select_db( $db, $connection );
		}
		if ( ! $success ) {
			$this->ready = false;
			var_dump( 'We were able to connect to the database server (which means your username and password is okay) but not able to select the '.$db.' database.' );
		}
		
	}


	public function test_db($db, $connection = null) {
		$sql = "SHOW DATABASES LIKE '$db'";
		$rows = mysqli_query($connection, $sql);
		$_SESSION['tested'] = true;
		return mysqli_num_rows($rows) > 0 ? true : false;
	}

	/**
	 * Parse the DB_HOST setting to interpret it for mysqli_real_connect.
	 *
	 * mysqli_real_connect doesn't support the host param including a port or
	 * socket like mysql_connect does. This duplicates how mysql_connect detects
	 * a port and/or socket file.
	 *
	 * @since 4.9.0
	 *
	 * @param string $host The DB_HOST setting to parse.
	 * @return array|bool Array containing the host, the port, the socket and whether
	 *                    it is an IPv6 address, in that order. If $host couldn't be parsed,
	 *                    returns false.
	 */
	public function parse_db_host( $host ) {
		$port    = null;
		$socket  = null;
		$is_ipv6 = false;

		// First peel off the socket parameter from the right, if it exists.
		$socket_pos = strpos( $host, ':/' );
		if ( $socket_pos !== false ) {
			$socket = substr( $host, $socket_pos + 1 );
			$host   = substr( $host, 0, $socket_pos );
		}

		// We need to check for an IPv6 address first.
		// An IPv6 address will always contain at least two colons.
		if ( substr_count( $host, ':' ) > 1 ) {
			$pattern = '#^(?:\[)?(?P<host>[0-9a-fA-F:]+)(?:\]:(?P<port>[\d]+))?#';
			$is_ipv6 = true;
		} else {
			// We seem to be dealing with an IPv4 address.
			$pattern = '#^(?P<host>[^:/]*)(?::(?P<port>[\d]+))?#';
		}

		$matches = array();
		$result  = preg_match( $pattern, $host, $matches );

		if ( 1 !== $result ) {
			// Couldn't parse the address, bail.
			return false;
		}

		$host = '';
		foreach ( array( 'host', 'port' ) as $component ) {
			if ( ! empty( $matches[ $component ] ) ) {
				$$component = $matches[ $component ];
			}
		}

		return array( $host, $port, $socket, $is_ipv6 );
	}

	/**
	 * Retrieves the MySQL server version.
	 *
	 * @since 2.7.0
	 *
	 * @return null|string Null on failure, version number on success.
	 */
	public function db_version() {
		if ( $this->use_mysqli ) {
			$server_info = mysqli_get_server_info( $this->connection );
		} else {
			$server_info = mysql_get_server_info( $this->connection );
		}
		return preg_replace( '/[^0-9.].*/', '', $server_info );
	}

	/**
	 * Checks that the connection to the database is still up. If not, try to reconnect.
	 *
	 * If this function is unable to reconnect, it will forcibly die, or if after the
	 * the {@see 'template_redirect'} hook has been fired, return false instead.
	 *
	 * If $allow_bail is false, the lack of database connection will need
	 * to be handled manually.
	 *
	 * @since 3.9.0
	 *
	 * @param bool $allow_bail Optional. Allows the function to bail. Default true.
	 * @return bool|void True if the connection is up.
	 */
	public function check_connection() {
		if ( $this->use_mysqli ) {
			if ( ! empty( $this->dbh ) && mysqli_ping( $this->dbh ) ) {
				return true;
			}
		} else {
			if ( ! empty( $this->dbh ) && mysql_ping( $this->dbh ) ) {
				return true;
			}
		}


		for ( $tries = 1; $tries <= $this->reconnect_retries; $tries++ ) {
			// On the last try, re-enable warnings. We want to see a single instance of the
			// "unable to connect" message on the bail() screen, if it appears.
			if ( $this->reconnect_retries === $tries && DEVMODE ) {
				error_reporting( $error_reporting );
			}

			if ( $this->create_connection() ) {

				return true;
			}

			sleep( 1 );
		}

		return false;
	}



	private function create_tables() {
		// stores all the settings of the system
		$sql = "CREATE TABLE IF NOT EXISTS options (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				option_name VARCHAR(100) NOT NULL,
				option_value TEXT NOT NULL
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create options table');
		}

		// stores all the actions of the system
		$sql = "CREATE TABLE IF NOT EXISTS actions (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				action_name VARCHAR(100) NOT NULL,
				action_cb TEXT NOT NULL,
				priority INT UNSIGNED
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create actions table');
		}

		// stores all the records of the system
		$sql = "CREATE TABLE IF NOT EXISTS records (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				record_name VARCHAR(100) NOT NULL,
				record_value LONGTEXT NOT NULL
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create records table');
		}

		// stores all the visitors of the system
		$sql = "CREATE TABLE IF NOT EXISTS visitors (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				visitor_name VARCHAR(100) NOT NULL,
				visitor_id VARCHAR(100) NOT NULL,
				visitor_ip VARCHAR(100) NOT NULL,
				visit_page TEXT NOT NULL,
				page_link VARCHAR(100) NOT NULL,
				request_time VARCHAR(100) NOT NULL,
				load_time VARCHAR(100) NOT NULL,
				user_agent TEXT NOT NULL,
				referer TEXT NOT NULL,
				status VARCHAR(10) NOT NULL,
				request_method VARCHAR(10) NOT NULL
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create visitors table');
		}

		// stores all the externals of the system
		$sql = "CREATE TABLE IF NOT EXISTS externals (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				visitor_name VARCHAR(100) NOT NULL,
				visitor_id VARCHAR(100) NOT NULL,
				visitor_ip VARCHAR(100) NOT NULL,
				visit_page TEXT NOT NULL,
				page_link VARCHAR(100) NOT NULL,
				request_time VARCHAR(100) NOT NULL,
				load_time VARCHAR(100) NOT NULL,
				user_agent TEXT NOT NULL,
				referer TEXT NOT NULL,
				status VARCHAR(10) NOT NULL,
				request_method VARCHAR(10) NOT NULL
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create visitors table');
		}

		// stores all the actions of the system
		$sql = "CREATE TABLE IF NOT EXISTS filters (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				filter_name VARCHAR(100) NOT NULL,
				filter_cb TEXT NOT NULL,
				priority INT UNSIGNED
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create filters table');
		}

		// stores all the result pins of the system
		$sql = "CREATE TABLE IF NOT EXISTS result_pins (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				pin TEXT NOT NULL,
				result BIGINT(20) DEFAULT -1 NOT NULL,
				batch TEXT NOT NULL,
				valid INT UNSIGNED
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create result pins table');
		}

		$sql = "CREATE TABLE IF NOT EXISTS notification (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				user_id BIGINT(20) NOT NULL,
				content TEXT NOT NULL,
				type VARCHAR(50) NOT NULL,
				action TEXT NOT NULL,
				max_send INT UNSIGNED,
				current_send INT UNSIGNED,
				last_sent VARCHAR(20) NOT NULL,
				send_interval VARCHAR(20) NOT NULL,
				status VARCHAR(20) NOT NULL
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create notification table');
		}

		// stores the login details and IDs of registered users
		$sql = "CREATE TABLE IF NOT EXISTS users (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				username VARCHAR(30) NOT NULL,
				email VARCHAR(50) NOT NULL,
				password TEXT NOT NULL,
				date_created TEXT NOT NULL
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create users table');
		}

		// stores user data
		$sql = "CREATE TABLE IF NOT EXISTS user_meta (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				user_id BIGINT(20) NOT NULL,
				meta_name TEXT NOT NULL,
				meta_value TEXT NOT NULL
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create user meta table');
		}

		// stores post
		$sql = "CREATE TABLE IF NOT EXISTS post (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				title TEXT NOT NULL,
				permalink TEXT NOT NULL
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create post table');
		}

		// stores post data
		$sql = "CREATE TABLE IF NOT EXISTS post_meta (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				post_id BIGINT(20) NOT NULL,
				meta_name TEXT NOT NULL,
				meta_value LONGTEXT NOT NULL
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create post meta table');
		}

		// stores post data
		$sql = "CREATE TABLE IF NOT EXISTS contacts (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				type TEXT NOT NULL,
				user_id BIGINT(20) NOT NULL,
				name TEXT NOT NULL,
				contact VARCHAR(30) NOT NULL,
				status VARCHAR(20) NOT NULL
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create contacts table');
		}

		// stores post data
		$sql = "CREATE TABLE IF NOT EXISTS cache (
				id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				selector TEXT NOT NULL,
				cache_group TEXT NOT NULL,
				cache_value LONGTEXT NOT NULL
				)";
		if (! mysqli_query($this->connection, $sql)) {
			die ('Unable to create cache table');
		}
	}//create_tables()
}