<?php

//function opensqlitedb ($filename="DB/all.sqlite3"){return new PDO("sqlite:".__DIR__."/".$filename);}

require_once('lib/logins.php');


$minutesbeforeclosetime = 15;

$lognow = true;
$cachenow = true;
$DB = DB();

settimezonetomanila();

$GLOBALS['CurrentUserUID'] = CurrentUserUID();


function SaveUploadedFile($fileInputIDName, $file_nameAndLocation = 'files/', $overwrite = false)
{
    if (!$fileInputIDName) {
        return false;
    }

    if (!$file_nameAndLocation) {
        $file_nameAndLocation = 'files/';
    }



    if ($_SERVER["REQUEST_METHOD"] == "POST" and isset($_FILES[$fileInputIDName])) {


        if (isset($_FILES[$fileInputIDName]) && $_FILES[$fileInputIDName]["error"] == UPLOAD_ERR_OK) {

            $file_name = $_FILES[$fileInputIDName]["name"];
            $file_tmp_name = $_FILES[$fileInputIDName]["tmp_name"];
            $file_size = $_FILES[$fileInputIDName]["size"];
            $file_type = $_FILES[$fileInputIDName]["type"];

            $target_dir = "uploads/";
            $target_file = $target_dir . basename($file_name);

            if (move_uploaded_file($file_tmp_name, $target_file)) {
                echo "The file " . htmlspecialchars($file_name) . " has been uploaded.";
            } else {
                echo "Sorry, there was an error uploading your file.";
            }

        } else {
            echo "Error: No file uploaded or an error occurred during upload.";
        }

    } else {
        // Redirect or handle invalid access
        return false;
    }

}


function getFileDataNowfromFileContent($uidorhashkey)
{
    if (!$uidorhashkey) {
        return false;
    }
    $details = getFileContentDetails($uidorhashkey);

    if (!$details) {
        return false;
    }
    if (!$details['content']) {
        //$filecheck = file

    }
}

function getFileDataNowfromFileList()
{

}


function getsqllitedata($query, $params = '', $sdb = null)
{
    if (!$sdb) {
        global $DB;
        $sdb = $DB;
    }

    try {
        if ($sdb instanceof PDO) {
            $statement = $sdb->prepare($query);

            if ($params && is_array($params)) {
                foreach ($params as $key => $values) {
                    $statement->bindParam(':' . $key, $values);
                }
            }

            $statement->execute();

            $result = [];
            while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
                $result[] = $row;
            }

            return $result;
        } else {
            echo "Invalid or missing database connection (PDO object).";
        }
    } catch (PDOException $e) {
        echo "Error: " . $e->getMessage();
    }
}

function sanitizeData($data)
{

    $data = preg_replace('/[^a-zA-Z0-9\s]/', '', $data);


    if (is_string($data)) {

        $data = htmlspecialchars($data, ENT_QUOTES);
    } elseif (is_int($data)) {
        // Layer 3: Validate integer range
        if ($data < 0 || $data > 100) {
            throw new Exception('Invalid integer range');
        }
    } else {
        throw new Exception('Invalid input type');
    }


    $data = strip_tags($data);


    $data = preg_replace('/(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|TRUNCATE)/i', '', $data);

    return $data;
}

function opennewdb($dbname = "", $host = 'localhost', $user = 'root', $passwd = '')
{
    //if (!$dbname){return FALSE;}
    // if ($host==''){$host='localhost';}
    // if ($user==''){$user='root';}
    $dsn = "mysql:host=$host;dbname=$dbname";
    return new PDO($dsn, $user, $passwd);
}

function GetCurrenSelectedDatabaseName($DB)
{
    if (!$DB) {
        return false;
    }
    return selectfromsimple($DB, 'SELECT DATABASE();')[0]['DATABASE()'] ?? false;
}
function CheckifTableExistinCurrentDB($DBPDO, $tablename)
{
    if (!$DBPDO || !$tablename) {
        return false;
    }
    $CurrentDBName = GetCurrenSelectedDatabaseName($DBPDO);
    if (!$CurrentDBName) {
        return false;
    }
    $sqlquery = "SELECT * FROM information_schema.tables  
 WHERE table_schema = '" . $CurrentDBName . "'  
    AND table_name = '" . $tablename . "' 
  LIMIT 1;";


    $res = selectfromsimple($DBPDO, $sqlquery, $bindings = '$currentfieldbindablevalues', $noindex = 0);
    if (!$res) {
        return false;
    } else {
        return true;
    }
}

function selectfromsimple($db, $sqlquery, $bindings = '$currentfieldbindablevalues', $noindex = 0)
{
    //bindings = ['username'=>'john']
    if (!$db) {
        return FALSE;
    }

    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // if (file_exists('errsql.html')){
    // unlink("errsql.html");}

    // $dataerr =  printarrayorobject($sqlquery).printarrayorobject($bindings);

    // file_put_contents('errsql.html',$dataerr,FILE_APPEND);

    try {
        $arraybindings = [];

        $sth = $db->prepare($sqlquery);
        if ($bindings and is_array($bindings) and !empty($bindings)) {
            foreach ($bindings as $key => $value) {

                $currentcolumn = ':' . $key;
                if (is_array($value)) {
                    $value = json_encode($value);
                }
                if ($value === NULL) {
                    $value = '';
                }


                // $sth->bindValue($currentcolumn, $value);

                $arraybindings[$currentcolumn] = $value;
            }
        }
        // echo $sqlquery.printarrayorobject($arraybindings);
        // var_dump($sqlquery);
        global $lognow;
        if ($lognow) {
            file_put_contents('sqllogs.html', p($sqlquery) . p($arraybindings), FILE_APPEND);
        }

        if (!$arraybindings or empty($arraybindings) or $arraybindings == '$currentfieldbindablevalues') {
            $sth->execute();
        } else {
            $sth->execute($arraybindings);
        }

        // $sth->execute();

        // file_put_contents('errsql.html',pr(),FILE_APPEND);

        $nquery = fopen("php://memory", "w");

        fwrite($nquery, $sqlquery);

        fseek($nquery, 0);

        if (stripos(fread($nquery, "12"), "INSERT INTO ") !== FALSE) {

            $id = $db->lastInsertId();

            $res = $id;

            // file_put_contents('errsql.html',pr($sqlquery).'INSERT ID: '.printarrayorobject($res),FILE_APPEND);

        } elseif (stripos(substr($sqlquery, 0, 11), "SELECT ") !== FALSE) {

            if ($noindex) {
                $resultarr = $sth->fetchAll(PDO::FETCH_NUM);
            } else {
                $resultarr = $sth->fetchAll(PDO::FETCH_ASSOC);
            }

            global $cachenow;
            if ($cachenow) {
                $hashvalue = ArraytoHash($resultarr);
                if (!file_exists('DBCache/' . $hashvalue)) {
                    file_put_contents('DBCache/' . $hashvalue, json_encode($resultarr));
                }
            }

            $res = $resultarr;
        } elseif (stripos(substr($sqlquery, 0, 11), "UPDATE ") !== FALSE) {
        } elseif (stripos(substr($sqlquery, 0, 11), "Delete ") !== FALSE) {
        } else {

            if ($noindex) {
                $resultarr = $sth->fetchAll(PDO::FETCH_NUM);
            } else {
                $resultarr = $sth->fetchAll(PDO::FETCH_ASSOC);
            }

            $res = $resultarr;
        }
    } catch (PDOException $e) {

        // $sth->debugDumpParams();
        $db = NULL;
        global $lognow;
        if ($lognow) {
            file_put_contents('errlogs', $e . p($sqlquery) . p($bindings));
            file_put_contents('errsql.html', 'Error: ' . $e . p($sqlquery) . p($bindings), FILE_APPEND);
        }

        /*$statement->debugDumpParams();*/


        return FALSE;
    }

    fclose($nquery);



    $db = NULL;
    if (!isset($res))
        $res = TRUE;
    return $res;
}

function insertintodb($dbvar, $table, $data)
{

    $keystring = implode(',', array_keys($data));
    $placeholdersString = ':' . implode(',:', array_keys($data));
    $sql = 'INSERT INTO ' . $table . ' (' . $keystring . ') VALUES (' . $placeholdersString . '); ';
    return selectfromsimple($dbvar, $sql, $data);
}

function deletefromdb($table, $wheredata, $DB = false)
{
    if (!$table)
        return FALSE;
    if (!$wheredata or !is_array($wheredata)) {
        return FALSE;
    }
    if (!$DB) {
        $DB = DB();
    }
    foreach ($wheredata as $key => $value) {
        $wherefields[] = ' ' . $key . ' = :' . $key . ' ';
    }
    $wherestring = implode(" and ", $wherefields);
    $sql = 'DELETE FROM ' . $table . ' WHERE ' . $wherestring . ';';
    return selectfromsimple($DB, $sql, $wheredata);
}

function updatedbsimple($db, $table, $data, $wherearray)
{

    if (!$db) {
        $db = DB();
    }
    if (!$data) {
        return FALSE;
    }
    if (!$table) {
        return FALSE;
    }
    $updatefields = [];
    $wherefields = [];

    foreach ($data as $key => $value) {

        $updatefields[] = ' ' . $key . ' = :' . $key . ' ';
    }

    $updatefields = implode(' , ', $updatefields);

    foreach ($wherearray as $key => $value) {

        $wherefields[] = ' ' . $key . ' = :' . $key . ' ';
    }

    $wherefields = implode(' AND ', $wherefields);
    // file_put_contents('updatewhere',$wherefields);

    $query = "UPDATE  " . $table . ' SET ' . $updatefields . ' WHERE ' . $wherefields . ';';

    $finalarray = array_merge($data, $wherearray);

    global $lognow;
    if ($lognow) {
        file_put_contents('updatesql', $query);
    }

    $resultd = selectfromsimple($db, $query, $finalarray);
    if ($resultd) {
        return TRUE;
    }
}

