<?php namespace App\Support;

use InvalidArgumentException;
use HTMLPurifier_Config;
use HTMLPurifier as Purifier;
use stdClass;

/**
* Transforms values based on array on transformation rules
*/

class Formatter
{
    public function instance()
    {
        return $this;
    }
    
    /**
     * Transforms a value with rules
     *
     * @param  string   $value
     * @param  string|array  $rules
     * @return string
     */
    public function transformItem($value, $rules){
        $rulesList = $rules;
        
        if(empty($value) || !is_string($value)){
            return $value;
        }
        
        if(is_string($rulesList)){
            $rulesList = explode("|", $rules);
        }
        
        if(!is_string($value) || !is_array($rulesList)){
            throw new InvalidArgumentException("The value must be a string and the rules must be a string or array");    
        }

        foreach($rulesList as $rule){
            $method = "transform{$this->_parseRule($rule)}";
            
            if(method_exists($this, $method)){
                $value = $this->$method($value);      
            }else{
                $value = $rule($value);    
            }           
        } 
        
        return $value;
    }
    
    
    /**
     * Transforms an array or object with rules
     *
     * @param  array|StdClass   $value
     * @param  array  $rules
     * @return array|StdClass
     */
    public function transformObject($value, $rules){
        if(empty($value)){
            return $value;
        }

        if(!is_array($value) && $value instanceOf stdClass){
            throw new InvalidArgumentException("The value must be an array or a stdClass");        
        }
        
        foreach($rules as $field => $fieldRules){
            if(is_string($fieldRules)){
                $fieldRules = explode("|", $fieldRules);    
            }
            
            if(!is_array($fieldRules)){
                throw new InvalidArgumentException("The rules in the {$field} must be a string or array");        
            }
            
            if(is_array($value) && array_key_exists($field, $value)){
                $value[$field] = $this->transformItem($value[$field], $fieldRules);    
            }elseif($value instanceOf stdClass && isset($value->$field)){
                $value->$field = $this->transformItem($value->$field, $fieldRules);    
            }    
        }
        
        return $value;        
    }
    
    /**
     * Transforms an array (list) of objects or arrays with rules
     *
     * @param  array  $values
     * @param  array  $rules
     * @return array|StdClass
     */
    public function transformList($list, $rules){
        if(empty($list)){
            return $list;
        }

        if(!is_array($list)){
            throw new InvalidArgumentException("The list must be an array");        
        }
        
        foreach($list as $key => $value){
            $list[$key] = $this->transformObject($value, $rules);   
        }
        
        return $list;        
    }
    
    protected function _parseRule($rule){
        return \Str::studly($rule);
    }
    
    
    protected function transformXssClean($value)
    {
        return InputCleaner::xss_clean($value);
    }
    
    protected function transformCsvString($value)
    {
        if (empty($value) || is_array($value)) {
            return $value;
        }
        
        if (!is_string($value)) {
            throw new InvalidArgumentException("The value must be a string");
        }

        return explode(',', preg_replace('/\s+/', '', $value));
    }
    
    protected function transformJsonStringToArray($value)
    {

        if (empty($value) || !is_string($value)) {
            return $value;
        }

        $res = json_decode($value, true);

        if ($res === FALSE) {
            throw new InvalidArgumentException("The value must be a json string");
        }

        return $res;
    }

    protected function transformCommaSeparated($value)
    {
        if (empty($value)) {
            return null;
        }

        $res = explode(',', $value);

        return $res;
    }

    protected function transformUrl($value)
    {
        if (!$value) {
            return null;
        }
        if (substr($value, 0, 7) === "http://" || substr($value, 0, 8) === "https://") {
            return $value;
        }
        return "http://" . $value;
    }

    protected function transformSecureUrl($value)
    {
        if (!$value) {
            return null;
        }
        if (substr($value, 0, 8) === "https://") {
            return $value;
        }
        if (substr($value, 0, 7) === "http://") {
            return 'https://' . substr($value, 8);
        }
        return "https://" . $value;
    }

    protected function transformPartialStrip($value)
    {
        $config = HTMLPurifier_Config::createDefault();
        $config->set('HTML.AllowedElements', array('p', 'br', 'ul', 'ol', 'li', 'strong', 'u', 'em'));
        $config->set('HTML.AllowedAttributes', array()); 
        $config->set('CSS.AllowedProperties', array());
        $purifier = new Purifier($config);
        if (!$value) {
            return null;
        }
        return $purifier->purify($value);
    }

    protected function transformCapitalize($value)
    {
        if (!$value) {
            return null;
        }
        return ucwords($value);
    }
}
