<?php


namespace Mnv\Core\Utilities;


use Mnv\Core\Helpers\Encoding;

class CUtil
{
    protected static $alreadyDecodedRequest = false;

    public static function addslashes($s)
    {
        static $aSearch = array("\\", "\"", "'");
        static $aReplace = array("\\\\", '\\"', "\\'");
        return str_replace($aSearch, $aReplace, $s);
    }

    public static function closetags($html)
    {
        preg_match_all("#<([a-z0-9]+)([^>]*)(?<!/)>#i".BX_UTF_PCRE_MODIFIER, $html, $result);
        $openedtags = $result[1];

        preg_match_all("#</([a-z0-9]+)>#i".BX_UTF_PCRE_MODIFIER, $html, $result);
        $closedtags = $result[1];
        $len_opened = count($openedtags);

        if(count($closedtags) == $len_opened)
            return $html;

        $openedtags = array_reverse($openedtags);

        for($i = 0; $i < $len_opened; $i++) {
            if (!in_array($openedtags[$i], $closedtags))
                $html .= '</'.$openedtags[$i].'>';
            else
                unset($closedtags[array_search($openedtags[$i], $closedtags)]);
        }

        return $html;
    }

    public static function JSEscape($s)
    {
        static $aSearch = array("\xe2\x80\xa9", "\\", "'", "\"", "\r\n", "\r", "\n", "\xe2\x80\xa8", "*/", "</");
        static $aReplace = array(" ", "\\\\", "\\'", '\\"', "\n", "\n", "\\n", "\\n", "*\\/", "<\\/");
        $val = str_replace($aSearch, $aReplace, $s);
        return $val;
    }

    public static function JSUrlEscape($s)
    {
        static $aSearch = array("%27", "%5C", "%0A", "%0D", "%", "&#039;", "&#39;", "&#x27;", "&apos;");
        static $aReplace = array("\\'", "\\\\", "\\n", "\\r", "%25", "\\'", "\\'", "\\'", "\\'");
        return str_replace($aSearch, $aReplace, $s);
    }

    public static function PhpToJSObject($arData, $bWS = false, $bSkipTilda = false, $bExtType = false)
    {
        static $use_bx_encode = null;
        if (!isset($use_bx_encode))
            $use_bx_encode = function_exists('bx_js_encode');
        if ($use_bx_encode)
            return js_encode($arData, $bWS, $bSkipTilda, $bExtType);

        switch(gettype($arData))
        {
            case "string":
                if(preg_match("#['\"\\n\\r<\\\\\x80]#", $arData))
                    return "'".CUtil::JSEscape($arData)."'";
                else
                    return "'".$arData."'";
            case "array":
                $i = -1;
                $j = -1;
                foreach($arData as $j => $temp) {
                    $i++;
                    if ($j !== $i) break;
                }

                if($j === $i) {
                    $res = '[';
                    $first = true;
                    foreach($arData as $key => $value) {
                        if($first)
                            $first = false;
                        else
                            $res .= ',';

                        switch(gettype($value)) {
                            case "string":
                                if(preg_match("#['\"\\n\\r<\\\\\x80]#", $value))
                                    $res .= "'".CUtil::JSEscape($value)."'";
                                else
                                    $res .= "'".$value."'";
                                break;
                            case "array":
                                $res .= CUtil::PhpToJSObject($value, $bWS, $bSkipTilda, $bExtType);
                                break;
                            case "boolean":
                                if($value === true)
                                    $res .= 'true';
                                else
                                    $res .= 'false';
                                break;
                            case "integer":
                                if ($bExtType)
                                    $res .= $value;
                                else
                                    $res .= "'".$value."'";
                                break;
                            case "double":
                                if ($bExtType)
                                    $res .= is_finite($value) ? $value : "Infinity";
                                else
                                    $res .= "'".$value."'";
                                break;
                            default:
                                if(preg_match("#['\"\\n\\r<\\\\\x80]#", $value))
                                    $res .= "'".CUtil::JSEscape($value)."'";
                                else
                                    $res .= "'".$value."'";
                                break;
                        }
                    }
                    $res .= ']';
                    return $res;
                }

                $sWS = ','.($bWS ? "\n" : '');
                $res = ($bWS ? "\n" : '').'{';
                $first = true;
                foreach($arData as $key => $value) {
                    if ($bSkipTilda && mb_substr($key, 0, 1) == '~') continue;

                    if($first)
                        $first = false;
                    else
                        $res .= $sWS;

                    if(preg_match("#['\"\\n\\r<\\\\\x80]#", $key))
                        $res .= "'".CUtil::JSEscape($key)."':";
                    else
                        $res .= "'".$key."':";

                    switch(gettype($value)) {
                        case "string":
                            if(preg_match("#['\"\\n\\r<\\\\\x80]#", $value))
                                $res .= "'".CUtil::JSEscape($value)."'";
                            else
                                $res .= "'".$value."'";
                            break;
                        case "array":
                            $res .= CUtil::PhpToJSObject($value, $bWS, $bSkipTilda, $bExtType);
                            break;
                        case "boolean":
                            if($value === true)
                                $res .= 'true';
                            else
                                $res .= 'false';
                            break;
                        case "integer":
                            if ($bExtType)
                                $res .= $value;
                            else
                                $res .= "'".$value."'";
                            break;
                        case "double":
                            if ($bExtType)
                                $res .= is_finite($value) ? $value : "Infinity";
                            else
                                $res .= "'".$value."'";
                            break;
                        default:
                            if(preg_match("#['\"\\n\\r<\\\\\x80]#", $value))
                                $res .= "'".CUtil::JSEscape($value)."'";
                            else
                                $res .= "'".$value."'";
                            break;
                    }
                }
                $res .= ($bWS ? "\n" : '').'}';
                return $res;
            case "boolean":
                if($arData === true)
                    return 'true';
                else
                    return 'false';
            case "integer":
                if ($bExtType)
                    return $arData;
                else
                    return "'".$arData."'";
            case "double":
                if ($bExtType)
                    return is_finite($arData) ? $arData : "Infinity";
                else
                    return "'".$arData."'";
            default:
                if(preg_match("#['\"\\n\\r<\\\\\x80]#", $arData))
                    return "'".CUtil::JSEscape($arData)."'";
                else
                    return "'".$arData."'";
        }
    }