function listselectsql($dbvariable, $tablename, $data = [], $likefields = [], $fieldstoselectarray = '', $orderby = '', $noindex = 0, $whereappend = ' and ', $dateonlyarray = '')
{

    if (!$noindex) {
        $noindex = 0;
    }
    if (!$data) {
        $data = [];
    }
    if (!$likefields) {
        $likefields = [];
    }
    if (!$whereappend) {
        $whereappend = ' and ';
    }

    $wherearray = [];
    $where = '';

    if ($likefields === '') {
        $likefields = [];
    }

    foreach ($data as $key => $value) {
        if ($value or $value === 0 or $value === '') {

            if (in_array($key, $likefields)) {
                if (is_array($dateonlyarray) and in_array($key, $dateonlyarray)) {
                    $wherearray[] = 'DATE(' . $key . ')' . ' LIKE :' . $key;
                } else {
                    $wherearray[] = $key . ' LIKE :' . $key;
                }
            } else {
                $wherearray[] = $key . '=:' . $key;
            }
        } else {
            unset($data[$key]);
        }
    }

    if (!empty($wherearray)) {
        $where = ' where ' . implode($whereappend, $wherearray) . ' ';
    }

    if ($fieldstoselectarray and !empty($fieldstoselectarray) and is_array($fieldstoselectarray)) {
        $fieldstoselect = implode(" , ", $fieldstoselectarray);
    } else {
        $fieldstoselect = '*';
    }
    if ($orderby) {
        $orderby = ' order by ' . $orderby . ' ';
    }

    $query = 'select ' . $fieldstoselect . ' from ' . $tablename . ' ' . $where . ' ' . $orderby . ' ;';


    return selectfromsimple($dbvariable, $query, $data, $noindex);
}
/**
 * Selects multiple values from a database table using the OR.
 *
 * @param PDO $dbvariable The database connection object.
 * @param string $table The name of the database table.
 * @param array $valuearray The array of values to select.
 * @param string $Columnname The name of the column to select from.
 * @param array $fieldstoselect The fields to select from the table. Defaults to *.
 * @param int|bool $noindex Whether to return the results with or without indexes. Defaults to 0.
 *
 * @return array|false The results of the query, or false if the query fails.
 */
function selectfromDBMultipleValuesSameField($dbvariable, $table, $valuearray, $Columnname, $fieldstoselect = '', $noindex = 0)
{
    if (!$dbvariable or !$table or !$valuearray or !$Columnname) {
        return false;
    }
    if ($fieldstoselect) {
        $fieldstoselect = '  ' . implode(',', $fieldstoselect) . '  ';
    } else {
        $fieldstoselect = " * ";
    }
    $wherearraystring = '';
    $wherearray = [];
    foreach ($valuearray as $key => $value) {
        $wherearray[] = $Columnname . '=:' . $key;
    }
    $wherearraystring = implode(' OR ', $wherearray);
    $query = 'select ' . $fieldstoselect . ' from ' . $table . ' where ' . $wherearraystring . ';';
    return selectfromsimple($dbvariable, $query, $valuearray, $noindex);
}

/**
 * Selects multiple values from a database table using the IN.
 *
 * @param PDO $dbvariable The database connection object.
 * @param string $table The name of the database table.
 * @param array $valuearray The array of values to select.
 * @param string $Columnname The name of the column to select from.
 * @param array $fieldstoselect The fields to select from the table. Defaults to *.
 * @param int|bool $noindex Whether to return the results with or without indexes. Defaults to 0.
 *
 * @return array|false The results of the query, or false if the query fails.
 */
function selectfromDBMultipleValuesSameFieldUSINGIN($dbvariable, $table, $valuearray, $Columnname, $fieldstoselect = '', $noindex = 0)
{

    if (!$dbvariable or !$table or !$valuearray or !$Columnname) {
        return false;
    }
    if ($fieldstoselect) {
        $fieldstoselect = '  ' . implode(',', $fieldstoselect) . '  ';
    } else {
        $fieldstoselect = " * ";
    }

    $placeholders = implode(',', array_fill(0, count($valuearray), '?'));
    $query = 'select ' . $fieldstoselect . ' from ' . $table . ' where ' . $Columnname . ' IN (' . $placeholders . ')';

    $dbvariable->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $sth = $dbvariable->prepare($query);
    $sth->execute($valuearray);

    if (stripos(substr($query, 0, 11), "SELECT ") !== FALSE) {
        if ($noindex) {
            $resultarr = $sth->fetchAll(PDO::FETCH_NUM);
        } else {
            $resultarr = $sth->fetchAll(PDO::FETCH_ASSOC);
        }
        return empty($resultarr) ? false : $resultarr;
    } else {
        return false;
    }
}


function checkifexists($table, $wherearray, $fieldstoselectarray = '', $orderby = '')
{
    return listselectsql(DB(), $table, $wherearray, $likefields = [], $fieldstoselectarray, $orderby, $noindex = 0)[0] ?? false;
}


function serverdatetimesql()
{
    return date("Y-m-d H:i:s", time());
}
function servedatename()
{
    return date("F j, Y h:i:s A", time());
}
function TimeConverttoMDY($timestring)
{
    return date("F j, Y h:i:s A", strtotime($timestring));
}
function settimezonetomanila()
{
    date_default_timezone_set('Asia/Manila');
}

function serverdateonlyforsql()
{
    return date("Y-m-d", time());
}
function isTargetDatePastToday($targetDate)
{
    $today = strtotime(date('Y-m-d'));
    $targetTimestamp = strtotime($targetDate);
    return $targetTimestamp < $today;
}
function isDateTimePastToday($targetdatetime)
{
    $today = strtotime(date('Y-m-d H:i:s'));  // Get current date and time
    $targetTimestamp = strtotime($targetdatetime); // Convert target datetime to timestamp

    return $targetTimestamp < $today;  // Check if target timestamp is before today
}

function isValidDate($str, $format = 'Y-m-d')
{

    try {
        $date = DateTime::createFromFormat($format, $str);
        return $date && $date->format($format) === $str;
    } catch (Exception $e) {
        return false;
    }
}

function convertTo24Hours_strtotime($timeStr)
{
    // Detect AM/PM using strpos
    $isPM = strpos($timeStr, "PM") !== false;

    // Remove AM/PM using str_replace
    $timeStr = str_replace(["AM", "PM"], "", $timeStr);

    // Convert hour to 24-hour format
    $hour = (int) $timeStr;
    if ($isPM && $hour !== 12) {
        $hour += 12;
    } else if (!$isPM && $hour === 12) {
        $hour = 0;
    }

    // Convert to timestamp using strtotime
    $timestamp = strtotime("$hour:00"); // Assume minutes are 00

    return $timestamp;
}

function convertsqltimetoPM($sqlTimeString)
{
    $timestamp = strtotime($sqlTimeString);

    return $formattedTime = date("H:i", $timestamp);
}

function convertMilitaryTimetoPMwithoutOClock($time24)
{ // sample 14:00 to 2PM
    $time12 = date('gA', strtotime($time24));
    return $time12;
}

function convertAMPMtosqltime($sqlTimeString)
{
    return convertsqltimetoPM($sqlTimeString);
}
function convertAMPMtosqltimeError($timeStr)
{
    if (strpos(strtolower($timeStr), "am") === false and strpos(strtolower($timeStr), "pm") === false) {
        return $timeStr;
    }
    $timeStr = convertTo24Hours_strtotime($timeStr);
    return date("H:i:s", time());
}

function isScheduleAllowed($date, $time, $schedule)
{
    $dayOfWeek = strtoupper(date('D', strtotime($date)));
    $inputTime = strtotime($time);

    foreach ($schedule as $allowedSchedule) {
        $allowedDay = strtoupper($allowedSchedule[0]);
        $allowedTime = strtotime($allowedSchedule[1]);

        if ($dayOfWeek === $allowedDay && $inputTime === $allowedTime) {
            return true;
        }
    }

    return false;
}



function isDayOfWeekMatch($date, $dayOfWeek)
{
    if (!$date or !$dayOfWeek) {
        return false;
    }
    // Ensure the input dayOfWeek is in a standard format (e.g., Mon, Tue)
    $dayOfWeek = strtoupper(substr($dayOfWeek, 0, 3));

    // Define the days of the week
    $daysOfWeek = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];

    // Parse the input date
    $inputDate = new DateTime($date);

    // Check if the day of the week matches
    return $daysOfWeek[$inputDate->format('w')] === $dayOfWeek;
}




function datetosqldatetime($datestring)
{
    return date("Y-m-d H:i:s", strtotime($datestring));
}

function isTargetTimepastMinutes($targettime, $numberofmins = '15', $currenttime = '')
{
    date_default_timezone_set('Asia/Manila');

    $targettime = strtotime('-' . $numberofmins . 'mins', strtotime($targettime));

    if (!$currenttime) {
        $currenttime = time();
    } else {
        $currenttime = strtotime($currenttime);
    }
    $currenttime = strtotime(date('H:i:s', $currenttime));

    if ($currenttime > $targettime) {
        return true;
    } else {
        return false;
    }
}



function istimepastDrawtime($time)
{
    global $minutesbeforeclosetime;
    if (!$minutesbeforeclosetime) {
        $minutesbeforeclosetime = 15;
    }
    $past = isTargetTimepastMinutes($time, $minutesbeforeclosetime);
    return $past;
}

function isCurrentTimeMinutesOrEarlierBeforeTargetTime($targetDateTime, $minutes)
{
    $targetDateTime = new DateTime($targetDateTime);
    $currentTime = new DateTime();
    $fifteenMinutesBeforeTarget = clone $targetDateTime;
    $fifteenMinutesBeforeTarget->sub(new DateInterval("PT" . $minutes . "M"));
    return $currentTime <= $fifteenMinutesBeforeTarget;
}

