<?php
/*
 * This file is part of Blended.
 *
 * Implements blended filters and extension.
 * 
 */

# Default timezone set to 'UTC/GMT'
date_default_timezone_set($config['Default_Timezone']);

# Default datetime format set to ISO8601 standard
const ISO8601 = "Y-m-d\TH:i:sO";

# Default Twig Markup class extension
class Blended_SafeMarkup extends Twig_Markup
{
    var $content;
    protected $charset;
    protected $strategy;
    public function __construct($content, $charset, $strategy = 'all')
    {
        $this->content  = (string) $content;
        $this->charset  = $charset;
        $this->strategy = $strategy;
    }
    /* gets current escape strategy */
    public function getStrategies()
    {
        if (is_string($this->strategy) && false !== $this->strategy) {
            return $this->strategy;
        }
    }

    public function __toString()
    {
        return $this->content;
    }
    
}

function strftimeFormatToDate($strftimeFormat)
{
    
    $caracs = array(
        "%d" => "d",
        "%a" => "D",
        "%e" => "j",
        "%A" => "l",
        "%u" => "N",
        "%w" => "w",
        "%j" => "z",
        "%V" => "W",
        "%B" => "F",
        "%m" => "m",
        "%b" => "M",
        "%G" => "o",
        "%Y" => "Y",
        "%y" => "y",
        "%P" => "a",
        "%p" => "A",
        "%l" => "g",
        "%I" => "h",
        "%H" => "H",
        "%M" => "i",
        "%S" => "s",
        "%z" => "O",
        "%Z" => "T",
        "%s" => "U"
    );
    return strtr((string) $strftimeFormat, $caracs);
}

# Return's datetime object
function blended_datetime($obj, $formatting = null)
{
    if ($obj instanceof DateTime) {
        return $obj;
    } else if (is_string($obj)) {
        
        if (isset($formatting)) {
            return new dateTime(date($obj));
        } else {
            return new dateTime(strftime($obj));
        }
    } else if (is_array($obj)) {
        # return default datetime object on ISO8601 standard format
        return new DateTime(date(ISO8601, mktime($obj[3], $obj[4], $obj[5], $obj[1], $obj[2], $obj[0])));
        
    }
}

# Sorts an array by key
function blended_items($item)
{
    ksort($item);
    return $item;
}

# Makes value to number format.
function blended_number($number_convert)
{
    $str_var = (string) $number_convert;
    return (float) $str_var;
}

# sorting multi-dimensional arrays by its key, for associative arrays.
function blended_sort(&$array){
    ksort($array);
    foreach($array as &$value)
        if(is_array($value))
            blended_sort($value);
}

# format value with provided formatting.
function blended_string($obj, $string_format = null, $isoutside = True)
{
    $temporary_list  = array();
    $temporary_dict  = array();
    $temporary_tuple = array();
    if (is_null($obj)) {
        return "null";
    } else if (is_bool($obj)) {
        
        if ($obj) {
            # boolean true are returned as string "true"
            return "true";
        } else {
            # boolean false are returned as string "false"
            return "false";
        }
    } else if (is_array($obj)) {        

        blended_sort($obj);

        if ($isoutside) {
            
            if (isset($string_format)) {
                # Operates as sprintf() but accepts an array of arguments and return formatted string.
                return vsprintf($string_format, $obj);
                
            } else {
                # manipulating array to json so as to extract string as python does.
                $var_string = json_encode($obj);
                $var_string = str_replace(",", ", ", $var_string);
                $var_string = str_replace('"', "'", $var_string);
                $var_string = str_replace(':', ": ", $var_string);
                return $var_string;                
            }
        }
        
    } else if (is_numeric($obj)) {
        if ($isoutside) {
            if (isset($string_format)) {
                # return string based on provided format
                return sprintf($string_format, $obj);
            } else {
                return (string) $obj;
            }
        } else {
            return $obj;
        }
    } else if ($obj instanceof DateTime) {
        
        if (isset($string_format)) {
            # return default datetime object in provided format
            return strftime($string_format, $obj->getTimestamp());
        } else {
            # return default datetime object on ISO8601 standard format
            return strftime(ISO8601, $obj->getTimestamp());
        }
    } else if (is_string($obj)) {
        return $obj;
    } else{
	     try {          
                 throw new Exception(get_class($obj).' Object could not be converted to string');
             } catch (Exception $e) {
                 echo 'Caught exception: ',  $e->getMessage(), "\n";
             }
    }    
}

