<?php
/*
 * This file is part of Blended.
 *
 * Implements blended functions.
 * 
 */

# Regular Expression to detect string as valid hexadecimal type.
const HEX_COLOR_RE_WITHOUT_HASH = '([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})';

function blended_unique($array)
{
    # return unique values from multi-dimensional arrays
    if (is_array($array)) {
        # returns an array containing all the unique elements of array 
        $result = array_map("unserialize", array_unique(array_map("serialize", $array)));
        
        # callback if array contains an array in a multi-dimensional way
        foreach ($result as $key => $value) {
            if (is_array($value)) {
                $result[$key] = blended_unique($value);
            }
        }
        
        return $result;
    }
}

function blended_difference($array1, $array2, $max_arr_changed = false)
{
    $size1 = count($array1);
    $size2 = count($array2);
    
    # compare size of arrays, to loop through max array elements.
    if ($size1 < $size2) {
        # maintaining change cases here if array2 size is greater so as to maintain ordering while merging two arrays.
        $max_arr_changed = true;
        $temp            = $array2;
        $array2          = $array1;
        $array1          = $temp;
    }
    return find_difference(blended_unique($array1), blended_unique($array2), $max_arr_changed);
}

function find_difference($array1, $array2, $max_arr_changed = false)
{
    if (is_array($array1) && is_array($array2)) {
        foreach ($array1 as $key => $value) {
            if (!isset($array1[$key]) && !is_null($array1[$key])) {
                unset($array1[$key]);
            } else if (is_array($array1[$key])) {
                # In multi-dimensional array, looking for same value in other array and if found unset it to find difference
                if (isset($array2[array_search($value, $array2)]) && ($array1[$key] === $array2[array_search($value, $array2)])) {
                    unset($array1[$key]);
                    unset($array2[array_search($value, $array2)]);
                    
                }
                # if value is integer unset value from other array
            } elseif (is_int(array_search($value, $array2)) && $array2[array_search($value, $array2)] === $value) {
                unset($array1[$key]);
                unset($array2[array_search($value, $array2)]);
            }
        }
        
        # Merges the elements of one or more arrays together so that the values of one are appended to the end of the previous one.
        if ($max_arr_changed == true) {
            return array_merge($array2, $array1);
        } else {
            return array_merge($array1, $array2);
        }
    }
    
}

function find_intersection($array1, $array2, $order_state = false)
{
    if ($order_state != false) {
        $temp   = $array1;
        $array1 = $array2;
        $array2 = $temp;
    }
    
    if (is_array($array1) && is_array($array2)) {
        foreach ($array1 as $key => $value) {
            # if same value does not exist in other array, unset the value.
            if (!is_array($value) && array_search($value, $array2) === false) {
                unset($array1[$key]);
            } else {
                if (is_array($value)) {
                    # If multi-dimensional array value exist in other array then call recursive.
                    if ($value == $array2[array_search($value, $array2)]) {
                        $array1[$key] = find_intersection($array1[$key], $array2[array_search($value, $array2)], $order_state);
                    } else {
                        # if value does not exist, unset the value.
                        unset($array1[$key]);
                    }
                    # if value is not array and exist in other array, unset the value.
                } elseif ($array2[array_search($value, $array2)] !== $value) {
                    unset($array1[$key]);
                }
            }
        }
        return $array1;
    }
}

function blended_intersection($array1, $array2)
{
    $order_state = false;
    
    if (is_array($array1) && is_array($array2)) {
        $size1 = count($array1);
        $size2 = count($array2);
        
        # compare size of arrays, to loop through max array elements.
        if ($size1 < $size2) {
            $temp        = $array2;
            $array2      = $array1;
            $array1      = $temp;
            $order_state = true;
        }
        
        # returns all the values from the array and indexes the array numerically.
        return array_values(find_intersection($array1, $array2, $order_state));
    }
}

function blended_union($array1, $array2)
{
    if (is_array($array1) && is_array($array2)) {
        
        $array1 = blended_unique($array1);
        $array2 = blended_unique($array2);
        
        # removing duplicate values from another array.
        foreach ($array2 as $key => $value) {
            if (in_array($value, $array1, true) == true) {
                unset($array2[$key]);
            }
            
        }
        
        $union = array_merge($array1, $array2);
        return $union;
    }
}


