<?php


require_once(MH_DIR_FS_CATALOG . MH_ROOT_PATH . 'common/functions/compatibility.php');
require_once(MH_DIR_FS_CATALOG . MH_ROOT_PATH . 'common/vendor/Gregwar/Cache/autoload.php');
require_once(MH_DIR_FS_CATALOG . MH_ROOT_PATH . 'common/vendor/Gregwar/Image/autoload.php');
require_once(MH_DIR_FS_CATALOG . MH_ROOT_PATH . 'common/classes/mailbeez_shrtnr.php');

mh_define('MH_IMG_CACHE_ROOT_PATH', (mh_cfg('MAILBEEZ_CONFIG_IMAGE_ENGINE_CACHE_DIR') && mh_cfg('MAILBEEZ_CONFIG_IMAGE_ENGINE_CACHE_DIR') != '') ? mh_cfg('MAILBEEZ_CONFIG_IMAGE_ENGINE_CACHE_DIR') : 'imgcache');
mh_define('MAILBEEZ_CONFIG_IMAGE_CACHE_DIR', MH_IMG_CACHE_ROOT_PATH);
mh_define('MAILBEEZ_CONFIG_IMAGE_CACHE_DIR_LEGACY', MH_ROOT_PATH . 'images/cache');

// Migration
// keep old cache directory with .htaccess
// http://localhost7/GX3_v3.1.2.0/ext/mailhive/images/cache/f/4/7/c/8/f47c86dc6a563c5bde01b0836da54062.png

mh_define('MAILBEEZ_CONFIG_IMAGE_CACHE_FS', mh_cfg('MH_DIR_FS_CATALOG') . mh_cfg('MAILBEEZ_CONFIG_IMAGE_CACHE_DIR'));
mh_define('MAILBEEZ_CONFIG_IMAGE_CACHE_FS_LEGACY', mh_cfg('MH_DIR_FS_CATALOG') . mh_cfg('MAILBEEZ_CONFIG_IMAGE_CACHE_DIR_LEGACY'));
mh_define('MAILBEEZ_CONFIG_IMAGE_CACHE_WS', mh_cfg('MH_DIR_WS_CATALOG') . mh_cfg('MAILBEEZ_CONFIG_IMAGE_CACHE_DIR'));

//echo mh_lng('MAILBEEZ_CONFIG_IMAGE_CACHE_WS'); mh_exit();

use Gregwar\Image\Exceptions\GenerationError;


class mailbeez_image_engine extends Gregwar\Image\Image
{
    protected $cacheDir;

    const INVALID_IMAGE_DATA = -99;

    var $apiPath;

    var $api_params = array('img_url', 'img_type', 'img_q',
        'resize', 'scaleResize', 'forceResize', 'cropResize', 'zoomCrop', 'crop',
        'fx_modify', 'fx_render', 'fx_grayscale', 'fx_sepia', 'fx_sharp', 'fx_smooth', 'fx_brightness', 'fx_contrast', 'fx_colorize',
        'fullsize');

    var $shrtner;

    /*
     * https://github.com/Gregwar/Image

     resize($width, $height, $background): resizes the image, will preserve scale and never enlarge it
     scaleResize($width, $height, $background): resizes the image, will preserve scale, can enlarge it
     forceResize($width, $height, $background): resizes the image forcing it to be exactly $width by $height
     cropResize($width, $height, $background): resizes the image preserving scale (just like resize()) and croping the whitespaces:
     zoomCrop($width, $height, $background, $xPos, $yPos): resize and crop the image to fit to given dimensions:
     crop($x, $y, $w, $h): crops the image to a box located on coordinates $x,y and which size is $w by $h

     grayscale(): converts the image to grayscale
     sepia(): applies a sepia effect
     sharp(): applies a mean removal filter on the image
     smooth($p): smooth the image http://stackoverflow.com/questions/5419666/php-imagefilter-parameter-img-filter-smooth-value-ranges-question
     brighness($b): applies a brightness effect to the image (from -255 to +255)
     contrast($c): applies a contrast effect to the image (from -100 to +100) 100 = max contrast, 0 = no change, +100 = min contrast (note the direction!)
     colorize($red, $green, $blue): colorize the image (from -255 to +255 for each color)

     *
     */