function mergeAndValidateDateTime($dateString, $timeString)
{
    try {

        $dateTimeString = "$dateString $timeString";

        $dateTime = DateTime::createFromFormat("Y-m-d H:i", $dateTimeString);


        if ($dateTime instanceof DateTime) {
            return $dateTimeString;
        } else {
            return false;
        }
    } catch (Exception $e) {
        return false;
    }
}


function DrawTimeAllowed($date, $time)
{
    $drawtime = mergeAndValidateDateTime($date, $time);
    if (!$drawtime) {
        return false;
    }
    global $minutesbeforeclosetime;
    if (!$minutesbeforeclosetime) {
        $minutesbeforeclosetime = 15;
    }
    return isCurrentTimeMinutesOrEarlierBeforeTargetTime($drawtime, $minutesbeforeclosetime);
}

function generatenewhash($table = 'users', $fieldname = 'hashkey')
{
    $hash = bin2hex(random_bytes(18) . random_bytes(18));
    $detect = selectfromsimple(DB(), 'select ' . $fieldname . ' from ' . $table . ' where ' . $fieldname . ' = "' . $hash . '";');
    if ($detect == '' or $detect == []) {
        return $hash;
    } else {
        return generatenewhash();
    }
}

function generate_sku($department, $category, $brand, $subcategory, $model, $datatable, $pdo)
{
    if (!$datatable or !$pdo) {
        return false;
    }
    $department = preg_replace('/[^a-zA-Z0-9\s-]/', '', $department);
    $category = preg_replace('/[^a-zA-Z0-9\s-]/', '', $category);
    $brand = preg_replace('/[^a-zA-Z0-9\s-]/', '', $brand);
    $subcategory = preg_replace('/[^a-zA-Z0-9\s-]/', '', $subcategory);
    $model = preg_replace('/[^a-zA-Z0-9\s-]/', '', $model);

    $sku_exists = true;
    while ($sku_exists) {
        $random_string = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 10)), 0, 10);
        $sku = $department . '-' . $category . '-' . $brand . '-' . $subcategory . '-' . $model . '-' . $random_string;

        $stmt = $pdo->prepare("SELECT COUNT(*) as count FROM $datatable WHERE sku = :sku");
        $stmt->bindParam(':sku', $sku);
        $stmt->execute();
        $result = $stmt->fetch();

        if ($result['count'] == 0) {
            $sku_exists = false;
        }
    }
    return $sku;
}

function generateUniqueReferralCode($db = false, $fieldname = 'referral_code', $table = false)
{
    $charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@!-+'; // Only numbers and capital letters
    $codeLength = 9; //for 20 billion users;
    if (!$db) {
        $db = DB();
    }
    if (!$table) {
        $table = 'referral_keys';
    }
    if (!$fieldname) {
        $fieldname = 'referral_code';
    }

    $query = "SHOW TABLES LIKE '$table'";
    $result = $db->query($query);
    if (!$result->rowCount()) {
        $query = "CREATE TABLE $table (uid INT PRIMARY KEY AUTO_INCREMENT, " . $fieldname . " VARCHAR($codeLength) NOT NULL UNIQUE)";
        $db->query($query);
    }

    $exists = true;
    do {
        $code = '';
        for ($i = 0; $i < $codeLength; $i++) {
            $code .= $charset[rand(0, strlen($charset) - 1)];
        }
        $exists = DB_REFERRAL_KEYS()->getDetailsbyReferral_Key($code);

    } while ($exists);

    return $code;
}

function checkifuserexists($mnumber = '', $hashkey = '', $nickname = '')
{
    $table = 'users';
    if (!$hashkey and !$mnumber and !$nickname) {
        return NULL;
    }

    if ($hashkey and checkifexists($table, ['hashkey' => $hashkey], ['uid'])) {
        return true;
    }

    if ($mnumber and checkifexists($table, ['mnumber' => $mnumber], ['uid'])) {
        return true;
    }
    if ($nickname and checkifexists($table, ['nickname' => $nickname], ['uid'])) {
        return true;
    }
}


// Generic DB function
function DB_QUERY($DB = false)
{

    $DBFUNC = new stdClass;
    $DBQueryclass = new DBQUERY($DB);
    $classmap = $DBQueryclass->classMap;

    foreach ($classmap as $key => $value) {
        $DBFUNC->$key = function ($DB) use ($value) {
            return new $value($DB);
        };
    }

    return $DBFUNC;
}

$classMap = [
    'USERS' => 'DB_USERS',
    'USERINFO' => 'DB_USERINFO',
    'FILE_LIST' => 'DB_FILE_LIST',
    'FILE_CONTENT' => 'DB_FILE_CONTENT'
];

/**
 * Class DBQUERY
 *
 * @method DB_USERS USERS($DB = null)
 * @method DB_USERINFO USERINFO($DB = null)
 * @method DB_PROPERTIES PROPERTIES($DB = null)
 * @method DB_REFERRALS REFERRALS($DB = null)
 * @method DB_REFERRAL_KEYS REFERRAL_KEYS($DB = null)
 * @method DB_FILE_CONTENT FILE_CONTENT($DB = null)
 * @method DB_FILE_LIST FILE_LIST($DB = null)
 * @method DB_STORES STORES($DB = null)
 * @method DB_PRODUCTS PRODUCTS($DB = null)
 * @method DB_PRODUCTS_TRANSACTIONS PRODUCTS_TRANSACTIONS($DB = null)
 * @method DB_POS_TRANSACTIONS POS_TRANSACTIONS($DB = null)
 * @method DB_PRODUCTS_TRANSACTIONS_SESSIONS PRODUCTS_TRANSACTIONS_SESSIONS($DB = null)
 * @method DB_CART CART($DB = null)
 * @method DB_PRODUCTSHISTORY PRODUCTS_HISTORY($DB=NULL)
 */
class DBQUERY
{
    public $DB;

    public $classMap = [];

    function __construct($DB = false)
    {
        if (!$DB) {
            $DB = DB();
        }
        $this->DB = $DB;
        global $classMap;
        $this->classMap = $classMap;

    }
    private function createInstance($methodName, $DB = false)
    {
        if (!$DB) {
            $DB = $this->DB ?: DB();
        }
        if (array_key_exists($methodName, $this->classMap)) {
            $className = $this->classMap[$methodName];
            return new $className($DB);
        }
        throw new Exception("Method $methodName not found in class map.");
    }

    public function __call($name, $arguments)
    {
        return $this->createInstance($name, $arguments[0] ?? false);
    }


}

function DBQUERY($DB = false)
{
    return new DBQUERY($DB);
}

function ModifySingleRowwithVerification($table, $newdata, $wherearray)
{
    if (!$wherearray || !$table || !$newdata) {
        return false;
    }

    $exists = checkifexists($table, $wherearray);

    if (!$exists or empty($exists)) {
        return false;
    }

    $db = DB();
    updatedbsimple($db, $table, $newdata, $wherearray);


    $newfetch = checkifexists($table, $wherearray);

    if (!$newfetch or empty($newfetch)) {
        return false;
    }



    foreach ($newdata as $key => $value) {
        $newfetchkey = tryjsondecode($newfetch[$key]);

        if (tryjsondecode($newdata[$key]) !== $newfetchkey) {//remove tryjson decodeif it causes problems

            return false;
        }
        return true;
    }

}

function ModifyDBfield($table, $newdata, $uidorhashkey)
{

    if (!$table) {
        return false;
    }

    //   if (!$newdata or empty($newdata)) {return false;}
    if (!$uidorhashkey or empty($uidorhashkey)) {
        return false;
    }
    if (is_numeric($uidorhashkey)) {
        $wherearray['uid'] = $uidorhashkey;
    } elseif (!is_numeric($uidorhashkey)) {
        $wherearray['hashkey'] = $uidorhashkey;
    }

    /* 
        $exists = checkifexists($table, $wherearray);

        if (!$exists or empty($exists)) {
            return false;
        }

        $db = DB();
        updatedbsimple($db, $table, $newdata, $wherearray);


        $newfetch = checkifexists($table, $wherearray);

        if (!$newfetch or empty($newfetch)) {
            return false;
        }



        foreach ($newdata as $key => $value) {
            $newfetchkey = tryjsondecode($newfetch[$key]);

            if (tryjsondecode($newdata[$key]) !== $newfetchkey) {//remove tryjson decodeif it causes problems

                return false;
            }
            return true;
        } */

    return ModifySingleRowwithVerification($table, $newdata, $wherearray);

}

function DeleteDBbyUIDorHashkey($table, $uidorhashkey)
{
    if (!$uidorhashkey or empty($uidorhashkey) or is_array($uidorhashkey)) {
        return false;
    }
    $wheredata = [];
    if (!is_numeric($uidorhashkey)) {
        $wheredata['hashkey'] = $uidorhashkey;
    } elseif (is_numeric($uidorhashkey)) {
        $wheredata['uid'] = $uidorhashkey;
    } else {
        return false;
    }
    if (!checkifexists($table, $wheredata)) {
        return NULL;
    }
    $delete = deletefromdb($table, $wheredata);
    if (!checkifexists($table, $wheredata)) {
        return true;
    } else {
        return true;
    }
}

function getDetailsbyUIDorHashkey($table, $uidorhashkey, $fieldstoselectarray = '')
{
    if (!$uidorhashkey) {
        return null;
    }
    if (is_numeric($uidorhashkey)) {
        $wherearray['uid'] = $uidorhashkey;
    } else {
        $wherearray['hashkey'] = $uidorhashkey;
    }
    $details = checkifexists($table, $wherearray, $fieldstoselectarray);
    return $details ?? false;
}