function blended_complement($array1, $array2)
{
    if (is_array($array1) && is_array($array2)) {
        
        # getting unique values from multi-dimensional array.
        $array1 = blended_unique($array1);
        $array2 = blended_unique($array2);
        foreach ($array1 as $key => $value) {
            if (!isset($array1[$key]) && !is_null($array1[$key])) {
                unset($array1[$key]);
            } else if (is_array($array1[$key])) {
                # In multi-dimensional array, looking for same value in other array and if found unset the value.
                if (($array1[$key] === $array2[array_search($value, $array2)])) {
                    unset($array1[$key]);
                    unset($array2[array_search($value, $array2)]);
                    
                }
                # if value is integer unset value from other array
            } elseif (is_int(array_search($value, $array2)) && $array2[array_search($value, $array2)] === $value) {
                unset($array1[$key]);
                unset($array2[array_search($value, $array2)]);
            }
        }
        
        # returns all the values from the array and indexes the array numerically.
        return array_values($array1);
    }
}

function blended_cartProd($array1, $array2)
{
    if (is_array($array1) && is_array($array2)) {
        
        # getting unique values from multi-dimensional array.
        $array1       = blended_unique($array1);
        $array2       = blended_unique($array2);
        $cart_product = array();
        foreach ($array1 as $array1_key)
            foreach ($array2 as $array2_key)
            # Merges the elements of one or more arrays together so that the values of one are appended to the end of the previous one.
                $cart_product[] = array_merge(array(
                    $array1_key
                ), array(
                    $array2_key
                ));
        
        return $cart_product;
    }
}

# Returns an array of elements from start to end, inclusive.
function blended_series($start, $length, $increment = 1)
{
    $i        = $start;
    $new_list = array();
    while ($length > 0) {
        array_push($new_list, $i);
        $i += $increment;
        $length--;
    }
    return $new_list;
}

# Returns the value of the first array element
function blended_first($first_arr)
{
    return reset($first_arr);
}

# Returns the value of the last array element
function blended_last($last_arr)
{
    $last = array_slice($last_arr, -1, 1, true);
    return end($last);
}

# Round fractions up
function blended_ceil($ceil_value)
{
    return ceil($ceil_value);
}

# Round fractions down
function blended_floor($floor_value)
{
    return floor($floor_value);
}

# Join array/string with provided separator.
function blended_join($join_arr, $join_sep = '')
{
    $joined = "";
    if (is_array($join_arr)) {
        $count = count($join_arr);
        foreach ($join_arr as $join_arr_key => $join_arr) {
            if ($join_arr_key != ($count - 1))
                $joined .= $join_arr . $join_sep;
            else
                $joined .= $join_arr;
        }
    } else if (is_string($join_arr)) {
        $splitted = str_split($join_arr);
        $count    = count($splitted);
        foreach ($splitted as $splitted_key => $splitted) {
            if ($splitted_key != ($count - 1))
                $joined .= $splitted . $join_sep;
            else
                $joined .= $splitted;
        }
    }
    return $joined;
}

# rounded value to specified precision
function blended_round($round_val, $precision = 0)
{
    if (is_object($round_val)) {
        $round_val = (string) $round_val;
        $round_val = floatval($round_val);
        return round($round_val, $precision);
    }
    return round($round_val, $precision);
}

# Concatenates string and arrays
function blended_concat($list1, $list2)
{
    if (is_array($list1) && is_array($list2)) {
        return array_merge($list1, $list2);
    } else if (is_string($list1) && is_string($list2)) {
        return $list1 . $list2;
    }
}

# Count all elements in an array
function blended_length($len_arr_str)
{
    if (is_array($len_arr_str)) {
        return count($len_arr_str);
    } else {
        return strlen($len_arr_str);
    }
}

# Make a string lowercase
function blended_lower($str_lower)
{
    return strtolower($str_lower);
}

# Make a string uppercase
function blended_upper($str_upper)
{
    return strtoupper($str_upper);
}

# Make string Titlecase 
function blended_title($str_title)
{
    $title_result = '';
    if (is_string($str_title)) {
        $str_title  = strtolower($str_title);
        $camel_case = explode(" ", $str_title);
        foreach ($camel_case as $camel_case) {
            $title_result .= ucfirst($camel_case) . " ";
        }
    }
    return trim($title_result);
}

