<?php

/**
 * Base Custom Database Class.
 *
 * @package     Database
 * @subpackage  Base
 * @copyright   Copyright (c) 2021
 * @license     https://opensource.org/licenses/MIT MIT
 * @since       1.0.0
 */
namespace WP_Ultimo\Dependencies\BerlinDB\Database;

// Exit if accessed directly
\defined('ABSPATH') || exit;
/**
 * The base class that all other database base classes extend.
 *
 * This class attempts to provide some universal immutability to all other
 * classes that extend it, starting with a magic getter, but likely expanding
 * into a magic call handler and others.
 *
 * @since 1.0.0
 */
class Base
{
    /**
     * The name of the PHP global that contains the primary database interface.
     *
     * For example, WordPress traditionally uses 'wpdb', but other applications
     * may use something else, or you may be doing something really cool that
     * requires a custom interface.
     *
     * A future version of this utility may abstract this out entirely, so
     * custom calls to the get_db() should be avoided if at all possible.
     *
     * @since 1.0.0
     * @var   string
     */
    protected $db_global = 'wpdb';
    /** Global Properties *****************************************************/
    /**
     * Global prefix used for tables/hooks/cache-groups/etc...
     *
     * @since 1.0.0
     * @var   string
     */
    protected $prefix = '';
    /**
     * The last database error, if any.
     *
     * @since 1.0.0
     * @var   mixed
     */
    protected $last_error = \false;
    /** Public ****************************************************************/
    /**
     * Magic isset'ter for immutability.
     *
     * @since 1.0.0
     *
     * @param string $key
     * @return mixed
     */
    public function __isset($key = '')
    {
        // No more uppercase ID properties ever
        if ('ID' === $key) {
            $key = 'id';
        }
        // Class method to try and call
        $method = "get_{$key}";
        // Return property if exists
        if (\method_exists($this, $method)) {
            return \true;
            // Return get method results if exists
        } elseif (\property_exists($this, $key)) {
            return \true;
        }
        // Return false if not exists
        return \false;
    }
    /**
     * Magic getter for immutability.
     *
     * @since 1.0.0
     *
     * @param string $key
     * @return mixed
     */
    public function __get($key = '')
    {
        // No more uppercase ID properties ever
        if ('ID' === $key) {
            $key = 'id';
        }
        // Class method to try and call
        $method = "get_{$key}";
        // Return property if exists
        if (\method_exists($this, $method)) {
            return \call_user_func(array($this, $method));
            // Return get method results if exists
        } elseif (\property_exists($this, $key)) {
            return $this->{$key};
        }
        // Return null if not exists
        return null;
    }
    /**
     * Converts the given object to an array.
     *
     * @since 1.0.0
     *
     * @return array Array version of the given object.
     */
    public function to_array()
    {
        return \get_object_vars($this);
    }
    /** Protected *************************************************************/
    /**
     * Maybe append the prefix to string.
     *
     * @since 1.0.0
     *
     * @param string $string
     * @param string $sep
     * @return string
     */
    protected function apply_prefix($string = '', $sep = '_')
    {
        return !empty($this->prefix) ? "{$this->prefix}{$sep}{$string}" : $string;
    }
    /**
     * Return the first letters of a string of words with a separator.
     *
     * Used primarily to guess at table aliases when none is manually set.
     *
     * Applies the following formatting to a string:
     * - Trim whitespace
     * - No accents
     * - No trailing underscores
     *
     * @since 1.0.0
     *
     * @param string $string
     * @param string $sep
     * @return string
     */
    protected function first_letters($string = '', $sep = '_')
    {
        // Set empty default return value
        $retval = '';
        // Bail if empty or not a string
        if (empty($string) || !\is_string($string)) {
            return $retval;
        }
        // Trim spaces off the ends
        $unspace = \trim($string);
        // Only non-accented table names (avoid truncation)
        $accents = remove_accents($unspace);
        // Only lowercase letters are allowed
        $lower = \strtolower($accents);
        // Explode into parts
        $parts = \explode($sep, $lower);
        // Loop through parts and concatenate the first letters together
        foreach ($parts as $part) {
            $retval .= \substr($part, 0, 1);
        }
        // Return the result
        return $retval;
    }
    /**
     * Sanitize a table name string.
     *
     * Used to make sure that a table name value meets MySQL expectations.
     *
     * Applies the following formatting to a string:
     * - Trim whitespace
     * - No accents
     * - No special characters
     * - No hyphens
     * - No double underscores
     * - No trailing underscores
     *
     * @since 1.0.0
     *
     * @param string $name The name of the database table
     *
     * @return string Sanitized database table name
     */
    protected function sanitize_table_name($name = '')
    {
        // Bail if empty or not a string
        if (empty($name) || !\is_string($name)) {
            return \false;
        }
        // Trim spaces off the ends
        $unspace = \trim($name);
        // Only non-accented table names (avoid truncation)
        $accents = remove_accents($unspace);
        // Only lowercase characters, hyphens, and dashes (avoid index corruption)
        $lower = sanitize_key($accents);
        // Replace hyphens with single underscores
        $under = \str_replace('-', '_', $lower);
        // Single underscores only
        $single = \str_replace('__', '_', $under);
        // Remove trailing underscores
        $clean = \trim($single, '_');
        // Bail if table name was garbaged
        if (empty($clean)) {
            return \false;
        }
        // Return the cleaned table name
        return $clean;
    }
    /**
     * Set class variables from arguments.
     *
     * @since 1.0.0
     * @param array $args
     */
    protected function set_vars($args = array())
    {
        // Bail if empty or not an array
        if (empty($args)) {
            return;
        }
        // Cast to an array
        if (!\is_array($args)) {
            $args = (array) $args;
        }
        // Set all properties
        foreach ($args as $key => $value) {
            $this->{$key} = $value;
        }
    }
    /**
     * Return the global database interface.
     *
     * See: https://core.trac.wordpress.org/ticket/31556
     *
     * @since 1.0.0
     *
     * @return \wpdb Database interface, or False if not set
     */
    protected function get_db()
    {
        // Default database return value (might change)
        $retval = \false;
        // Look for a commonly used global database interface
        if (isset($GLOBALS[$this->db_global])) {
            $retval = $GLOBALS[$this->db_global];
        }
        /*
         * Developer note:
         *
         * It should be impossible for a database table to be interacted with
         * before the primary database interface is setup.
         *
         * However, because applications are complicated, it is unsafe to assume
         * anything, so this silently returns false instead of halting everything.
         *
         * If you are here because this method is returning false for you, that
         * means the database table is being invoked too early in the lifecycle
         * of the application.
         *
         * In WordPress, that means before the $wpdb global is created; in other
         * environments, you will need to adjust accordingly.
         */
        // Return the database interface
        return $retval;
    }
    /**
     * Check if an operation succeeded.
     *
     * @since 1.0.0
     *
     * @param mixed $result
     * @return bool
     */
    protected function is_success($result = \false)
    {
        // Bail if no row exists
        if (empty($result)) {
            $retval = \false;
            // Bail if an error occurred
        } elseif (is_wp_error($result)) {
            $this->last_error = $result;
            $retval = \false;
            // No errors
        } else {
            $retval = \true;
        }
        // Return the result
        return (bool) $retval;
    }
}