trait BASICDB
{
    public function GenerateNewHash($fieldname = 'hashkey')
    {
        return generatenewhash($this->tablename, $fieldname);
    }
    public function InsertIntoDB($data)
    {

        return insertintodb($this->DB, $this->tablename, $data);
    }

    public function InsertIntoDB_ExceptBlank($data)
    {
        foreach ($data as $key => $value) {
            if ($value === null || $value === '') {
                unset($data[$key]);
                continue;
            } elseif ($value === []) {
                $data[$key] = tryjsonencode($value);
                continue;
            }
        }
        return insertintodb($this->DB, $this->tablename, $data);
    }
    public function InsertIntoDBNewDatawithDefaults($data, $requiredfieldsarray = [])
    {
        if (!$data) {
            return false;
        }
        if (!isset($data['createdby']) || !$data['createdby']) {
            $data['createdby'] = CurrentUserUID();
        }

        if (!isset($data['photourl']) || !$data['photourl']) {
            $data['photourl'] = tryjsonencode($data['photourl']);
        }
        $userdata = DBQUERY()->USERS()->getDetailsbyUIDorHashkey($data['createdby']);
        if (!$userdata) {
            return false;
        }
        $datenow = serverdatetimesql();
        $data['created'] = $datenow;
        $data['modified'] = $datenow;
        $data['hashkey'] = $this->GenerateNewHash();
        if (!isset($data['logs']) || !$data['logs']) {
            $username = $userdata['username'] ?? '';
            $useruid = $userdata['uid'] ?? '';
            $data['logs'] = [[$datenow, 'Added by ' . $username . ' (' . $useruid . ')']];
            $data['logs'] = tryjsonencode($data['logs']);
        }
        if ($requiredfieldsarray && is_array($requiredfieldsarray)) {
            foreach ($requiredfieldsarray as $value) {
                if (!isset($data[$value])) {
                    return false;
                } elseif ($data[$value] === null || $data[$value] === '') {
                    return false;
                }
            }
        }
        return $this->InsertIntoDB_ExceptBlank($data);
    }
    function DefaultDBInsert($data, $requiredfieldsarray = [])
    {
        return $this->InsertIntoDBNewDatawithDefaults($data, $requiredfieldsarray);
    }
    function DefaultDBInsertwithHashResult($data, $requiredfieldsarray = [])
    {
        $key = $this->InsertIntoDBNewDatawithDefaults($data, $requiredfieldsarray);
        if (!$key) {
            return false;
        }
        $hash = $this->getHashkeyfromUID($key) ?? false;
        return $hash;
    }

    function DeleteFromDB($wheredata)
    {
        if (!$wheredata or empty($wheredata)) {
            return false;
        }
        return deletefromdb($this->tablename, $wheredata, $this->DB);
    }
    function DeleteDBbyUIDorHashkey($uidorhashkey)
    {
        return DeleteDBbyUIDorHashkey($this->tablename, $uidorhashkey);
    }
    function UpdateDB($data, $wherearray)
    {
        if (!$data or !$wherearray or empty($wherearray)) {
            return false;
        }
        return updatedbsimple($this->DB, $this->tablename, $data, $wherearray);
    }
    function ModifyDBfieldByUIDorHashkey($changeddata, $uidorhashkey)
    {

        if (!$uidorhashkey) {
            return false;
        }

        return ModifyDBfield($this->tablename, $changeddata, $uidorhashkey);
    }

    function ModifySingleRowwithVerification($newdata, $wherearray)
    {
        return ModifySingleRowwithVerification($this->tablename, $newdata, $wherearray);
    }

    function ListFromDB($data = [], $likefields = [], $fieldstoselectarray = '', $orderby = '', $noindex = 0, $whereappend = ' and ', $dateonlyarray = '', $DB = false, $tablename = false)
    {

        //$this->DB = $DB;
        //$this->tablename=$tablename;

        return listselectsql($this->DB, $this->tablename, $data, $likefields, $fieldstoselectarray, $orderby, $noindex, $whereappend, $dateonlyarray);
    }
    function ListFromDBMultipleValuesSameField($valuearray, $Columnname, $fieldstoselect = '', $noindex = 0)
    {
        //allows searching of database with OR in wherearray
        return selectfromDBMultipleValuesSameField($this->DB, $this->tablename, $valuearray, $Columnname, $fieldstoselect, $noindex);
    }
    function ListFromDBMultipleValuesSameFieldUSINGIN($valuearray, $Columnname, $fieldstoselect = '', $noindex = 0)
    {
        return selectfromDBMultipleValuesSameField($this->DB, $this->tablename, $valuearray, $Columnname, $fieldstoselect, $noindex);
    }
    function CheckifExists($wherearray, $fieldstoselectarray = '', $orderby = '')
    {
        if (!$wherearray) {
            return false;
        }
        return checkifexists($this->tablename, $wherearray, $fieldstoselectarray, $orderby);
    }
    function CheckifUIDorHashKeyExist($uidorhashkey, $fieldstoselectarray = '', $orderby = '')
    {
        if (!$uidorhashkey or is_array($uidorhashkey)) {
            return false;
        }
        $field = '';
        if (is_numeric($uidorhashkey)) {
            $field = 'uid';
        } elseif (is_string($uidorhashkey)) {
            $field = 'hashkey';
        } else {
            return false;
        }
        return checkifexists($this->tablename, [$field => $uidorhashkey], $fieldstoselectarray, $orderby);
    }
    function getDetailsbyUIDorHashkey($uidorhashkey, $fieldstoselectarray = '')
    {
        return getDetailsbyUIDorHashkey($this->tablename, $uidorhashkey, $fieldstoselectarray);
    }
    function getcurrentTableHash($fieldstoselectarray = ['uid,hashkey,created,modified'])
    {
        $data = $this->ListFromDB([], [], $fieldstoselectarray);
        return hash('sha256', json_encode($data));
    }
    function getcurrentTableHashSHORT()
    {
        //Not compatible with the original getcurrentTableHash function
        return $this->getcurrentTableHash(['uid', 'modified']);
    }
    function getUIDfromHashkey($hashkey)
    {
        if (!$hashkey) {
            return false;
        }
        if (is_numeric($hashkey)) {
            return $hashkey;
        }
        return $uid = $this->getDetailsbyUIDorHashkey($hashkey, ['uid'])['uid'] ?? false;
    }
    function getHashkeyfromUID($uid)
    {
        if (!$uid) {
            return false;
        }
        if (is_numeric($uid)) {
            return $this->getDetailsbyUIDorHashkey($uid, ['hashkey'])['hashkey'] ?? false;
        } elseif (is_string($uid)) {
            return $uid;
        }

    }

    function getSpecificFieldandTryJSONDecodebyUIDorHASHKEY($uidorhashkey, $fieldname)
    {
        if (!$uidorhashkey) {
            return false;
        }
        $details = $this->getDetailsbyUIDorHashkey($uidorhashkey, [$fieldname])[$fieldname] ?? false;
        if (!$details) {
            return false;
        }
        if (!is_array($details)) {
            $details = tryjsondecode($details);
        }
        return $details;
    }
    function setSpecificFieldbyUIDorHASHKEY($uidorhashkey, $fieldname, $dataorarray)
    {
        if (is_array($dataorarray)) {
            $data = tryjsonencode($dataorarray);
        } else {
            $data = $dataorarray;
        }
        return $this->ModifyDBfieldByUIDorHashkey([$fieldname => $fieldname], $uidorhashkey);
    }
    function AddtoSpecificFieldArraybyUIDorHASHKEY($uidorhashkey, $fieldname, $datatoadd)
    {
        $data = $this->getSpecificFieldandTryJSONDecodebyUIDorHASHKEY($uidorhashkey, $fieldname);
        if (!$data) {
            $data = [$datatoadd];
        } else {
            $data[] = $datatoadd;
        }
        $new = $this->setSpecificFieldbyUIDorHASHKEY($uidorhashkey, $fieldname, $data);
        if ($new) {
            return true;
        } else {
            return false;
        }
    }
    function ClearSpecificFieldbyUIDorHASHKEY($uidorhashkey, $fieldname)
    {
        return $this->setSpecificFieldbyUIDorHASHKEY($uidorhashkey, $fieldname, []);
    }
    function getLogsbyUIDorHASH($uidorhashkey)
    {
        return $this->getSpecificFieldandTryJSONDecodebyUIDorHASHKEY($uidorhashkey, 'logs');
    }
    function SetLogsbyUIDorHashkey($uidorhashkey, $logsarray)
    {
        return $this->setSpecificFieldbyUIDorHASHKEY($uidorhashkey, 'logs', $logsarray);
    }

    function AddLogbyUIDorHashkey($uidorhashkey, $newlog)
    {
        $logs = $this->getLogsbyUIDorHASH($uidorhashkey);
        if (!$logs) {
            $logs = [[serverdatetimesql(), $newlog]];
        } else {
            $logs[] = [serverdatetimesql(), $newlog];
        }
        $new = $this->SetLogsbyUIDorHashkey($uidorhashkey, $logs);
        if ($new) {
            return true;
        } else {
            return false;
        }
    }

    function ClearLogbyUIDorHashkey($uidorhashkey)
    {
        return $this->SetLogsbyUIDorHashkey($uidorhashkey, []);
    }

    function getFilesbyUIDorHASH($uidorhashkey)
    {
        return $this->getSpecificFieldandTryJSONDecodebyUIDorHASHKEY($uidorhashkey, 'files');
    }