function theme_data($context_key, $block_name, $ext_html)
{
    $grid_all      = $context_key['grid']['all'];
    $ext_html_data = $context_key['grid']['templates'][$ext_html . ".html"]['all'];
    $block_data    = $context_key['grid']['templates'][$ext_html . ".html"]['blocks'][$block_name];
    $theme_data    = array_merge($grid_all, $ext_html_data, $block_data);
    
    return $theme_data;
}

# Takes hexa color code or defined color name as string and return's RGB values in an array.
function blended_rgbcolor($hex)
{
    
    $color_list = '{
	"aqua": "#00ffff",
	"aquamarine": "#7fffd4",
	"aliceblue": "#f0f8ff",
	"antiquewhite": "#faebd7",
	"azure": "#f0ffff",
	"beige": "#f5f5dc",
	"bisque": "#ffe4c4",
	"black": "#000000",
	"blanchedalmond": "#ffebcd",
	"blue": "#0000ff",
	"blueviolet": "#8a2be2",
	"brown": "#a52a2a",
	"burlywood": "#deb887",
	"cadetblue": "#5f9ea0",
	"chartreuse": "#7fff00",
	"chocolate": "#d2691e",
	"coral": "#ff7f50",
	"cornflowerblue": "#6495ed",
	"cornsilk": "#fff8dc",
	"crimson": "#dc143c",
	"cyan": "#00ffff",
	"darkblue": "#00008b",
	"darkcyan": "#008b8b",
	"darkgoldenrod": "#b8860b",
	"darkgray": "#a9a9a9",
	"darkgrey": "#a9a9a9",
	"darkgreen": "#006400",
	"darkkhaki": "#bdb76b",
	"darkmagenta": "#8b008b",
	"darkolivegreen": "#556b2f",
	"darkorange": "#ff8c00",
	"darkorchid": "#9932cc",
	"darkred": "#8b0000",
	"darksalmon": "#e9967a",
	"darkseagreen": "#8fbc8f",
	"darkslateblue": "#483d8b",
	"darkslategray": "#2f4f4f",
	"darkslategrey": "#2f4f4f",
	"darkturquoise": "#00ced1",
	"darkviolet": "#9400d3",
	"deeppink": "#ff1493",
	"deepskyblue": "#00bfff",
	"dimgray": "#696969",
	"dimgrey": "#696969",
	"dodgerblue": "#1e90ff",
	"firebrick": "#b22222",
	"floralwhite": "#fffaf0",
	"forestgreen": "#228b22",
	"fuchsia": "#ff00ff",
	"gainsboro": "#dcdcdc",
	"ghostwhite": "#f8f8ff",
	"gold": "#ffd700",
	"goldenrod": "#daa520",
	"gray": "#808080",
	"grey": "#808080",
	"green": "#008000",
	"greenyellow": "#adff2f",
	"honeydew": "#f0fff0",
	"hotpink": "#ff69b4",
	"indianred": "#cd5c5c",
	"indigo": "#4b0082",
	"ivory": "#fffff0",
	"khaki": "#f0e68c",
	"lavender": "#e6e6fa",
	"lavenderblush": "#fff0f5",
	"lawngreen": "#7cfc00",
	"lemonchiffon": "#fffacd",
	"lightblue": "#add8e6",
	"lightcoral": "#f08080",
	"lightcyan": "#e0ffff",
	"lightgoldenrodyellow": "#fafad2",
	"lightgray": "#d3d3d3",
	"lightgrey": "#d3d3d3",
	"lightgreen": "#90ee90",
	"lightpink": "#ffb6c1",
	"lightsalmon": "#ffa07a",
	"lightseagreen": "#20b2aa",
	"lightskyblue": "#87cefa",
	"lightslategray": "#778899",
	"lightslategrey": "#778899",
	"lightsteelblue": "#b0c4de",
	"lightyellow": "#ffffe0",
	"lime": "#00ff00",
	"limegreen": "#32cd32",
	"linen": "#faf0e6",
	"magenta": "#ff00ff",
	"maroon": "#800000",
	"mediumaquamarine": "#66cdaa",
	"mediumblue": "#0000cd",
	"mediumorchid": "#ba55d3",
	"mediumpurple": "#9370db",
	"mediumseagreen": "#3cb371",
	"mediumslateblue": "#7b68ee",
	"mediumspringgreen": "#00fa9a",
	"mediumturquoise": "#48d1cc",
	"mediumvioletred": "#c71585",
	"midnightblue": "#191970",
	"mintcream": "#f5fffa",
	"mistyrose": "#ffe4e1",
	"moccasin": "#ffe4b5",
	"navajowhite": "#ffdead",
	"navy": "#000080",
	"oldlace": "#fdf5e6",
	"olive": "#808000",
	"olivedrab": "#6b8e23",
	"orange": "#ffa500",
	"orangered": "#ff4500",
	"orchid": "#da70d6",
	"palegoldenrod": "#eee8aa",
	"palegreen": "#98fb98",
	"paleturquoise": "#afeeee",
	"palevioletred": "#db7093",
	"papayawhip": "#ffefd5",
	"peachpuff": "#ffdab9",
	"peru": "#cd853f",
	"pink": "#ffc0cb",
	"plum": "#dda0dd",
	"powderblue": "#b0e0e6",
	"purple": "#800080",
	"red": "#ff0000",
	"rosybrown": "#bc8f8f",
	"royalblue": "#4169e1",
	"saddlebrown": "#8b4513",
	"salmon": "#fa8072",
	"sandybrown": "#f4a460",
	"seagreen": "#2e8b57",
	"seashell": "#fff5ee",
	"sienna": "#a0522d",
	"silver": "#c0c0c0",
	"skyblue": "#87ceeb",
	"slateblue": "#6a5acd",
	"slategray": "#708090",
	"slategrey": "#708090",
	"snow": "#fffafa",
	"springgreen": "#00ff7f",
	"steelblue": "#4682b4",
	"tan": "#d2b48c",
	"teal": "#008080",
	"thistle": "#d8bfd8",
	"tomato": "#ff6347",
	"turquoise": "#40e0d0",
	"violet": "#ee82ee",
	"wheat": "#f5deb3",
	"white": "#ffffff",
	"whitesmoke": "#f5f5f5",
	"yellow": "#ffff00",
	"yellowgreen": "#9acd32"
    }';
    $color_list = json_decode($color_list, true);
    
    $hex_r = 0;
    $hex_g = 0;
    $hex_b = 0;
    
    if (is_array($hex) && count($hex) == 3) {
        if (($hex[0] >= 0 && $hex[0] <= 255) && ($hex[1] >= 0 && $hex[1] <= 255) && ($hex[2] >= 0 && $hex[2] <= 255)) {
            return $hex;
        } else {
            # if any of values are over limit 255 or below 0, it will be counted as invalide arguments passed and returns black RGB color value.
            return $rgbcolor = array(
                0,
                0,
                0
            );
        }
    } else if ($hex instanceof \Twig_Markup) {
        $hex = (string) $hex;
    } else if (is_string($hex) && isset($color_list[$hex])) {
        $hex = $color_list[$hex];
    }
    
    if (is_string($hex)) {
        
        if (strstr($hex, '#')) {
            $hex = str_replace("#", "", $hex);
        }
        
        if (strlen($hex) == 3 && preg_match(HEX_COLOR_RE_WITHOUT_HASH, $hex)) {
            $hex_r = hexdec(substr($hex, 0, 1) . substr($hex, 0, 1));
            $hex_g = hexdec(substr($hex, 1, 1) . substr($hex, 1, 1));
            $hex_b = hexdec(substr($hex, 2, 1) . substr($hex, 2, 1));
            
        } else if (strlen($hex) == 6 && preg_match(HEX_COLOR_RE_WITHOUT_HASH, $hex)) {
            $hex_r = hexdec(substr($hex, 0, 2));
            $hex_g = hexdec(substr($hex, 2, 2));
            $hex_b = hexdec(substr($hex, 4, 2));
        }
        
        $rgbcolor = array(
            $hex_r,
            $hex_g,
            $hex_b
        );
        
        return $rgbcolor; // returns an array with the rgb values
    }
}

