<?php
/**
 * @author Ulrich Hecht <ulrich.hecht@hecht-software.de>
 * @date 10/09/2016
 */

namespace AppBundle;


use AppBundle\Entity\BreadcrumbEntry;
use AppBundle\Entity\Page;

class Util
{
    /**
     * @param Page $page
     *
     * @return BreadcrumbEntry[]|array
     */
    public static function createBreadcrumb(Page $page)
    {
        $ret = [];
        do {
            $ret[] = new BreadcrumbEntry($page->getTitle(), $page->getUrlPath());
        } while(($page = $page->getParent()) !== null);

        return array_reverse($ret);
    }

    public static function reAttachRelatedCollection($entity, $field, $collection)
    {
        $cls = new \ReflectionClass(get_class($entity));
        $prop = $cls->getProperty($field);
        $prop->setAccessible(true);
        $prop->setValue($entity, $collection);
    }

    public static function getBaseUrl()
    {
        return 'http' . (($_SERVER['SERVER_PORT'] == 443) ? 's://' : '://') .$_SERVER['HTTP_HOST'];
    }

    public static function convertUrisInHtmlToAbsolute($html, $baseUrl = null)
    {
        if ($baseUrl === null)
        {
            $baseUrl = self::getBaseUrl();
        }
        $phpUri = \phpUri::parse($baseUrl);

        return preg_replace_callback('/(href|src)="((\\\\.|[^"\\\\])*)"/', function($matches) use ($phpUri) {
            return $matches[1] .'="'. $phpUri->join($matches[2]) .'"';
        }, $html);
    }

    public static function formatPrice($value)
    {
        return number_format($value, 2, ',', '.') .' €';
    }

