<?php
use \Firebase\JWT\JWT;
use \Firebase\JWT\ExpiredException;
use \Firebase\JWT\SignatureInvalidException;
class apiHandler {
    public $headers;
    public $hosturl;
    public $getrequest;
    public $lang;
    public $trans;
    public $openkey;
    public $useerpids;
    public $accessToken;
    public $optSend;
    // it will run in everytime with
    // default required
    public function __construct() {

        include_once 'apiConfig.php';
        require_once (__DIR__ . "/../_helper/_helper.php");
        require_once (__DIR__ ."/../_helper/client.php");
        
        $this->headers = getallheaders();
        $this->hosturl = Host_URL;
        $this->optSend = 2 ;
        $this->lang = isset($this->headers["Lang"]) ? $this->headers["Lang"] : 'ar';
        $this->trans = require_once(__DIR__ ."/../_lang/".$this->lang.".php");
        $this->openkey = isset($this->headers["Openkey"]) ? $this->headers["Openkey"] : '';
        $this->accessToken  = isset($this->headers["Accesstoken"]) ? $this->headers["Accesstoken"] : '';
        if (isset($_REQUEST['useERPIDs']) && $_REQUEST['useERPIDs'] == 1) {
            $this->useerpids = 1;
        } else { 
            $this->useerpids = (int) isset($this->headers["useERPIDs"]) ? $this->headers["useERPIDs"] : 0;
        }
        $_POST['useERPIDs'] = $this->useerpids;  //default
        error_reporting(E_ERROR); //E_ALL
        ini_set('display_errors', 1);
        ini_set('memory_limit', '-1');

        $timezone = R::getCell('SELECT timezone from programsettings where programsettingsid = 1');
        date_default_timezone_set($timezone);

         header('Content-Type: application/json; charset=utf-8');
        header('X-Content-Type-Options: nosniff'); // منع تخمين نوع المحتوى
        header('X-Frame-Options: SAMEORIGIN'); // منع الـ iframe من دومين خارجي
        header('X-XSS-Protection: 1; mode=block'); // حماية XSS
        header('Referrer-Policy: no-referrer-when-downgrade');
        header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload');
        
        // إعدادات CORS
        if (isset($_SERVER['HTTP_ORIGIN'])) {
            header("Access-Control-Allow-Origin: *");
            header('Access-Control-Allow-Credentials: true');
            header('Access-Control-Max-Age: 86400');
        }
        
        // معالجة OPTIONS
        if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
            if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
                header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
            }
            if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
                header("Access-Control-Allow-Headers: Content-Type, Authorization, X-CSRF-Token, X-Requested-With");
            }
            http_response_code(204);
            exit(0);
        }
        
        // 🌐 تحديد نوع الطلب
        $contentType = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : '';
        
        if ($_SERVER['REQUEST_METHOD'] === 'GET') {
            $this->getrequest = (object) $_GET;
        
        } else {
            // ✅ إضافة بسيطة لمعالجة الملفات دون التأثير على الكود الأصلي
            if (stripos($contentType, 'multipart/form-data') !== false && !empty($_FILES)) {
                // الطلب من نوع رفع ملفات
              $this->getrequest = (object) array_merge($_POST, $_FILES);

        
            } else {
                // الكود القديم كما هو بالضبط
                $post_data = file_get_contents("php://input");
        
                if (!empty($post_data)) {
                    $this->getrequest = json_decode($post_data);
                } elseif (!empty($_POST)) {
                    $this->getrequest = (object) $_POST;
                } else {
                    $this->getrequest = new stdClass();
                }
            }
        }
    }


    protected function respond($code = 200, $success = true, $message = '', $exception = '', $errors = [], $data = [], $headers = 1)
    {
        http_response_code($code);
        if (count($errors) == 1) {
            $errors = [$errors];
        }
      
        $response = [
            'code'      => $code,
            'success'   => $success,
            'message'   => $message,
            'exception' => $exception,
            'errors'    => $errors,
        ];

        // دالة لتحويل القيم حسب النوع
        $normalize = function ($value) {
            if (is_numeric($value)) {
                // لو القيمة رقمية وفيها صفر بادئ أو طويلة (زي رقم موبايل) → خليه سترنج
                if ((strlen($value) > 1 && $value[0] === '0') || strlen($value) > 15) {
                    return (string)$value;
                }
                // غير كده رجعها رقم (int أو float)
                return (strpos($value, '.') !== false) ? (float)$value : (int)$value;
            }
            return $value;
        };

        // عمل نسخة قابلة للتعديل
        $data = json_decode(json_encode($data), true);

        // معالجة كل القيم (recursive)
        if (is_array($data)) {
            array_walk_recursive($data, function (&$v) use ($normalize) {
                $v = $normalize($v);
            });

        } else {
            $data = array(); // لو null أو غير مصفوفة خليه array فاضية
        }

       

        

        if ($headers  == 0) {
              $response['data'] = $data;
              echo json_encode($response,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
            );
        }else{
            echo json_encode(['header' => $response, 'body' => $data],JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); 
        }
       
        exit;
    }






    protected function checkERPAccess() {
        if ($this->useerpids == 1 || $this->openkey == getenv('erpToken')) {
            if ($this->openkey !== getenv('erpToken')) {
                $this->respond(405,false,$this->trans['httpStatusCodes']['405'], null, []);
            }
        } else {
             $this->respond(401,false,$this->trans['httpStatusCodes']['401'], null, []);
        }
    }



    /**
     * تنظيف من SQL Injection و XSS
     */
    protected function sanitizeValue($value, $type = 'string')
    {
        if (!is_string($value) || $type !== 'string') {
            return $value;
        }

        $value = strip_tags($value);
        $value = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
        $value = trim($value);

        // أنماط حقن SQL
        $sqlInjectionPatterns = array(
            '/\b(select|insert|update|delete|drop|alter|create|truncate|replace|rename)\b\s+/i',
            '/\b(union|exec|execute|declare|cast|char|convert|sleep|benchmark)\b\s+/i',
            '/(--|#|\/\*|\*\/|;|@@|@)/',
            '/\b(or|and)\b\s+(?=\d+\s*[=<>]|["\']?\w+["\']?\s*[=<>])/i',
            '/(["\']?)\s*or\s*\1?1\1?\s*=\s*\1?1\1?/i'
        );

        // أنماط XSS
        $xssPatterns = array(
            '/<script\b[^>]*>(.*?)<\/script>/is',
            '/javascript:/i',
            '/on\w+="[^"]*"/i',
            '/<iframe\b[^>]*>(.*?)<\/iframe>/is',
            '/<img[^>]+src=["\']?javascript:/i',
        );

        foreach ($sqlInjectionPatterns as $pattern) {
            $value = preg_replace($pattern, '', $value);
        }

        foreach ($xssPatterns as $pattern) {
            $value = preg_replace($pattern, '', $value);
        }

        return $value;
    }

    /**
     * تنظيف + تحقق
     * 
     * @param array $inputs البيانات الخام
     * @param array $fields مصفوفة تحتوي على القواعد والأنواع بالشكل:
     *   [
     *     'fieldName' => [
     *         'rules' => 'required|integer|min:1',
     *         'type'  => 'integer'
     *     ],
     *     ...
     *   ]
     * @return array تحتوي على 'cleaned' و 'errors'
     */

    public function sanitizeAndValidate(array $inputs, array $fields = array())
    {
        $cleaned = array();
        $errors  = array();
        $fieldsTrans = isset($this->trans['fields']) ? $this->trans['fields'] : [];
        $messagesTrans = isset($this->trans['messages']['validate']) ? $this->trans['messages']['validate'] : [];

        foreach ($inputs as $key => $value) {
            $type = isset($fields[$key]['type']) ? $fields[$key]['type'] : 'text';
            $rules = isset($fields[$key]['rules']) ? explode('|', $fields[$key]['rules']) : [];

            
            if ($field['type'] === 'file') {

                if (!isset($_FILES[$key])) {
                    if (in_array('required', $rules)) {
                        $errors[$key][] = "الملف «{$key}»: " . $messagesTrans['required'];
                    }
                    continue;
                }
        
                // تحويل الملفات لمصفوفة واحدة للتعامل مع كل ملف على حدة
                $files = [];
                if (is_array($_FILES[$key]['name'])) {
                    foreach ($_FILES[$key]['name'] as $i => $name) {
                        $files[] = [
                            'name' => $name,
                            'tmp_name' => $_FILES[$key]['tmp_name'][$i],
                            'size' => $_FILES[$key]['size'][$i],
                            'error' => $_FILES[$key]['error'][$i]
                        ];
                    }
                } else {
                    $files[] = $_FILES[$key];
                }
        
                foreach ($files as $file) {
                    if ($file['error'] !== UPLOAD_ERR_OK) {
                        if (in_array('required', $rules)) {
                            $errors[$key][] = "الملف «{$file['name']}»: " . $messagesTrans['required'];
                        }
                        continue;
                    }
        
                    $fileName = $file['name'];
                    $fileTmp  = $file['tmp_name'];
                    $fileSize = $file['size'];
                    $fileExt  = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
        
                    if (!is_uploaded_file($fileTmp)) {
                        $errors[$key][] = "الملف «{$fileName}»: فشل التحقق من مصدر الملف.";
                        continue;
                    }
        
                    foreach ($rules as $rule) {
                        if (strpos($rule, 'mimes:') === 0) {
                            $allowed = explode(',', substr($rule, 6));
                            if (!in_array($fileExt, $allowed)) {
                                $errors[$key][] = "الملف «{$fileName}»: " . $messagesTrans['invalidFileType'];
                            }
                        }
                        if (strpos($rule, 'max_file:') === 0) {
                            $maxKb = (int)substr($rule, 9);
                            if ($fileSize > ($maxKb * 1024)) {
                                $errors[$key][] = "الملف «{$fileName}»: " . $messagesTrans['fileTooLarge'];
                            }
                        }
                    }
                }
            }

          
            // تنظيف
            if (is_array($value)) {
                $value = array_map(function ($item) use ($type) {
                    return $this->sanitizeValue($item, $type);
                }, $value);

                // إزالة القيم الفارغة والمكررة
                $value = array_values(array_unique(array_filter($value, function ($item) {
                    return $item !== null && $item !== '';
                })));
            } else { 
                $value = $this->sanitizeValue($value, $type);
            }

            $cleaned[$key] = $value;

            // تحقق
            if (isset($fields[$key]['rules'])) {
                $val = $value;
                $rulesArr = explode('|', $fields[$key]['rules']);

                foreach ($rulesArr as $rule) {
                    $fieldName = isset($fieldsTrans[$key]) ? $fieldsTrans[$key] : $key;

                    if ($rule === 'required' && (is_null($val) || trim((string)$val) === '')) {
                        $msg = isset($messagesTrans['required']) ? $messagesTrans['required'] : 'required';
                        $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                    }

                    if ($val === null || $val === '') continue;

                    if ($rule === 'string') {
                        if (!is_string($val)) {
                            $msg = isset($messagesTrans['notString']) ? $messagesTrans['notString'] : 'not_string';
                            $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                        } else {
                            $val = trim(filter_var($val, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES));
                            $cleaned[$key] = $val;
                        }
                    }

                    if ($rule === 'email' && !filter_var($val, FILTER_VALIDATE_EMAIL)) {
                        $msg = isset($messagesTrans['invalidEmail']) ? $messagesTrans['invalidEmail'] : 'invalid_email';
                        $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                    }

                    if ($rule === 'numeric' && !is_numeric($val)) {
                        $msg = isset($messagesTrans['notNumeric']) ? $messagesTrans['notNumeric'] : 'not_numeric';
                        $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                    }

                    if ($rule === 'integer' && filter_var($val, FILTER_VALIDATE_INT) === false) {
                        $msg = isset($messagesTrans['notInteger']) ? $messagesTrans['notInteger'] : 'not_integer';
                        $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                    }

                    if ($rule === 'float' && filter_var($val, FILTER_VALIDATE_FLOAT) === false) {
                        $msg = isset($messagesTrans['notFloat']) ? $messagesTrans['notFloat'] : 'not_float';
                        $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                    }

                    if (strpos($rule, 'min:') === 0) {
                        $min = (int)substr($rule, 4);
                        if (is_numeric($val)) {
                            if ($val < $min) {
                                $msg = isset($messagesTrans['tooSmall']) ? $messagesTrans['tooSmall'] : 'too_small';
                                $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                            }
                        } else {
                            if (mb_strlen($val) < $min) {
                                $msg = isset($messagesTrans['tooShort']) ? $messagesTrans['tooShort'] : 'too_short';
                                $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                            }
                        }
                    }

                    if (strpos($rule, 'max:') === 0) {
                        $max = (int)substr($rule, 4);
                        if (mb_strlen((string)$val) > $max) {
                            $msg = isset($messagesTrans['tooLong']) ? $messagesTrans['tooLong'] : 'too_long';
                            $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                        }
                    }

                    if (strpos($rule, 'between:') === 0) {
                        $rangeParts = array_map('intval', explode(',', substr($rule, 8)));
                        $min = isset($rangeParts[0]) ? $rangeParts[0] : 0;
                        $max = isset($rangeParts[1]) ? $rangeParts[1] : 0;

                        if (is_numeric($val)) {
                            if ($val < $min || $val > $max) {
                                $msg = isset($messagesTrans['outOfRange']) ? $messagesTrans['outOfRange'] : 'out_of_range';
                                $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                            }
                        } else {
                            $len = mb_strlen($val);
                            if ($len < $min || $len > $max) {
                                $msg = isset($messagesTrans['lengthOutOfRange']) ? $messagesTrans['lengthOutOfRange'] : 'length_out_of_range';
                                $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                            }
                        }
                    }

                    if (strpos($rule, 'in:') === 0) {
                        $allowed = explode(',', substr($rule, 3));
                        if (!in_array($val, $allowed)) {
                            $msg = isset($messagesTrans['invalidValue']) ? $messagesTrans['invalidValue'] : 'invalid_value';
                            $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                        }
                    }

                    if (strpos($rule, 'regex:') === 0) {
                        $pattern = substr($rule, 6);
                        if (!preg_match($pattern, $val)) {
                            $msg = isset($messagesTrans['invalidFormat']) ? $messagesTrans['invalidFormat'] : 'invalid_format';
                            $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                        }
                    }

                    if ($rule === 'date' && (strtotime($val) === false)) {
                        $msg = isset($messagesTrans['invalidDate']) ? $messagesTrans['invalidDate'] : 'invalid_date';
                        $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                    }

                    if ($rule === 'url' && !filter_var($val, FILTER_VALIDATE_URL)) {
                        $msg = isset($messagesTrans['invalidUrl']) ? $messagesTrans['invalidUrl'] : 'invalid_url';
                        $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                    }

                    if ($rule === 'boolean' && !in_array($val, [true, false, 0, 1, '0', '1'], true)) {
                        $msg = isset($messagesTrans['invalidBoolean']) ? $messagesTrans['invalidBoolean'] : 'invalid_boolean';
                        $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                    }

                    if (strpos($rule, 'password:') === 0) {
                        $pattern = substr($rule, 9);
                        if (!preg_match($pattern, $val)) {
                            $msg = isset($messagesTrans['invalidPasswordRegex']) ? $messagesTrans['invalidPasswordRegex'] : 'invalid_password_format';
                            $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                        }
                    }

                    if ($rule === 'confirmed') {
                        $confirmationKey = $key . '_confirmation';
                        if (!isset($inputs[$confirmationKey]) || $val !== $inputs[$confirmationKey]) {
                            $msg = isset($messagesTrans['confirmationFailed']) ? $messagesTrans['confirmationFailed'] : 'confirmation_failed';
                            $errors[$key][] = $this->trans['field'] . " «{$fieldName}»: {$msg}";
                        }
                    }
                }
            }
        }

        return array(
            'cleaned' => $cleaned,
            'errors'  => $errors
        );
    }


    /**
     * تنظيف و تحقق لحقول محددة داخل مصفوفة
     * 
     * @param array $request بيانات الطلب الخام
     * @param array $allowedFields قائمة الحقول المسموح بها
     * @param array $fields مصفوفة القواعد والأنواع لكل حقل بالشكل:
     * [
     *   'fieldName' => [
     *       'rules' => 'required|integer|min:1',
     *       'type'  => 'integer'
     *    ],
     *    ...
     * ]
     * @return array بيانات الطلب مع الحقول النظيفة و 'validation_errors' في حالة وجود أخطاء
     */
    public function cleanRequestInputs(array $request, array $fields = array(), array $allowedFields = array())
    {
        $inputs = array();

        foreach ($allowedFields as $field) {
            $inputs[$field] = isset($request[$field]) ? $request[$field] : '';
        }

        $result = $this->sanitizeAndValidate($inputs, $fields);

        foreach ($result['cleaned'] as $key => $value) {
            $request[$key] = $value;
        }

        $request['validation_errors'] = $result['errors'];

        return $request;
    }


    public function createJwt($tokenPayload = [])
    {
        // $tokenPayload['expires_token'] = date("Y-m-d H:i:s", strtotime("+ 1 day"));
        $tokenPayload['expires_token'] = date("Y-m-d H:i:s", strtotime("+1 day +1 hour"));
        $token = JWT::encode($tokenPayload, getenv('erpToken'));
        $dataArr['expires_token'] = $tokenPayload['expires_token'];
        $dataArr['token'] = $token;
        return $dataArr;
    }


    public function decodeJwt($token)
    {
       
        return  JWT::decode($token, getenv('erpToken'), array('HS256'));
    }


    protected function checkTokenClient() {
        try {

            if (!$this->accessToken) {
                $this->respond(451,false,$this->trans['httpStatusCodes']['401'], null, []);
            }
             
            $token = $this->decodeJwt($this->accessToken);
            if(!$token->expires_token || $token->expires_token < date("Y-m-d H:i:s", strtotime("+1 hour")) ){
                $this->respond(451,false,$this->trans['httpStatusCodes']['403'], null, []);
            }
            
        
            $client = R::load('client',$token->id);
            if(!$client){
                $this->respond(404,false,$this->trans['httpStatusCodes']['404'], null, []);
            }
            return $client;
        } catch (Exception $exception) {
            $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
        }  
    }


    




    public function sendEmailMessage($subject, $message, $email, $data = [], $res = true)
    {
    //   try {
            // $onlinestoremainsetting = R::load('onlinestoremainsetting', 1);
            // $templatePath = __DIR__ . '/../_html/sendemailotp.html';
            // $pageHtml = file_get_contents($templatePath);
            // $body = str_replace('{{ reset_link }}', $message, $pageHtml);
            // include_once(__DIR__ . '/../_library/phpMailer/PHPMailer.php');
            // $mail = new PHPMailer(true);
            // $mail->isSMTP();
            // $mail->Host       = $onlinestoremainsetting->mail_host;
            // $mail->SMTPAuth   = true;
            // $mail->Username   = $onlinestoremainsetting->mail_username;
            // $mail->Password   = $onlinestoremainsetting->mail_password;
            // $mail->SMTPSecure = $onlinestoremainsetting->mail_encryption;
            // $mail->Port       = $onlinestoremainsetting->mail_port;
            // $mail->setFrom($onlinestoremainsetting->mail_fromaddress, 'Your App Erp');
            // $mail->addAddress($email); 
            // $mail->isHTML(true); 
            // $mail->Subject = $subject;
            // $mail->Body    = $body;
            // if ($mail->send()) {
                if($res){
                    $this->respond(200,true,$this->trans['httpStatusCodes']['200'], null,[], $data);
                }
        //     } else {
        //         $this->respond(400,true,$this->trans['messages']['failedSendMail'], $mail->ErrorInfo,[],$data);
        //     }
        // } catch (Exception $exception) {
        //     $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), [], $data);

        // }
    }

    public function sendMobileMessage($subject, $message, $phoneNumber, $data = [], $res = true)
    {
        // try {
            // $username = "YOUR_USERNAME";
            // $password = "YOUR_PASSWORD";
            // $sender   = "YOUR_SENDER_ID";

            // $url = "https://smsmisr.com/api/webapi/?username=$username&password=$password&language=1&sender=$sender&mobile=$phoneNumber&message=" . urlencode($message);

            // $ch = curl_init();
            // curl_setopt($ch, CURLOPT_URL, $url);
            // curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            // $response = curl_exec($ch);
            // curl_close($ch);

            // $responseData = json_decode($response, true);

            // if ($responseData && isset($responseData['code']) && $responseData['code'] == 1901) {
        if($res){
                $this->respond(200, true,$this->trans['httpStatusCodes']['200'], null, [], $data);
            }
        //     } else {
        //         $this->respond(400,true,$this->trans['messages']['failedSendMail'], $mail->ErrorInfo,[],$data);
        //     }
        // } catch (Exception $exception) {
        //     $this->respond(500,false,$this->trans['httpStatusCodes']['500'], $exception->getMessage(), [], $data);

        // }
    }


    //by fatma
    public function liveBackupComment($comment)
    {
        $myfile = fopen("../backup/" . date("Y-m-d") . ".txt", "a+") or die("Unable to open file!");
        $toWrite = "\r\n-- ----------------------------------------------------------------------------------------------------\r\n";
        $toWrite .= $comment;
        $toWrite .= "\r\n-- ----------------------------------------------------------------------------------------------------\r\n\r\n";
        fwrite($myfile, $toWrite);
    }

    protected function checkErpAccessOrTokenClient()
    {
        // First check if openkey is provided - use ERP access
        if ($this->openkey) {
            if ($this->useerpids == 1 || $this->openkey == getenv('erpToken')) {
                // ERP access is valid, return null (no client data needed for ERP)
                return null;
            } else {
                $this->respond(401, false, $this->trans['httpStatusCodes']['401'], null, []);
            }
        } else {
            // If no openkey, try client token access
            try {
                if (!$this->usertoken) {
                    $this->respond(401, false, $this->trans['httpStatusCodes']['401'], null, []);
                }
                $token = $this->decodeJwt($this->usertoken);
                if (!$token->expires_token || $token->expires_token < date("Y-m-d H:i:s")) {
                    $this->respond(403, false, $this->trans['httpStatusCodes']['403'], null, []);
                }
                $client = R::load('client', $token->id);
                if (!$client) {
                    $this->respond(404, false, $this->trans['httpStatusCodes']['404'], null, []);
                }
                return $client;
            } catch (Exception $exception) {
                $this->respond(500, false, $this->trans['httpStatusCodes']['500'], $exception->getMessage(), []);
            }
        }
    }

    public function customArrayIndexOne($array, $colName = 'id') {
        $newArr = array();
        foreach ($array as $val) {
            $newArr[$val[$colName]] = $val;
        }
        return $newArr;
    }
    
    public function customArrayIndexMany($array, $colName = 'id') {
        $newArr = array();
        foreach ($array as $val) {
            if (!isset($newArr[$val[$colName]])) {
                $newArr[$val[$colName]] = array();
            }
            $newArr[$val[$colName]][] = $val;
        }
        return $newArr;
    }
    
    public function customArrayManyIndexOne($array, $colName = array()) {
        $newArr = array();
        if (count($colName) > 0) {
            foreach ($array as $val) {
                $builtUpIndex = '';
                foreach ($colName as $col) {
                    $builtUpIndex .= ',' . $val[$col];
                }
                $builtUpIndex = trim($builtUpIndex, ',');
                $newArr[$builtUpIndex] = $val;
            }
        }
        return $newArr;
    }
    
    public function customArrayManyIndexMany($array, $colName = array()) {
        $newArr = array();
        if (count($colName) > 0) {
            foreach ($array as $val) {
                $builtUpIndex = '';
                foreach ($colName as $col) {
                    $builtUpIndex .= ',' . $val[$col];
                }
                $builtUpIndex = trim($builtUpIndex, ',');
                $newArr[$builtUpIndex][] = $val;
            }
        }
        return $newArr;
    }

    public function __destruct() {
        R::close(); // close db from red bean
    }


}