    function __construct($originalFile = null, $width = null, $height = null)
    {
        parent::__construct($originalFile, $width, $height);
        $this->cacheDir = MAILBEEZ_CONFIG_IMAGE_CACHE_FS;
        //$this->apiPath = HTTP_CATALOG_SERVER . MH_DIR_WS_CATALOG . 'mailhive.php/api/public/v1.0/editor/imgengine/';
        $this->apiPath = HTTPS_CATALOG_SERVER . MH_DIR_WS_CATALOG . 'mailhive.php/api/public/v1.0/editor/imgengine/';

        if (getenv('SAAS_FORGE')) {
            $this->apiPath = HTTPS_CATALOG_SERVER . MH_DIR_WS_CATALOG . 'mailhive.php?/api/public/v1.0/editor/imgengine/';
        }

        $this->checkOrCreateHtaccess();
        $this->shrtner = new mailbeez_shrtnr();
    }

    function getPrefixSize()
    {
        $c = new mailbeez_image_engine_cache();
        return $c->getPrefixSize();
    }

    function makeCacheId($parameters)
    {
        $string = '';
        $params = array();
        foreach ($this->api_params as $p) {
            $params[$p] = (isset($parameters[$p])) ? $parameters[$p] : '';
        }

        $params['img_url'] = str_replace('%2F', '/', $params['img_url']);

        // 2732_0.jpg%3Fv%3D1722322950
        // clean up filenames like 2732_0.jpg?v=1722322950 -> 2732_0.jpg
        $real_url = urldecode($params['img_url']);

        if (stristr($real_url, '?')) {
            $params['img_url'] = substr($real_url, 0, strpos($real_url, '?'));
        }
        $valueString = $this->encode($params);
        return $this->shrtner->set($valueString);
    }

    function makeCacheIdFilePath($parameters)
    {
        // 'format=jpg-90&width=300&height=400&mode=scaleResize&bgcolor=ff0000'
        parse_str($parameters['fx_render'], $render_data);

        $format = (isset($render_data['format'])) ? $render_data['format'] : 'jpg';

        if (stristr($format, '-')) {
            list ($img_type,) = explode('-', $format);
        } else {
            $img_type = $format;
        }
        $filename = $this->makeCacheFilePath($this->makeCacheId($parameters), $img_type);
        return $filename;
    }


    /**
     * generate cache path from input
     *
     * @param $string
     * @return array|string
     */
    function makeCacheFilePath($string, $ext)
    {
        $path = array();

        $len = strlen($string);

        for ($i = 0; $i < min($len, $this->getPrefixSize()); $i++) {
            $path[] = $string[$i];

        }
        $path = implode('/', $path);
        return $path . '/' . $string . '.' . $ext;
    }

    /**
     * return raw api url
     *
     * used for gambio cloud in mailhive/configbeez/config_editor/smarty_plugins/function.mailbeez_img_engine_url.php
     *
     * @param $string
     * @return array|string
     */

    function makeRawApiPath($params)
    {
        $fcgi_path = str_replace('mailhive.php/', 'mailhive.php?/', $this->apiPath);
        return $fcgi_path . '&id=' . $this->makeCacheId($params);
    }


    function getCacheIdFromFileName($cachefilename, $cachefileExt)
    {
        $cachefileExt = str_replace('.', '', $cachefileExt);
        $cachefilename = str_replace('.' . $cachefileExt, '', $cachefilename);

        $parts = explode('/', $cachefilename);
        return array_pop($parts);
    }