    function setFilesbyUIDorHASH($uidorhashkey, $data)
    {
        return $this->setSpecificFieldbyUIDorHASHKEY($uidorhashkey, 'files', $data);
    }
    function addFilesbyUIDorHASH($uidorhashkey, $datatoadd)
    {
        return $this->AddtoSpecificFieldArraybyUIDorHASHKEY($uidorhashkey, 'files', $datatoadd);
    }
    function clearFilesbyUIDorHASH($uidorhashkey)
    {
        return $this->setFilesbyUIDorHASH($uidorhashkey, []);
    }

    function getphotoURLsbyUIDorHASH($uidorhashkey)
    {
        return $this->getSpecificFieldandTryJSONDecodebyUIDorHASHKEY($uidorhashkey, 'photourl');
    }

    function setphotoURLsbyUIDorHASH($uidorhashkey, $data)
    {
        return $this->setSpecificFieldbyUIDorHASHKEY($uidorhashkey, 'photourl', $data);
    }
    function addphotoURLsbyUIDorHASH($uidorhashkey, $data)
    {
        return $this->AddtoSpecificFieldArraybyUIDorHASHKEY($uidorhashkey, 'photourl', $data);
    }
    function cleaphotoURLsbyUIDorHASH($uidorhashkey)
    {
        return $this->ClearSpecificFieldbyUIDorHASHKEY($uidorhashkey, 'photourl');
    }





    function SetRemarksbyUIDorHASHKEY($uidorhashkey, $newremarks)
    {
        return $this->ModifyDBfieldByUIDorHashkey(['remarks' => $newremarks], $uidorhashkey);
    }
    function GetRemarksbyUIDorHASHKEY($uidorhashkey)
    {
        return $this->getDetailsbyUIDorHashkey($uidorhashkey, ['remarks'])['remarks'] ?? false;
    }
    function ClearRemarksbyUIDorHASHKEY($uidorhashkey)
    {
        return $this->SetRemarksbyUIDorHASHKEY($uidorhashkey, '');
    }

    function sqlqueryDB($query, $bindableValues, $noindex = 0)
    {
        return selectfromsimple($this->DB, $query, $bindableValues, $noindex);
    }

    function GetMaxValueofFieldTable($fieldname)
    {
        if (!$fieldname) {
            return false;
        }
        $query = "SELECT MAX(" . $fieldname . ") FROM " . $this->tablename . " AS greatest_value";
        return selectfromsimple($this->DB, $query)[0]['MAX(uid)'] ?? false;
    }
    function getIncrementedMaxValueofFieldTable($fieldname, $incrementby = 1)
    {
        if (!$fieldname) {
            return false;
        }
        if (!$incrementby) {
            $incrementby = 1;
        }
        return $this->GetMaxValueofFieldTable($fieldname) + $incrementby;
    }
    function GetLastUIDofTable()
    {
        return $this->GetMaxValueofFieldTable('uid');
    }
    function GetNewAvailableUIDofTable()
    {
        return $this->getIncrementedMaxValueofFieldTable('uid');
    }

    function ListbyFieldDateOnly($fieldname, $sqldateonlyformat, $fieldstoselect = '')
    {
        if (!$fieldname || !$sqldateonlyformat) {
            return false;
        }
        $array = $this->ListFromDB([], [], $fieldstoselect);
        $results = [];
        foreach ($array as $key => $value) {
            $currentDateFieldValue = $value[$fieldname];

            if (strpos($currentDateFieldValue, $sqldateonlyformat) !== false) {
                $results[] = $value;
            }

        }
        return $results;
    }

    function ListbyDateCreated($sqldateonlyformat, $fieldstoselect = '')
    {
        return $this->ListbyFieldDateOnly('created', $sqldateonlyformat, $fieldstoselect);
    }
    function ListbyDateModified($sqldateonlyformat, $fieldstoselect = '')
    {
        return $this->ListbyFieldDateOnly('modified', $sqldateonlyformat, $fieldstoselect);
    }
    function ModifyDBSinglefieldbyUID($uidorhashkey, $fieldname, $newfieldvalue)
    {
        if (!$uidorhashkey || !$fieldname || !$newfieldvalue) {
            return false;
        }
        return $this->ModifyDBfieldByUIDorHashkey([$fieldname => $newfieldvalue], $uidorhashkey);

    }
    function ListbyUniqueField_SingleField($fieldname, $data = [], $fieldstoselectarray = '', $likefields = [], $orderby = '', $noindex = 0, $whereappend = ' and ', $dateonlyarray = '')
    {
        if (!$fieldname) {
            return false;
        }
        $result = $this->ListFromDB($data, $likefields, $fieldstoselectarray, $orderby, $noindex, $whereappend, $dateonlyarray, $this->DB, $this->tablename);
        if (!$result) {
            return null;
        }

        $target_column = array_column($result, $fieldname) ?? false;
        if (!$target_column) {
            return false;
        }
        $unique = array_unique($target_column);
        return array_values($unique);
    }
    function InsertBasicDBHashCreatedModified($data)
    {
        if (!$data) {
            return false;
        }
        $data['hashkey'] = $this->GenerateHashKey();
        $date = serverdatetimesql();
        $data['created'] = $date;
        $data['modified'] = $date;

        $this->InsertIntoDB($data);

    }




}

class DBFunctions
{
    public $tablename;
    public $DB;
    use BASICDB;
    public function __construct($tablename, $DB = false)
    {

        if (!$tablename) {
            return false;
        }
        if (!isset($this->tablename)) {
            $this->tablename = '';
        }
        if ($tablename && !$this->tablename) {
            $this->tablename = $tablename;
        }
        if (!isset($this->DB)) {
            $this->DB = null;
        }
        if (!$DB) {
            $this->DB = DB();
        } else {
            $this->DB = $DB;
        }
        if (!$this->DB) {
            return false;
        }


    }


}

function DBFunctions($tablename, $DB = false)
{
    if (!$tablename) {
        return false;
    }

    return new DBFunctions($tablename, $DB);
}


trait STATUSDB
{

    public function UpdateStatus($uidorhashkey, $status)
    {
        if ($status === null || $status === false || !$uidorhashkey) {
            return false;
        }
        return $this->ModifyDBfieldByUIDorHashkey(['status' => $status], $uidorhashkey);
    }
    public function ViewStatus($uidorhashkey, $fieldstoselect = '')
    {
        return $this->getDetailsbyUIDorHashkey($uidorhashkey, $fieldstoselect);
    }

}

trait LOGSDB
{

    public function SetLogbyUID($uidorhashkey, $LogStringOrArray)
    {
        if (!$LogStringOrArray || !$uidorhashkey) {
            return false;
        }
        if (!is_array($LogStringOrArray)) {
            $LogStringOrArray = json_decode($LogStringOrArray, true) ?? false;
            if (!$LogStringOrArray) {

                return false;
            }
        }

        return $this->ModifyDBfieldByUIDorHashkey(['logs' => $LogStringOrArray], $uidorhashkey);
    }
    public function DeleteFullLogbyUID($uidorhashkey)
    {
        return $this->DeleteDBbyUIDorHashkey($uidorhashkey);
    }
    public function viewLogsbyUID($uidorhashkey)
    {
        if (!$uidorhashkey) {
            return false;
        }
        return json_decode($this->getDetailsbyUIDorHashkey($uidorhashkey, ['logs'])['logs'] ?? false, true) ?? false;
    }
    public function deleteLogbyArrayIndex($uidorhashkey, $LogArrayIndex)
    {
        if (!$uidorhashkey || !$LogArrayIndex || !is_numeric($LogArrayIndex)) {
            return false;
        }
        $logs = $this->logs->viewLogsbyUID($uidorhashkey);
        if (!$logs) {
            return false;
        }
        $LogsArray = json_decode($uidorhashkey, true) ?? false;
        if (!$LogsArray) {
            return false;
        }
        unset($LogsArray[$LogArrayIndex]);
        return $this->SetLogbyUID($uidorhashkey, json_encode(array_values($LogsArray)));
    }
    public function AddLog($uidorhashkey, $newlog)
    {

        if (!$uidorhashkey || !$newlog) {
            return false;
        }
        $exists = $this->getDetailsbyUIDorHashkey($uidorhashkey);

        if (!$exists) {
            return false;
        }
        $logs = $this->viewLogsbyUID($uidorhashkey);

        if (!$logs) {
            $logs = [];
            $logs[] = [serverdatetimesql(), $newlog];
        } elseif (is_array($logs)) {
            $logs[] = [serverdatetimesql(), $newlog];
        } else {
            return false;
        }

        return $this->SetLogbyUID($uidorhashkey, $logs);
    }


}



trait DBClassSearch
{

    function initialize($data = [], $likefields = [], $fieldstoselectarray = '', $orderby = '', $noindex = 0, $whereappend = ' and ', $dateonlyarray = '', $newdata = false, $DB = false)
    {
        if (is_array($fieldstoselectarray)) {
            foreach ($fieldstoselectarray as $key => $value) {
                $fieldstoselectarray[$key] = strtolower($value);
            }
        }

        if (!isset($this->DB) || !$this->DB) {
            $this->DB = $DB;
        }
        if (!$this->DB) {
            $this->DB = DB();
        }

        if ($newdata and is_array($newdata)) {
            $this->data = $newdata;
        } else {

            $this->data = DBFunctions($this->tablename, $this->DB)->ListFromDB($data, $likefields, $fieldstoselectarray, $orderby, $noindex, $whereappend, $dateonlyarray);
        }
    }

    function checkifUIDorHashKeyexist($uidorhashkey, $newdata = false)
    {
        if (!$uidorhashkey) {
            return false;
        }
        return !!$this->getDetailsbyUIDorHashkey($uidorhashkey, $exact = true, $newdata);
    }

    function currentTableHash($newdata = false)
    {
        if (!$newdata) {
            $newdata = $this->data;
        }
        return hash('sha256', json_encode($newdata));
    }