# Takes RGB color array and return's hexa color value.
function blended_hexcolor($rgb)
{
    if (!is_array($rgb)) {
        $rgb = blended_rgbcolor($rgb);
    }
    if (is_array($rgb) && count($rgb) == 3) {
        if (($rgb[0] >= 0 && $rgb[0] <= 255) && ($rgb[1] >= 0 && $rgb[1] <= 255) && ($rgb[2] >= 0 && $rgb[2] <= 255)) {
            
            $hex = "#";
            $hex .= str_pad(dechex($rgb[0]), 2, "0", STR_PAD_LEFT);
            $hex .= str_pad(dechex($rgb[1]), 2, "0", STR_PAD_LEFT);
            $hex .= str_pad(dechex($rgb[2]), 2, "0", STR_PAD_LEFT);
            
            # make hexa color value to Capital case.
            return strtoupper($hex); // returns the hex value including the number sign (#)
            
        } else {
            
            return '#000000';
        }
    }
}

# Calculates average of two RGB colors.
function rgb_avg($first_color, $second_color, $factor = 0.5)
{
    # get the average RGB values.
    
    $r_avg = floor($first_color[0] * (1 - $factor) + $second_color[0] * $factor);
    $g_avg = floor($first_color[1] * (1 - $factor) + $second_color[1] * $factor);
    $b_avg = floor($first_color[2] * (1 - $factor) + $second_color[2] * $factor);
    
    # construct the result color.
    
    $color_avg = '#' . sprintf("%02s", dechex($r_avg)) . sprintf("%02s", dechex($g_avg)) . sprintf("%02s", dechex($b_avg));
    $avg_str   = array(
        $r_avg,
        $g_avg,
        $b_avg
    );
    # return $color_avg;
    return $avg_str;
}