    function getParamsFromCacheId($cacheId)
    {
        $param_array = array();
        $params_raw_array = $this->decode($this->shrtner->get($cacheId));
        foreach ($this->api_params as $p) {
            $param_array[$p] = $params_raw_array[$p];
        }
        return $param_array;
    }

    function dropOldFiles()
    {
        Gregwar\Image\GarbageCollect::dropOldFiles(MAILBEEZ_CONFIG_IMAGE_CACHE_FS, 30, false);
    }

    function dropLegacyCache()
    {
        Gregwar\Image\GarbageCollect::dropOldFiles(MAILBEEZ_CONFIG_IMAGE_CACHE_FS_LEGACY, 0, false);
    }

    /*
     *
     * in fcgi environments the rewrite rule in mailbeez_image_engine
     * like
     * RewriteRule ^([^.]+\.(jpg|png|gif))$ /mailhive.php/api/public/v1.0/editor/imgengine/?id=$1&type=$2&c=$0 [' . $parameters . ']
     *
     * gives "no input file specified"
     *
     *
     * SOLUTION
     *
     * with changing to mailhive.php?/api...
     * the rewrite rule works, but the PATH_INFO is not longer set
     * so fix this and restore the correct $_SERVER variables


    .htaccess
    <IfModule mod_fcgid.c>
	  RewriteCond %{REQUEST_FILENAME} !-f
      RewriteRule ^([^.]+)\.(jpg|png|gif)$  <domain>/mailhive.php?/api/public/v1.0/editor/imgengine/?id=$1&type=$2&c=$0 [QSA,L]
    </IfModule>


    inc_mailhive.php:
    if (!isset($_SERVER['PATH_INFO'])) {

     	list($path, $query) = explode('?',$_SERVER['QUERY_STRING']);


     	$_SERVER['PATH_INFO'] = $path;
     	$_SERVER['QUERY_STRING'] = $query;

     	parse_str($query, $get_array);
    	$_GET = array_merge($_GET, $get_array);
     }



     *
     */


    function checkOrCreateHtaccess()
    {
        // $v_apache = apache_get_version();
        // https://gist.github.com/jaswsinc/97c72252531277f7aa19

        // http://borkweb.com/story/apache-rewrite-cheatsheet
        // http://mod-rewrite.org/book/mod_rewrite.html
//        $parameters = 'P,NC'; // apache 2.2
        $parameters = 'NC'; // apache 2.2
//        $parameters = 'QSA,NC'; // apache 2.4 - changes url

        // rewrite flag P causes error on apache 2.4
        // solution: handle redirect in api class

// http://localhost7/GX3_v3.1.2.0/ext/mailhive/images/cache/f/4/7/c/8/f47c86dc6a563c5bde01b0836da54062.png

        $filename = MAILBEEZ_CONFIG_IMAGE_CACHE_FS . '/.htaccess';

        if (file_exists($filename)) {
            return true;
        }

        // handling of legacy cache
        $filename_legacy = MAILBEEZ_CONFIG_IMAGE_CACHE_FS_LEGACY . '/.htaccess';

        if ($filename_legacy != $filename) {
            self::checkCacheDirWriteable();
            if (file_exists($filename_legacy)) {
                if (copy($filename_legacy, $filename)) {
                    $this->dropLegacyCache();
                }
                return true;
            }
        }

        // todo: test

        $fcgi_path = str_replace('mailhive.php', 'mailhive.php?', $this->apiPath);

        $content = '
        RewriteEngine On
        RewriteBase /
        
        <IfModule mod_fcgid.c>
	        RewriteCond %{REQUEST_FILENAME} !-f
            RewriteRule ^([^.]+)\.(jpg|png|gif)$ ' . $fcgi_path . '&id=$1&type=$2&c=$0 [QSA,L]
        </IfModule>
        # force https
        # RewriteCond %{HTTPS} off
        # RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
        
        # Check if file *.* exist in the cache folder
        RewriteCond %{REQUEST_FILENAME} !-f
        # RewriteRule ^([^.]+\.(jpg|png|gif))$ ' . $this->apiPath . '?id=$1&type=$2&c=$0 [' . $parameters . ']
        RewriteRule ^([^.]+)\.(jpg|png|gif)$ ' . $this->apiPath . '?id=$1&type=$2&c=$0 [' . $parameters . ']
        
        # in case of 406 error
        # RewriteRule ^([^.]+)\.(jpg|png|gif)$ ' . $this->apiPath . '?id=$1&type=$2&c=$0 [' . $parameters . ']
        # - in case / is not allowed as parameter
        # RewriteRule ([^/]+)\.(jpg|png|gif)$ ' . $this->apiPath . '?id=$1&type=$2&c=$0 [NC]
        # testing curl -iv --raw URL
        ';

        return file_put_contents($filename, $content);

    }