    function getUIDfromHASH($hash, $newdata = false)
    {
        if (!$hash) {
            return false;
        }

        if (!$newdata) {
            $newdata = $this->data;
        }

        return $this->List('hashkey', $hash, true, false, $newdata)[0]['uid'] ?? '';
    }

    function getHASHfromUID($uid, $newdata = false)
    {
        if (!$uid) {
            return false;
        }

        if (!$newdata) {
            $newdata = $this->data;
        }

        return $this->List('uid', $uid, true, false, $newdata)[0]['hashkey'] ?? '';
    }

    function List($fieldname, $contenttosearch, $exact = true, $caseinsensitive = false, $newdata = false, $usestrpos = false)
    {
        if (!$fieldname or !$contenttosearch) {
            return false;
        }
        if (is_array($newdata)) {
            return sqlarray_2dfilter($newdata, $fieldname, $contenttosearch, $exact, $caseinsensitive, $usestrpos);
        } else {
            if (!$this->data) {
                return false;
            }
            return sqlarray_2dfilter($this->data, $fieldname, $contenttosearch, $exact, $caseinsensitive, $usestrpos);
        }
    }

    function Find($fieldname, $contenttosearch, $exact = true, $caseinsensitive = false, $newdata = false)
    {
        return $this->List($fieldname, $contenttosearch, $exact, $caseinsensitive, $newdata)[0] ?? false;
    }

    function GetValue($fieldnametosearch, $contenttosearch, $fieldvaluetoget, $exact = true, $caseinsensitive = false, $newdata = false)
    {
        return $this->List($fieldnametosearch, $contenttosearch, $exact, $caseinsensitive, $newdata)[0][$fieldvaluetoget] ?? false;
    }

    function getDetailsbyUIDorHashkey($uidorhashkey, $exact = true, $newdata = false)
    {
        if (!$uidorhashkey) {
            return false;
        }
        if (!is_numeric($uidorhashkey)) {
            return $this->Find('hashkey', $uidorhashkey, $exact, false, $newdata);
        }
        return $this->Find('uid', $uidorhashkey, $exact, false, $newdata);
    }
    function getValueByUIDorHashkey($uidorhashkey, $fieldtoreturn, $newdata = false)
    {
        if (!$uidorhashkey || !$fieldtoreturn) {
            return false;
        }
        if (is_numeric($uidorhashkey)) {
            $field = 'uid';
        } else {
            $field = 'hashkey';
        }
        return $this->GetValue($field, $uidorhashkey, $fieldtoreturn, $exact = true, $caseinsensitive = false, $newdata);
    }

    function getCreatedDate($uidorhashkey, $newdata = false)
    {
        return $this->getValueByUIDorHashkey($uidorhashkey, 'created', $newdata);
    }

    function getModifiedDate($uidorhashkey, $newdata = false)
    {
        return $this->getValueByUIDorHashkey($uidorhashkey, 'modified', $newdata);
    }
}



//USER DB FUNCTIONS


function trylogin($mnumber, $password)
{
    //Logs Password

    if (!$mnumber or !$password) {
        return false;
    }
    $wherearray['mnumber'] = $mnumber;
    $wherearray['password'] = hash('sha256', $password);
    $wherearray['active'] = 1;
    $user = checkifexists('users', $wherearray, ['hashkey', 'uid']);
    if ($user and !empty($user)) {
        NewLog('system', 'login', 'Successful Login with Username' . $mnumber . '', $useruid = '-1');
        return $user;
    } else {
        NewLog('system', 'login', 'Failed Login with Username' . $mnumber . ' and password ' . $password, $useruid = '-1');
        return false;
    }
}


class UserSettingsDB
{
    function Get($uidorhashkey)
    {
        return GetUserSettings($uidorhashkey);
    }
    function Clear($uidorhashkey)
    {
        return ClearUserSettings($uidorhashkey);
    }
    function Update($uidorhashkey, $newsettingsvalue)
    {
        return UpdateUserSettings($uidorhashkey, $newsettingsvalue);
    }
}
class UserNotesDB
{
    function Get($uidorhashkey)
    {
        return GetUserNotes($uidorhashkey);
    }
    function Clear($uidorhashkey)
    {
        return ClearUserNotes($uidorhashkey);
    }
    function Update($uidorhashkey, $newnotevalue)
    {
        return UpdateUserNotes($uidorhashkey, $newnotevalue);
    }
}

class UserExecDB
{
    function Get($uidorhashkey)
    {
        return GetUserExec_Command($uidorhashkey);
    }
    function Clear($uidorhashkey)
    {
        return ClearUserExec_Command($uidorhashkey);
    }
    function Update($uidorhashkey, $exec_command_js)
    {
        return UpdateUserExec_Command($uidorhashkey, $exec_command_js);
    }
}
class UserBalanceDB
{
    function GetUserTotalBalancebyUID($uidorhashkey = '')
    {
        return GetUserTotalBalancebyUID($uidorhashkey);
    }
    function GetUserTotalCreditbyUID($uidorhashkey)
    {
        return GetUserTotalCreditbyUID($uidorhashkey);
    }
    public function UserTransferBalancetoAnotherUser($SenderuserUIDorHash, $RecipientUserUIDorHash, $amount)
    {
        return UserTransferBalancetoAnotherUser($SenderuserUIDorHash, $RecipientUserUIDorHash, $amount);
    }
    public function AddBalance($userUIDorHash, $amount)
    {
        return AddBalanceToUser($userUIDorHash, $amount);
    }
    public function checkAndDeductBalance($amount, $useruidorhashkey = '')
    {
        return checkAndDeductBalance($amount, $useruidorhashkey);
    }
    public function checkBalanceifEnough($amount, $useruidorhashkey = '')
    {
        return checkBalance($amount, $useruidorhashkey);
    }
    function deductBalance($amount, $useruidorhashkey = '')
    {
        return deductBalance($amount, $useruidorhashkey);
    }
}


enum UserType: string
{
    case ULTIMATE = 'ultimate';
    case SUPER_OPERATOR = 'super operator';
    case OPERATOR = 'operator';
    case COORDINATOR = 'coordinator';
    case USER = 'user';
    case RIDER = 'rider';
    case AUDIT = 'audit';
    case STORE_OWNER = 'store owner';
    case STORE_MANAGER = 'store manager';
    case SUPPLIER = 'supplier';
    case SUPPLIER_OVERSEER = 'supplier overseer';
    case WHOLESALE_BUYER = 'wholesale buyer';
}


class DB_USERS
{
    public $DB = false;
    public $tablename = 'users';
    use BASICDB;
    public function __construct($DB = false)
    {
        if (!$DB) {
            $DB = DB();
        }
        if (!$DB) {
            return false;
        }
        if ($DB) {
            $this->DB = $DB;
        }
        if (!$this->tablename) {
            return false;
        }
    }

    function isTargetUserActive($uidorhashkey)
    {
        return isTargetUserActive($uidorhashkey);
    }

    function NewUser($mnumber, $password, $nickname = '', $acct_type = '', $parentid = '', $active = 0, $target_uids = [], $notes = '', $exec_command = '', $settings = '', $multiple_logins = 0, $photourl = '')
    {
        return NewUser($mnumber, $password, $nickname, $acct_type, $parentid, $active, $target_uids, $notes, $exec_command, $settings, $multiple_logins, $photourl);
    }
    function ModifyUser($newdata, $uidorhashkey)
    {
        return ModifyUser($newdata, $uidorhashkey);
    }
    public function Settings()
    {
        return new UserSettingsDB;
    }
    public function Notes()
    {
        return new UserNotesDB;
    }
    public function Exec()
    {
        return new UserExecDB;
    }
    function DeleteUser($uidorhashkey)
    {
        return DeleteUser($uidorhashkey);
    }
    function GetUserDatabyUID($uidorhashkey, $fieldstoselect = '')
    {
        return GetUserDatabyUID($uidorhashkey, $fieldstoselect);
    }
    function getUserNumberbyHashkey($hashkey)
    {
        return getUserNumberbyHashkey($hashkey);
    }
    function GetUserUIDbyHashkey($hashkey)
    {
        return GetUserUIDbyHashkey($hashkey);
    }
    function GetUserTypeInDB($uidorhashkey = '')
    {
        return GetUserTypeInDB($uidorhashkey);
    }
    function Balance()
    {
        return new UserBalanceDB;
    }
    function GetParentUIDofUser($useruid = '')
    {
        return GetParentUIDofUser($useruid);
    }
    function GetUserCoordinatorNumber($uid = '')
    {
        return GetUserCoordinatorNumber($uid);
    }
    function setUserCoordinator($uidorhashkey, $coordinatoruid)
    {
        return setUserCoordinator($uidorhashkey, $coordinatoruid);
    }
    function ListALLUsers($wheredata = [], $fieldstoselect = '', $orderby = '')
    {
        return ListALLUsers($wheredata, $fieldstoselect, $orderby);
    }
    function ListUserIDsbyParent($parentuid, $fieldstoselect = '', $orderby = '')
    {
        return ListUserIDsbyParent($parentuid, $fieldstoselect, $orderby);
    }
    function ListUserIdsHashkey()
    {
        return ListUserIdsHashkey();
    }
    function searchUsersByParentUid($array, $parentUid, &$result)
    {
        return searchUsersByParentUid($array, $parentUid, $result);
    }
    function ListChildUsersofParent($parentuid, $fieldstoselect = '', $addself = false)
    {
        return ListChildUsersofParent($parentuid, $fieldstoselect, $addself);
    }
    function isTargetUserAChildofParent($target_useruidorhash, $parentuid = '', $fieldstoselect = '', $addself = false)
    {
        return isTargetUserAChildofParent($target_useruidorhash, $parentuid, $fieldstoselect, $addself);
    }
    function isTargetUserModificationAllowed($currentuseruidorhash, $targetuseruidorhash, $conditiontrue = true)
    {
        return isTargetUserModificationAllowed($currentuseruidorhash, $targetuseruidorhash, $conditiontrue);
    }
    function UserTransferBalancetoAnotherUser($SenderUID, $RecipientUID, $amount)
    {
        return UserTransferBalancetoAnotherUser($SenderUID, $RecipientUID, $amount);
    }


}