# loads a template from a string.
function blended_template(\Twig_Environment $env, $template_convert)
{
    # Default Twig function of its filter **template_from_string**
    return twig_template_from_string($env, $template_convert);
}

# render template object
function blended_render($template_obj, $context = null)
{
    if (isset($context)) {
        if (is_array($context)) {
            if (!empty($template_obj)) {
                return $template_obj->render($context);
            }
        }
    }
}

#  variable will not be escaped.
function blended_safe(\Twig_Environment $env, $string)
{
    #  getting current strategy of template corrospond to unique template name.

//    $current_strategy = call_user_func(array(
//        'Twig_FileExtensionEscapingStrategy',
//        'guess'
//    ), $env->getBaseTemplateClass());
    //), $env->getCompiler()->getFilename());


    $current_strategy = call_user_func(array(
        'Twig_FileExtensionEscapingStrategy',
        'guess'
    ), getTwigTemplateName());

    if ($string instanceof Blended_SafeMarkup) {
        if ($string->getStrategies() == 'all') {
            return $string;
        } else {
            $new_strategy = new Blended_SafeMarkup($string, $env->getCharset(), $current_strategy);
            return $new_strategy;
        }
    } else if ($string instanceof Twig_Markup && !($string instanceof Blended_SafeMarkup)) {
        return $string;
    } else if (is_string($string)) {
        if (!isset($current_strategy)) {
            $instantiate_blendedsafe = new Blended_SafeMarkup($string, $env->getCharset());
        } else if (isset($current_strategy)) {
            $instantiate_blendedsafe = new Blended_SafeMarkup($string, $env->getCharset(), $current_strategy);
            return $instantiate_blendedsafe;
        } else {
            return $string;
        }
    }
}

// Utility function that fetches the current filename using a debug backtrace
function getTwigTemplateName()
{
    foreach (debug_backtrace() as $trace) {
        if (isset($trace['object'])
            && (strpos($trace['class'], 'TwigTemplate') !== false)
            && 'Twig_Template' !== get_class($trace['object'])
        ) {
            return $trace['object']->getTemplateName()
//                . "({$trace['line']})"
                    ;
        }
    }
    return '';
}

# escapes a string for safe insertion into the final output.
function blended_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
{
    /*
     * Debugging block, TODO : delete in code cleanup
     * */
/*    $backtrace = debug_backtrace();

    print_r( $backtrace );*/

    #  getting current strategy of template corrospond to unique template name.

//    $current_strategy = call_user_func(array(
//        'Twig_FileExtensionEscapingStrategy',
//        'guess'
//    ), $env->getCompiler()->getFilename());

    /*Second method used is present below : */
//    $current_strategy = call_user_func(array(
//        'Twig_FileExtensionEscapingStrategy',
//        'guess'
//    ), $env->getBaseTemplateClass());

    $current_strategy = call_user_func(array(
        'Twig_FileExtensionEscapingStrategy',
        'guess'
    ), getTwigTemplateName());

    if ($string instanceof Blended_SafeMarkup) {
        # if same strategy then return unmodified else intantiate with new strategy.
        if ($string->getStrategies() == $current_strategy || $string->getStrategies() == 'all') {
            return $string;
        } else if ($string->getStrategies() != $current_strategy && $string->getStrategies() != 'all') {
            $escape_string = new Blended_SafeMarkup($string->content, $charset, $current_strategy);
            return $escape_string;
        }
    }
    if (($string instanceof Twig_Markup) && !($string instanceof Blended_SafeMarkup)) {
        $escape_string = twig_escape_filter($env, $string, $strategy, $charset, $autoescape);
        return $escape_string;
    }
    if (is_string($string)) {
        $escape_string = twig_escape_filter($env, $string, $strategy, $charset, $autoescape);
        # marking string as safe by instantiating new Blended_safeMarkup so as to avoid double escaping.
        $escape_string = new Blended_SafeMarkup($escape_string, $charset, $strategy);
        return $escape_string;
    }
    if (!is_string($string)) {
        if (is_object($string) && method_exists($string, '__toString')) {
            $string = twig_escape_filter($env, (string) $string, $strategy, $charset, $autoescape);
            return $string;
        } elseif (in_array($strategy, array(
            'html',
            'js',
            'css',
            'html_attr',
            'url'
        ))) {
            return $string;
        }
    }
    
}