    function getOrLoadRemoteImageData($imgUrl)
    {
        // debug
//        $this->getRemoteImage($imgUrl);

        $cacheFile = md5($imgUrl) . '.raw';

        $conditions = array();

        // PHP5.3 compatiblity workaround
        if (PHP_VERSION >= '5.4') {
            // The generating function
            $generate = function ($target) use ($imgUrl) {
                $data = $this->getRemoteImage($imgUrl);
                return $data;
            };
            // Asking the cache for the cacheFile
            try {
                $data = $this->getCacheSystem()->getOrCreate($cacheFile, $conditions, $generate);
                if ($data == false) {
                    throw new GenerationError('empty image result');
                }
            } catch (GenerationError $e) {
                return self::INVALID_IMAGE_DATA;
                // can cause infinite loop
//                $data = $this->getRemoteImage($imgUrl);
            }
        } else {
            $data = $this->getCacheSystem()->get($cacheFile);
            if (!$data) {
                $data = $this->getRemoteImage($imgUrl);
                $this->getCacheSystem()->set($cacheFile, $data);
            }
        }
        return $data;
    }

    function getRemoteImage($imgUrl, $iteration = 0)
    {
        // image url support for ()/
        $imgUrl = (str_replace([' '], ['%20'], $imgUrl));
        $real_url = $imgUrl;
        $headers = [];
        if (stristr($imgUrl, 'proxy:')) {
            $headers = [
                'X-Url: ' . str_replace('proxy:', '', $real_url)
            ];
            $imgUrl = 'https://proxy.mlbz.io';
        }

        $ch = curl_init($imgUrl);

        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
//        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
//        curl_setopt($ch, CURLOPT_NOBODY, true);
//        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); // open_basedir conflict
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        $rawResult = curl_exec($ch);
        $info = curl_getinfo($ch);

        if (curl_exec($ch) === false) {
            // e.g. Curl error: error:0A000458:SSL routines::tlsv1 unrecognized name
            if (stristr(curl_error($ch), 'SSL')) {
                return $this->getRemoteImage('proxy:'.$real_url);
            }
            return false;
            //return 'Curl error: ' . curl_error($ch);
        }
        curl_close($ch);

        if (!stristr($info['content_type']??'', 'image') ) {
            return false;
        }

        // check if redirect
        if (isset($info['redirect_url']) && stristr($info['redirect_url'], 'http')) {
            $real_url = $info['redirect_url'];
//            echo $real_url; mh_exit();
            return $this->getRemoteImage($real_url);
        } elseif (preg_match('#Location: (.*)#', $rawResult, $r)) {
            $real_url = trim($r[1]);
//            echo $real_url; mh_exit();
            return $this->getRemoteImage($real_url);
        } elseif (preg_match('#href="(.*)"#', $rawResult, $r)) {
            // e.g. unsplash.com
            $real_url = trim($r[1]);
            $real_url = str_replace('&amp;', '&', $real_url);
            $real_url = str_replace('&fit=crop', '', $real_url);
//            echo $real_url;mh_exit();
            return $this->getRemoteImage($real_url);
        } else {
//            echo $rawResult;mh_exit();
            return $rawResult;
        }

    }