    static function httpRequest($url, $method = "GET", $data = "", $headers = array(), $withRespHeaders = false,
        $cookieJar = null)
    {
        global $kernel;

        $ch = curl_init();
        //self::buildHttpQueryForCurl($headers, $headerList); //?
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_HEADER, $withRespHeaders);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        if (isset($cookieJar))
        {
            curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieJar);
            curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieJar);
        }
        if (strtoupper($method) == 'POST')
        {
            $dataStr = is_array($data) ? http_build_query($data) : $data;
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $dataStr);
        }
        $response = curl_exec($ch);

        $ret = [
            'info'        => curl_getinfo($ch),
            'success'     => true,
            'status_code' => curl_getinfo($ch, CURLINFO_HTTP_CODE)
        ];

        if ($withRespHeaders)
        {
            $respArray = explode("\r\n\r\n", $response);
            $ret['response_headers'] = [];
            // count() - 2 due to HTTP status 100 (continue) with multiple responses
            $headers = is_array($respArray) && isset($respArray[count($respArray) - 2])
                ? explode("\r\n", $respArray[count($respArray) - 2])
                : [];

            // HTTP/1.1 200 OK
            array_shift($headers);

            foreach ($headers as $header)
            {
                $headerKV = explode(': ', $header);
                $key = strtolower($headerKV[0]);
                if (isset($ret['response_headers'][$key]))
                {
                    if (is_array($ret['response_headers'][$key]))
                    {
                        $ret['response_headers'][$key][] = $headerKV[1];
                    }
                    else
                    {
                        $ret['response_headers'][$key] = array($ret['response_headers'][$key], $headerKV[1]);
                    }
                }
                else
                {
                    $ret['response_headers'][$key] = $headerKV[1];
                }
            }
            $ret['content'] = $respArray[count($respArray) - 1];
        }
        else
        {
            $ret['content'] = $response;
        }

        if (curl_errno($ch) > 0)
        {
            $ret['info']['curl_errno'] = curl_errno($ch);
            $ret['success'] = false;
        }

        if (isset($kernel) && $ret['status_code'] >= 300)
        {
            $logger = $kernel->getContainer()->get('logger');
            $logger->warn('HTTP request to \''. $url .'\' with server response code '. $ret['status_code']);
        }

        curl_close($ch);
        return $ret;
    }

    static function httpPost($url, $postData = '', $headers = array(), $withRespHeaders = true, $cookieJarPath = null)
    {
        return self::httpRequest($url, 'POST', $postData, $headers, $withRespHeaders, $cookieJarPath);
    }

    static function httpGet($url, $headers = array(), $withRespHeaders = false, $cookieJarPath = null)
    {
        return self::httpRequest($url, 'GET', '', $headers, $withRespHeaders, $cookieJarPath);
    }

    /**
     * Prints formatted back-trace. CLI-output is colorized as well.
     *
     * @param array $trace trace-content (e.g. from exception) [optional]
     *
     * @link http://www.php.net/manual/en/function.debug-print-backtrace.php#102609
     */
    public static function printBacktrace($trace = null)
    {
        if ($trace === null)
        {
            $trace = debug_backtrace();
        }

        if (Util::isCli())
        {
            $endl = "\r\n";
            $begin = "";
            $end = "";
            $fnFormatterBegin = "\033[0;36m$";
            $fnFormatterEnd = "\033[0m";
            $stackPosFormatterBegin = "\033[1;33m\033[43m ";
            $stackPosFormatterEnd = " \033[0m";
            $argsFormatterBegin = "\033[0;33m";
            $argsFormatterEnd = "\033[0m";
            $fileFormatterBegin = "\033[1;30m";
            $fileFormatterEnd = "\033[0m";
            $lineFormatterBegin = "\033[1;35m";
            $lineFormatterEnd = "\033[0m";
        }
        else
        {
            $endl = "\r\n";
            $begin = "<pre style='width:100%;height:150px;'><code>";
            $end = "</code></pre>";
            $fnFormatterBegin = '<span style="color:blue;">';
            $fnFormatterEnd = '</span>';
            $stackPosFormatterBegin = '<span style="font-weight:bold;color:magenta;">';
            $stackPosFormatterEnd = '</span>';
            $argsFormatterBegin = '<span style="color:orange;">';
            $argsFormatterEnd = '</span>';
            $fileFormatterBegin = '<span style="font-weight:bold;color:black;">';
            $fileFormatterEnd = '</span>';
            $lineFormatterBegin = '<span style="font-weight:bold;color:black;">';
            $lineFormatterEnd = '</span>';
        }

        $ret = $begin . $endl . $endl . '================= STACK TRACE =================' . $endl . $endl;

        foreach($trace as $k=>$v){
            if($v['function'] == "include" || $v['function'] == "include_once" || $v['function'] == "require_once" || $v['function'] == "require")
            {
                $args = $v['args'][0];
            }
            else
            {
                $args = '';
            }
            $ret .=
              $stackPosFormatterBegin .'#'. $k . $stackPosFormatterEnd .' '.
              $fnFormatterBegin .' '. $v['function'] . $fnFormatterEnd .'('.
              $argsFormatterBegin . $args . $argsFormatterEnd .') called at ['.
              $fileFormatterBegin . (isset($v['file']) ? $v['file'] : '?') . $fileFormatterEnd .':'.
              $lineFormatterBegin . (isset($v['line']) ? $v['line'] : '?') . $lineFormatterEnd .']'.
              $endl;
        }
        $ret .= $endl . $endl .'==============================================='. $endl . $endl;

        echo $ret . $end;
    }

    /**
     * Better GI than print_r or var_dump -- but, unlike var_dump, you can only dump one variable.
     * Added htmlentities on the var content before echo, so you see what is really there, and not the mark-up.
     *
     * Also, now the output is encased within a div block that sets the background color, font style, and left-justifies it
     * so it is not at the mercy of ambient styles.
     *
     * Inspired from:     PHP.net Contributions
     * Stolen from:       [highstrike at gmail dot com]
     * Modified by:       stlawson *AT* JoyfulEarthTech *DOT* com
     * Modified by:       uli.hecht@gmail.com (colorized CLI support)
     *
     * @param mixed $var  -- variable to dump
     * @param string $var_name  -- name of variable (optional) -- displayed in printout making it easier to sort out what variable is what in a complex output
     * @param string $indent -- used by internal recursive call (no known external value)
     * @param unknown_type $reference -- used by internal recursive call (no known external value)
     *
     * @todo support stdClass
     */
    public static function varDump(&$var, $var_name = NULL, $indent = NULL, $reference = NULL)
    {
        $isCli = Util::isCli();
        $beginStdFmt = $isCli
          ? "\033[1;30m"
          : "<span style='color:#666666;'>"
        ;
        $endStdFmt = $isCli
          ? "\033[0m"
          : "</span>"
        ;
        $spc = $isCli
          ? " "
          : "&nbsp;"
        ;
        $endl = $isCli ? "\r\n" : "<br>";

        $do_dump_indent = "$beginStdFmt|$endStdFmt$spc$spc";

        $reference = $reference.$var_name;
        $keyvar = 'the_do_dump_recursion_protection_scheme'; $keyname = 'referenced_object_name';

        // So this is always visible and always left justified and readable
        echo $isCli
          ? ""
          : "<div style='text-align:left; background-color:white; font: 100% monospace; color:black;'>"
        ;

        if (is_array($var) && isset($var[$keyvar]))
        {
            $real_var = &$var[$keyvar];
            $real_name = &$var[$keyname];
            $type = ucfirst(gettype($real_var));
            echo $isCli
              ? "$indent$var_name \033[1;30m$type\033[0m = \033[0;33m$real_name\033[0m\r\n"
              : "$indent$var_name <span style='color:#666666'>$type</span> = <span style='color:#e87800;'>&amp;$real_name</span><br>"
            ;
        }
        else
        {
            $var = array($keyvar => $var, $keyname => $reference);
            $avar = &$var[$keyvar];

            $type = ucfirst(gettype($avar));
            if($type == "String") $type_color = $isCli ? "\033[0;32m" : "<span style='color:green'>";
            elseif($type == "Integer") $type_color = $isCli ? "\033[0;31m" : "<span style='color:red'>";
            elseif($type == "Double"){ $type_color = $isCli ? "\033[0;36m" : "<span style='color:#0099c5'>"; $type = "Float"; }
            elseif($type == "Boolean") $type_color = $isCli ? "\033[0;35m" : "<span style='color:#92008d'>";
            elseif($type == "NULL") $type_color = $isCli ? "\033[0;37m\033[40m" : "<span style='color:black'>";

            if(is_array($avar))
            {
                $count = count($avar);
                echo "$indent" . ($var_name ? "$var_name => ":"") ."$beginStdFmt$type ($count)$endStdFmt$endl$indent($endl";
                $keys = array_keys($avar);
                foreach($keys as $name)
                {
                    $value = &$avar[$name];
                    Util::varDump($value, "['$name']", $indent.$do_dump_indent, $reference);
                }
                echo "$indent)$endl";
            }
            elseif(is_object($avar))
            {
                $cls = get_class($avar);
                echo "$indent$var_name $beginStdFmt$cls$endStdFmt$endl$indent($endl";
                foreach($avar as $name=>$value) Util::varDump($value, "$name", $indent.$do_dump_indent, $reference);
                echo "$indent)$endl";
            }
            elseif(is_int($avar)) echo "$indent$var_name = $beginStdFmt$type(".strlen($avar).")$endStdFmt $type_color".($isCli ? $avar : htmlentities($avar))."$endStdFmt$endl";
            elseif(is_string($avar)) echo "$indent$var_name = $beginStdFmt$type(".strlen($avar).")$endStdFmt $type_color\"".($isCli ? $avar : htmlentities($avar))."\"$endStdFmt$endl";
            elseif(is_float($avar)) echo "$indent$var_name = $beginStdFmt$type(".strlen($avar).")$endStdFmt $type_color".($isCli ? $avar : htmlentities($avar))."$endStdFmt$endl";
            elseif(is_bool($avar)) echo "$indent$var_name = $beginStdFmt$type(".strlen($avar).")$endStdFmt $type_color".($avar == 1 ? "TRUE":"FALSE")."$endStdFmt$endl";
            elseif(is_null($avar)) echo "$indent$var_name = $beginStdFmt$type(".strlen($avar).")$endStdFmt {$type_color}NULL$endStdFmt$endl";
            else echo "$indent$var_name = $beginStdFmt$type(".strlen($avar).")$endStdFmt ".($isCli ? $avar : htmlentities($avar))."$endl";

            $var = $var[$keyvar];
        }

        echo $isCli ? "" : "</div>";
    }

    /**
     * @see http://www.codediesel.com/php/quick-way-to-determine-if-php-is-running-at-the-command-line/
     * @return boolean
     */
    public static function isCli()
    {
        return php_sapi_name() == 'cli';
    }
}