    public static function DecodeUtf16($ch)
    {
        $res = chr(hexdec($ch[2])).chr(hexdec($ch[1]));
        return Encoding::convertEncoding($res, "UTF-16", LANG_CHARSET);
    }


    public static function DetectUTF8($string)
    {
        //http://mail.nl.linux.org/linux-utf8/1999-09/msg00110.html

        if(preg_match_all("/(?:%)([0-9A-F]{2})/i", $string, $match)) {
            $string = pack("H*", strtr(implode('', $match[1]), 'abcdef', 'ABCDEF'));
        }

        //valid UTF-8 octet sequences
        //0xxxxxxx
        //110xxxxx 10xxxxxx
        //1110xxxx 10xxxxxx 10xxxxxx
        //11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

        $prevBits8and7 = 0;
        $is_utf = 0;
        foreach(unpack("C*", $string) as $byte)
        {
            $hiBits8and7 = $byte & 0xC0;
            if ($hiBits8and7 == 0x80) {
                if ($prevBits8and7 == 0xC0)
                    $is_utf++;
                elseif (($prevBits8and7 & 0x80) == 0x00)
                    $is_utf--;
            } elseif ($prevBits8and7 == 0xC0) {
                $is_utf--;
            }
            $prevBits8and7 = $hiBits8and7;
        }
        return ($is_utf > 0);
    }



    public static function GetAdditionalFileURL($file, $bSkipCheck=false)
    {
        $filePath = $_SERVER['DOCUMENT_ROOT'].$file;
        if($bSkipCheck || file_exists($filePath))
            return $file.'?'.filemtime($filePath).filesize($filePath);
        else
            return $file;
    }

    /**
     * @deprecated Use strlen()
     * @param $buf
     * @return int
     */
    public static function BinStrlen($buf)
    {
        return strlen($buf);
    }

    /**
     * @deprecated Use substr()
     * @param $buf
     * @param $start
     * @param array $args
     * @return string
     */
    public static function BinSubstr($buf, $start, ...$args)
    {
        return substr($buf, $start, ...$args);
    }

    /**
     * @deprecated Use strpos()
     * @param $haystack
     * @param $needle
     * @param int $offset
     * @return false|int
     */
    public static function BinStrpos($haystack, $needle, $offset = 0)
    {
        return strpos($haystack, $needle, $offset);
    }

    /**
     * Convert shorthand notation to integer equivalent
     * @param string $str
     * @return int
     *
     */
    public static function Unformat($str)
    {
        $str = mb_strtolower($str);
        $res = intval($str);
        $suffix = mb_substr($str, -1);
        if($suffix == "k")
            $res *= 1024;
        elseif($suffix == "m")
            $res *= 1048576;
        elseif($suffix == "g")
            $res *= 1048576*1024;
        elseif($suffix == "b")
            $res = self::Unformat(mb_substr($str, 0, -1));
        return $res;
    }

    /**
     * Adjust php pcre.backtrack_limit
     * @param int $val
     * @return void
     *
     */
    public static function AdjustPcreBacktrackLimit($val)
    {
        $val = intval($val);
        if($val <=0 )
            return;

        $pcreBacktrackLimit = self::Unformat(ini_get("pcre.backtrack_limit"));
        if($pcreBacktrackLimit < $val)
            @ini_set("pcre.backtrack_limit", $val);
    }

}