    // http://stackoverflow.com/questions/11449577/why-is-base64-encode-adding-a-slash-in-the-result
    function encode($s)
    {
        return serialize($s);
        return str_replace(array('+', '/'), array('-', '_'), base64_encode(gzcompress($s)));
//        return str_replace(array('+', '/'), array('-', '_'), base64_encode(($s)));
    }

    function decode($s)
    {
        return unserialize($s);

        return gzuncompress(base64_decode(str_replace(array('-', '_'), array('+', '/'), $s)));
//        return (base64_decode(str_replace(array('-', '_'), array('+', '/'), $s)));
    }

    function createIcon($icon_set, $icon, $color, $bgcolor = 'transparent', $canvasSize = 1000)
    {

        $mappingPaths = $this->getIconMapPaths($icon_set);

        $icon_unicodes = array();
        if (file_exists($mappingPaths['php'])) {
            include_once($mappingPaths['php']);
        }

        $icon_color = $color;

        $bgcolor = ($bgcolor == '') ? 'transparent' : $bgcolor;

        $canvas_width = $canvasSize;
        $canvas_height = $canvasSize;

        // map icon to hexcode
        $icon_text = $icon_unicodes[$icon_set][$icon];


        $icon_angle = 0;

        // iconfont settings
        $icon_font['fontawesome'] = MH_DIR_FS_CATALOG . MH_ROOT_PATH . 'common/css/font-awesome/fonts/fontawesome-webfont.ttf';
        $icon_fontsize['fontawesome'] = $canvas_height * 0.5;
        $icon_baselineheight_perc['fontawesome'] = 14;

        $icon_lineheight_perc['fontawesome'] = 88; // to center icon


        // total height of icon
//        $icon_height_total = $icon_fontsize[$icon_set] * $icon_totalheight_perc[$icon_set] / 100;

        // height of baseline offset
        $icon_baseline_height = ($icon_fontsize[$icon_set] * $icon_lineheight_perc[$icon_set] / (100 - $icon_baselineheight_perc[$icon_set])) - $icon_fontsize[$icon_set];

        $draw_pos_x = $canvas_width / 2;
//            $draw_pos_y = $canvas_height - ($canvas_height - $icon_fontsize[$icon_group]) / 2 - $icon_baseline_height;
        $draw_pos_y = $canvas_height - (($canvas_height - $icon_fontsize[$icon_set]) / 2) - (1 * $icon_baseline_height);


//            echo $draw_pos_y;
//            mh_exit();

        // icon-height = line-height + baselineheight

        // font awesome
        // font-size: 280px
        // widest icon 300px // fa-keyboard-o f11c
        // heighest icon 280px // fa-binoculars f1e5

        // $icon_fontsize[$icon_group] = 500 -> 667  -> + 33%

        // icon-canvase is 33% higher than fontsize
        // base line is 15% of lineheight


//            list($_draw_pos_x, $draw_pos_y) = $this->imageTTFCenter($canvas_width, $canvas_height, $icon_text, $icon_font[$icon_group], $icon_fontsize[$icon_group], $icon_angle);

        $img = $this->create($canvas_width, $canvas_height)
            ->fill($bgcolor)
            // ($font, $text, $x = 0, $y = 0, $size = 12, $angle = 0, $color = 0x000000, $align = 'left')
            ->write($icon_font[$icon_set], $icon_text, $draw_pos_x, $draw_pos_y, $icon_fontsize[$icon_set], $icon_angle, $icon_color, 'center');
        return $img;
    }


    function updateIcons()
    {
        $this->generateIconMap('fontawesome');
    }