# Returns Current Date-Time.
function blended_now()
{
    return new \DateTime(date('m/d/Y h:i:s a', time()));
}

# Calculates a mean value from array values.
function blended_mean($mean_value)
{
    if (is_array($mean_value)) {
        return array_sum($mean_value) / count($mean_value);
    }
}

function blended_common_mark(Twig_Environment $env, $string)
{
    
    $string = blended_escape_filter($env, $string);
    if (function_exists('commonmark')) {
        $string = commonmark($string);
        return $string;
    }
    
}

/**
 * Get hash value of a package
 * @global object $context
 * @param string $self
 * @param string $prefix
 * @return string
 */
function blended_hash($self, $prefix = null) {
    if ($self):
        try {
            $prefix = !$prefix ? "layout_" : $prefix;

            //Remove space from prefix
            $prefix = str_replace(" ", "_", $prefix);

            //First character should be alphabet or "_"
            if (!preg_match("/^[a-z_]$/i", substr($prefix, 0, 1)))
                throw new \Exception("Argument second should start with alphabet or underscore for hash().");
            else
                $result = $prefix . md5(serialize($self));
        } catch (\Exception $e) {
            $result = $e->getMessage();
        }
        return $result;
    endif;
}


/**
 * Get block data
 * @param array $theme_object
 * @param string $block
 * @param string $template
 * @return boolean | array
 */
function blended_block_data(array $theme_object, $block, $template = null) {

    //Check required parameters
    if (empty($theme_object) || empty($block))
        return false;

    //Set default block data
    $all = $theme_object['meta']['grid']['all'];
    
    //Set template data
    $template_all = $template && isset( $theme_object['meta']['grid']['templates'][$template . ".html"]) ? $theme_object['meta']['grid']['templates'][$template . ".html"]['all'] : array();
    $template_block = $template && isset( $theme_object['meta']['grid']['templates'][$template . ".html"]['blocks'][$block]) ? $theme_object['meta']['grid']['templates'][$template . ".html"]['blocks'][$block] : array();


    //Set block data
    $block_data = isset($theme_object['meta']['grid']['blocks'][$block]) ? $theme_object['meta']['grid']['blocks'][$block] : array();
    
    //Set grid meta data
    $grid_data = array_merge($all, $block_data, $template_all, $template_block);
    
    //Theme palatte data
    $palette_data = $theme_object['meta']['config']['palette'];
    
    //Set inverse attribute
   // $grid_data['inverse'] = (bool) ( $grid_data['inverse'] ^ $palette_data['inverse'] );

    //We are done!
    return  $grid_data;
}