function DB_USERS($DB = false)
{
    return new DB_USERS($DB);
}




function NewUser($mnumber, $password, $nickname = '', $acct_type = '', $parentid = '', $active = 0, $target_uids = [], $notes = '', $exec_command = '', $settings = '', $multiple_logins = 0, $photourl = '', $referralcode = '')
{
    if (checkifuserexists($mnumber)) {
        return 'EXISTS';
    }
    $hash = generatenewhash();
    $datenow = serverdatetimesql();
    if ($multiple_logins) {
        $multiple_logins = 1;
    }

    $DB = DB();

    //   $referralcode = generateUniqueReferralCode($DB, 'users', 'referralcode');
    if ($photourl and is_array($photourl)) {
        $photourl = json_encode($photourl);
    }
    $photourl ??= '';
    $data = [
        'hashkey' => $hash,
        'mnumber' => $mnumber,
        'nickname' => $nickname,
        'acct_type' => $acct_type,
        'parentuid' => $parentid,
        'created' => $datenow,
        'modified' => $datenow,
        'active' => $active,
        'password' => hash('sha256', $password),
        'targetuids' => json_encode([]),
        'notes' => $notes,
        'settings' => $settings,
        'exec_command' => $exec_command,
        'multiple_logins' => $multiple_logins,
        'referralcode' => $referralcode,
        'photourl' => $photourl
    ];
    $key = insertintodb($DB, 'users', $data);
    if ($key) {
        return $key;
    } else {
        return false;
    }
}

function ModifyUser($newdata, $uidorhashkey)
{
    return ModifyDBfield('users', $newdata, $uidorhashkey);
}

function GetUserSettings($uidorhashkey)
{
    return tryjsondecode(GetUserDatabyUID($uidorhashkey)['settings']) ?? false;
}
function UpdateUserSettings($uidorhashkey, $newsettingsvalue)
{
    return ModifyUser(['settings' => $newsettingsvalue], $uidorhashkey);
}
function ClearUserSettings($uidorhashkey)
{
    return ModifyUser(['settings' => ''], $uidorhashkey);
}

function isTargetUserActive($uidorhashkey)
{
    if (!$uidorhashkey) {
        return null;
    }
    $getuser = GetUserDatabyUID($uidorhashkey, ['active'])['active'] ?? null;
    if (!$getuser or $getuser == 0 or $getuser === '0') {
        return false;
    }
    return $getuser;
}


function GetUserNotes($uidorhashkey)
{
    return GetUserDatabyUID($uidorhashkey)['notes'] ?? false;
}

function UpdateUserNotes($uidorhashkey, $newnotevalue)
{
    return ModifyUser(['notes' => $newnotevalue], $uidorhashkey);
}
function ClearUserNotes($uidorhashkey)
{
    return ModifyUser(['notes' => ''], $uidorhashkey);
}

function UpdateUserExec_Command($uidorhashkey, $exec_command_js)
{
    return ModifyUser(['exec_command' => $exec_command_js], $uidorhashkey);
}
function ClearUserExec_Command($uidorhashkey)
{
    return ModifyUser(['exec_command' => ''], $uidorhashkey);
}

function GetUserExec_Command($uidorhashkey)
{
    return GetUserDatabyUID($uidorhashkey)['exec_command'] ?? false;
}

function DeleteUser($uidorhashkey)
{
    return DeleteDBbyUIDorHashkey('users', $uidorhashkey);
}

function GetUserDatabyUID($uidorhashkey, $fieldstoselect = '')
{
    return getDetailsbyUIDorHashkey('users', $uidorhashkey, $fieldstoselect);
}

function checkifuserisActive($uidorhashkey)
{
    $user = GetUserDatabyUID($uidorhashkey, ['active']);
    if (!$user) {
        return NULL;
    }
    if ($user['active'] == 0) {
        return false;
    }
    if ($user['active'] == 1) {
        return true;
    }
    return NULL;
}

function getUserNumberbyHashkey($hashkey)
{
    if (is_numeric($hashkey)) {
        return false;
    }
    $user = GetUserDatabyUID($hashkey, ['mnumber']);
    if (!$user) {
        return false;
    }
    return $user['mnumber'];
}
function GetUserUIDbyHashkey($hashkey)
{
    if (!$hashkey or is_numeric($hashkey)) {
        return false;
    }
    $userdata = GetUserDatabyUID($hashkey, ['uid']);
    if (!$userdata or !$userdata['uid']) {
        return false;
    }
    return $userdata['uid'];
}

function GetUserTypeInDB($uidorhashkey = '')
{
    if (!$uidorhashkey) {
        return false;
    }
    return strtolower(GetUserDatabyUID($uidorhashkey, ['acct_type'])['acct_type']);
}


function GetUserTotalBalancebyUID($uidorhashkey = '')
{
    if (!$uidorhashkey) {
        global $CurrentUserUID;
        $uidorhashkey = $CurrentUserUID;
    }
    return getDetailsbyUIDorHashkey('users', $uidorhashkey, ['total_balance'])['total_balance'] ?? FALSE;
    // return checkifexists('users',['uid'=>$uid],['total_balance'])['total_balance'] ?? FALSE;
}

function GetUserTotalCreditbyUID($uidorhashkey)
{
    return getDetailsbyUIDorHashkey('users', $uidorhashkey, ['total_credit'])['total_credit'] ?? FALSE;
    //  return checkifexists('users',['uid'=>$uid],['total_credit'])['total_credit'] ?? FALSE;
}

function ChangeUserPassword($uidorhashkey, $password)
{
    if (!$uidorhashkey or !$password) {
        return false;
    }
    return ModifyUser(['password' => hash('sha256', $password)], $uidorhashkey);
}

function UserTransferBalancetoAnotherUser($SenderuserUIDorHash, $RecipientUserUIDorHash, $amount)
{
    global $IsUserOperator;
    global $IsUserSuperOperator;
    global $IsUserUltimate;
    $Senderbalance = GetUserTotalBalancebyUID($SenderuserUIDorHash);
    $Recipientbalance = GetUserTotalBalancebyUID($RecipientUserUIDorHash);
    if ($IsUserSuperOperator or $IsUserUltimate) { // ad $IsUserOperator to remove limit of operator
        $Senderbalance = 99999999999999999999999999;
    }

    if (!$Senderbalance or $Recipientbalance === false) {
        // echo 'recipienterror';
        return false;
    }
    if ($Senderbalance < $amount) {
        //echo 'amounterror';
        return false;
    }
    $SenderNewbalance = $Senderbalance - $amount;
    $RecipientNewbalance = $Recipientbalance + $amount;

    if (!$IsUserSuperOperator and !$IsUserUltimate) { // add !$IsUserOperator and  to remove limit of operator
        $deductbalance = checkAndDeductBalance($amount, $SenderuserUIDorHash);
    }


    $Senderbalance = GetUserTotalBalancebyUID($SenderuserUIDorHash);
    $Recipientbalance = GetUserTotalBalancebyUID($RecipientUserUIDorHash);



    if ($Senderbalance === $SenderNewbalance or ($IsUserSuperOperator or $IsUserUltimate)) { // add $IsUserOperator or to remove limit of operator
        $AddBalanceSuccessful = AddBalanceToUser($RecipientUserUIDorHash, $amount);
        $Recipientbalance = GetUserTotalBalancebyUID($RecipientUserUIDorHash);

        $creditrequest = DB_CREDIT_REQUESTS()->CreateCreditRequest($amount, $SenderuserUIDorHash, $RecipientUserUIDorHash, 0, null, serverdatetimesql());

        if (!$creditrequest) {
            return false;
        }

        if ($Recipientbalance === $RecipientNewbalance) {
            return true;
        }
    } else {
        return false;
    }
}

function checkBalance($amount, $useruidorhashkey = '')
{
    if (!$amount or !is_numeric($amount) or $amount < 0) {
        return false;
    }

    if (!$useruidorhashkey) {
        $useruidorhashkey = CurrentUserUID();
    }
    if (!$useruidorhashkey) {
        return false;
    }

    $user = GetUserDatabyUID($useruidorhashkey, ['total_balance']);
    if (!$user or empty($user) or $user['total_balance'] < $amount) {
        return false;
    }

    return true;
}

function deductBalance($amount, $useruidorhashkey = '')
{
    if (!checkBalance($amount, $useruidorhashkey)) {
        return false;
    }

    $user = GetUserDatabyUID($useruidorhashkey, ['total_balance']);
    $new_balance = $user['total_balance'] - $amount;
    $data['total_balance'] = $new_balance;

    ModifyUser($data, $useruidorhashkey);
    $user = GetUserDatabyUID($useruidorhashkey, ['total_balance']);

    return $user['total_balance'] === $new_balance;
}

function checkAndDeductBalance($amount, $useruidorhashkey = '')
{
    if (!$amount or !is_numeric($amount)) {
        return false;
    }
    if ($amount < 0) {
        return false;
    }

    if (!$useruidorhashkey) {
        $useruidorhashkey = CurrentUserUID();
    }
    if (!$useruidorhashkey) {
        return false;
    }
    $user = GetUserDatabyUID($useruidorhashkey, ['total_balance']);
    if (!$user or empty($user)) {
        return false;
    }
    if ($user['total_balance'] < $amount) {
        return false;
    }
    $new_balance = $user['total_balance'] - $amount;
    $data['total_balance'] = $new_balance;
    ModifyUser($data, $useruidorhashkey);
    $user = GetUserDatabyUID($useruidorhashkey, ['total_balance']);
    if ($user['total_balance'] === $new_balance) {
        return true;
    } else {
        return false;
    }
}