    function getIconMapPaths($iconSet)
    {

        switch ($iconSet) {
            case 'fontawesome':
                $targetPathJs = MH_DIR_FS_CATALOG . MH_ROOT_PATH . 'common/vendor/victor-valencia/bootstrap-iconpicker/js/iconset/iconset-fontawesome-generated.js';
                $targetPathPHP = MH_DIR_FS_CATALOG . MH_ROOT_PATH . 'common/vendor/victor-valencia/bootstrap-iconpicker/php/iconset-fontawesome-generated.php';
                break;
        }
        return array('js' => $targetPathJs, 'php' => $targetPathPHP);
    }


    function generateIconMap($iconSet)
    {
        $matches = array();

        switch ($iconSet) {
            case 'fontawesome':
                $targetPaths = $this->getIconMapPaths($iconSet);
                $targetPathJs = $targetPaths['js'];
                $targetPathPHP = $targetPaths['php'];

                $path = MH_DIR_FS_CATALOG . MH_ROOT_PATH . 'common/css/font-awesome/css/font-awesome.css';
                $css = file_get_contents($path);
                $iconClass = 'fa';
                $iconClassPrefix = 'fa';
                $pattern = '/\.(' . $iconClassPrefix . '-(?:\w+(?:-)?)+):before\s+{\s*content:\s*"(.+)";\s+}/';
                preg_match_all($pattern, $css, $matches, PREG_SET_ORDER);
                break;
        }

//        print_r ($matches);
        $iconList = array();
        $iconListCodesPhpArray = array();
        $iconListCodesPhp = '';

        if (is_array($matches) and sizeof($matches) > 0) {
            foreach ($matches as $match) {
//                $icon = new Icon($this, $match[1], $match[2]);

                $match[1]; // fa-check
                $match[2]; // \f00c -> &#xf00c;
                $iconList[$match[1]] = $match[2];

                $iconListCodesPhpArray[] = "'" . $match[1] . "' => '" . str_replace('\\', '&#x', $match[2]) . ";'";
            }

            $iconListCodesPhp = implode(',', $iconListCodesPhpArray);
        }

        $iconListCodes = "'" . implode("','", array_keys($iconList)) . "'";
        $iconListCodes = str_replace('fa-', '', $iconListCodes);


        $iconSetCode = ";(function($){
        
            $.iconset_$iconSet = {
                iconClass: '$iconClass',
                iconClassFix: '$iconClassPrefix-',
                icons: [
                    '',
                    $iconListCodes
            ]};
        })(jQuery);";


        $iconMappingCode = '<?php
        
        $icon_unicodes[\'' . $iconSet . '\'] = array(' .
            $iconListCodesPhp . '
        );';

        file_put_contents($targetPathJs, $iconSetCode);
        file_put_contents($targetPathPHP, $iconMappingCode);
        echo "iconSet $iconSet updated<br>";

    }

    function formatBytes($bytes, $precision = 2)
    {
        $units = array('B', 'kB', 'MB', 'GB', 'TB');

        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
        $bytes /= pow(1024, $pow);

        return round($bytes, $precision) . '' . $units[$pow];
    }


    static function checkCacheDirWriteable()
    {
        $test_folder = MAILBEEZ_CONFIG_IMAGE_CACHE_FS;

        if (!is_dir($test_folder)) {
            @mkdir($test_folder, 0755, true);
        }
        if (!is_dir($test_folder)) {
            return false;
        }

        $test_file = '/image_cache_write_test.txt';
        if (file_exists($test_folder . $test_file)) {
            unlink($test_folder . $test_file);
        }
        if (!file_exists($test_folder . $test_file)) {
            @chmod($test_folder, 0777);
            @touch($test_folder . $test_file);
            @chmod($test_folder, 0755);
            if (!file_exists($test_folder . $test_file)) {
                return false;
            }
        }
        return is_writable($test_folder . $test_file);
    }
}

class mailbeez_image_engine_cache extends Gregwar\Cache\Cache
{
    function getPrefixSize()
    {
        return $this->prefixSize;
    }

}