function AddBalanceToUser($userUIDorHash, $amount)
{
    if (!$amount) {
        return false;
    }
    $oldbalance = GetUserTotalBalancebyUID($userUIDorHash);
    $newbalance = $oldbalance + $amount;
    $data['total_balance'] = $newbalance;
    ModifyUser(['total_balance' => $newbalance], $userUIDorHash);
    if ($newbalance === GetUserTotalBalancebyUID()) {
        return true;
    } else {
        return false;
    }
}


function GetParentUIDofUser($useruid = '')
{
    if (!$useruid) {
        global $CurrentUserUID;
        $useruid = $CurrentUserUID;
    }
    if (!$useruid) {
        $useruid = CurrentUserUID();
    }
    if (!$useruid) {
        return false;
    }

    $ParentUID = GetUserDatabyUID($useruid, ['parentuid'])['parentuid'] ?? false;
    if ($ParentUID) {
        return $ParentUID;
    } else {
        return false;
    }
}



function GetUserCoordinatorNumber($uid = '')
{
    if (!$uid) {
        global $CurrentUserUID;
        $uid = $CurrentUserUID;
    }
    if (!$uid) {
        return false;
    }
    $ParentUID = GetParentUIDofUser($uid);
    if (!$ParentUID) {
        return false;
    }
    $ParentNumber = GetUserDatabyUID($ParentUID, ['mnumber'])['mnumber'] ?? false;
    return $ParentNumber;
}

function setUserCoordinator($uidorhashkey, $coordinatoruid)
{
    $newdata['parentuid'] = $coordinatoruid;
    return ModifyDBfield('users', $newdata, $uidorhashkey);
}

function ListALLUsers($wheredata = [], $fieldstoselect = '', $orderby = '')
{
    global $DB;
    if (!$wheredata) {
        $wheredata = [];
    }

    $list = listselectsql($DB, 'users', $wheredata, [], $fieldstoselect, $orderby) ?? '';
    if (empty($list)) {
        return false;
    }
    return $list;
}

function ListUserIDsbyParent($parentuid, $fieldstoselect = '', $orderby = '')
{
    if (!$parentuid) {
        return false;
    }
    return ListALLUsers(['parentuid' => $parentuid], $fieldstoselect, $orderby);
}

function ListUserIdsHashkey()
{
    $list = ListALLUsers([], ['hashkey', 'uid']);
    return $list ?? '';
}

class UserQuickMultipleSearch
{
    use DBClassSearch;
    public $data;

    public $tablename = 'users';

    private $parentidresults = [];
    public $DB;

    public function __construct($data = [], $likefields = [], $fieldstoselectarray = '', $orderby = '', $noindex = 0, $whereappend = ' and ', $dateonlyarray = '', $newdata = false)
    {
        return $this->initialize($data, $likefields, $fieldstoselectarray, $orderby, $noindex, $whereappend, $dateonlyarray, $newdata, $this->DB, $this->tablename);
    }

    function getNickname($uidorhashkey, $newdata = false)
    {
        return $this->getValueByUIDorHashkey($uidorhashkey, 'nickname', $newdata);
    }
    function getUsername($uidorhashkey, $newdata = false)
    {
        return $this->getValueByUIDorHashkey($uidorhashkey, 'username', $newdata);
    }

    function getNumberbyUIDorHashkey($uidorhashkey, $newdata = false)
    {
        return $this->getValueByUIDorHashkey($uidorhashkey, 'mnumber', $newdata);
    }
    function getParentUIDbyUserUID($useruid, $newdata = false)
    {
        return $this->GetValue('uid', $useruid, 'parentuid', $exact = true, false, $newdata);
    }
    function getParentUIDbyUserHashkey($useridorhashkey, $newdata = false)
    {
        return $this->getValueByUIDorHashkey($useridorhashkey, 'parentuid', $newdata);
    }
    function filterbyAcct_Type($acct_type, $newdata = false)
    {
        if (!$acct_type) {
            return false;
        }
        return $this->List('acct_type', $acct_type, $exact = true, true, $newdata);
    }
    public function searchUsersByParentUid($parentUid)
    {
        $this->parentidresults = [];
        $this->searchUsersByParentUidRecursive($this->data, $parentUid, $this->parentidresults);
        return $this->parentidresults;
    }

    private function searchUsersByParentUidRecursive($array, $parentUid, &$result)
    {
        foreach ($array as $user) {
            if ($user['parentuid'] == $parentUid) {
                $result[] = $user;
                $this->searchUsersByParentUidRecursive($array, $user['uid'], $result);
            }
        }
    }
}

function searchUsersByParentUid($array, $parentUid, &$result)
{
    foreach ($array as $user) {
        if ($user['parentuid'] == $parentUid) {
            $result[] = $user;
            searchUsersByParentUid($array, $user['uid'], $result);
        }
    }
}

function ListChildUsersofParent($parentuid, $fieldstoselect = '', $addself = false)
{
    $users = new UserQuickMultipleSearch();
    $user_list = $users->data;
    $list = [];
    //fix parent uid looping by itself when there is useruid and parentuid is the same
    searchUsersByParentUid($user_list, $parentuid, $list);
    if ($addself) {
        $list[] = $users->getDetailsbyUIDorHashkey($parentuid);
    }
    if ($fieldstoselect and is_array($fieldstoselect)) {
        $list = filterArrayColumns($list, $fieldstoselect);
    }

    return $list;
}

function isTargetUserAChildofParent($target_useruidorhash, $parentuid = '', $fieldstoselect = '', $addself = false)
{
    if (!$target_useruidorhash) {
        return false;
    }
    if (!$parentuid) {
        $parentuid = CurrentUserUID();
    }
    $children = ListChildUsersofParent($parentuid, $fieldstoselect = '', $addself = false);
    if (is_numeric($target_useruidorhash)) {
        $columnsearch = 'uid';
    } else {
        $columnsearch = 'hashkey';
    }
    $ischild = sqlarray_2dfilter($children, $columnsearch, $target_useruidorhash, true);
    if (!$ischild) {
        return false;
    } else {
        return $ischild[0] ?? false;
    }
}



function isTargetUserModificationAllowed($currentuseruidorhash, $targetuseruidorhash, $conditiontrue = true)
{ // to edit
    if (!$conditiontrue) {
        return false;
    }
    $currentuser = GetUserDatabyUID($currentuseruidorhash);
    $targetuser = GetUserDatabyUID($targetuseruidorhash);
    $currentuserUID = $currentuser['uid'] ?? false;
    $targetuserUID = $targetuser['uid'] ?? false;


    if (!$currentuser or !$targetuser) {
        return false;
    }
    $currentuser_type = $currentuser['acct_type'] ?? false;
    $targetuser_type = $targetuser['acct_type'] ?? false;

    if (!$currentuser_type or !$targetuser_type) {
        return false;
    }

    $CurrentUserisUltimate = $currentuser_type === 'ult';
    $CurrentUserisSuperOperator = $currentuser_type === 'super operator';
    $CurrentUserisOperator = $currentuser_type === 'operator';
    $CurrentUserisCoordinator = $currentuser_type === 'coordinator';
    $CurrentUserisUsher = $currentuser_type === 'usher';
    $CurrentUserisNormalUser = $currentuser_type === 'user';
    $CurrentUserisDisabler = $currentuser_type === 'disabler';
    $CurrentUserisViewer = $currentuser_type === 'viewer';

    $TargetUserisUltimate = $targetuser_type === 'ult';
    $TargetUserisSuperOperator = $targetuser_type === 'super operator';
    $TargetUserisOperator = $targetuser_type === 'operator';
    $TargetUserisCoordinator = $targetuser_type === 'coordinator';
    $TargetUserisUsher = $targetuser_type === 'usher';
    $TargetUserisNormalUser = $targetuser_type === 'user';
    $TargetUserisDisabler = $targetuser_type === 'disabler';
    $TargetUserisViewer = $targetuser_type === 'viewer';



    $CurrentUserlevel = ($CurrentUserisUltimate) ? 20 : (($CurrentUserisSuperOperator) ? 19 : (($CurrentUserisOperator) ? 18 : (($CurrentUserisCoordinator) ? 17 : (($CurrentUserisUsher) ? 16 : (($CurrentUserisDisabler) ? 15 : (($CurrentUserisNormalUser) ? 14 : (($CurrentUserisViewer) ? 13 : false)))))));

    $TargetUserlevel = ($TargetUserisUltimate) ? 20 : (($TargetUserisSuperOperator) ? 19 : (($TargetUserisOperator) ? 18 : (($TargetUserisCoordinator) ? 17 : (($TargetUserisUsher) ? 16 : (($TargetUserisDisabler) ? 15 : (($TargetUserisNormalUser) ? 14 : (($TargetUserisViewer) ? 13 : false)))))));





    $children = ListChildUsersofParent($currentuserUID, ['uid']);
    $children = array_column($children, 'uid');
    sort($children);
    $isIndirectParentofTargetUser = in_array($targetuserUID, $children);

    if ($CurrentUserisViewer) {
        return false;
    }
    if ($CurrentUserisUltimate) {
        return true;
    }
    if ($CurrentUserisSuperOperator and !$TargetUserisUltimate) {
        return true;
    }
    if ($CurrentUserlevel > $TargetUserlevel and $isIndirectParentofTargetUser) {
        return true;
    }


    return false;
}



require_once('EXT/DBEXT/USERINFODB.php');
require_once('EXT/DBEXT/FILESDB.php');
require_once('EXT/DBEXT/MARKETDB.php');


