<?php

/**
 * EXHIBIT A. Common Public Attribution License Version 1.0
 * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the “License”);
 * you may not use this file except in compliance with the License. You may obtain a copy of the License at
 * http://www.oxwall.org/license. The License is based on the Mozilla Public License Version 1.1
 * but Sections 14 and 15 have been added to cover use of software over a computer network and provide for
 * limited attribution for the Original Developer. In addition, Exhibit A has been modified to be consistent
 * with Exhibit B. Software distributed under the License is distributed on an “AS IS” basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language
 * governing rights and limitations under the License. The Original Code is Oxwall software.
 * The Initial Developer of the Original Code is Oxwall Foundation (http://www.oxwall.org/foundation).
 * All portions of the code written by Oxwall Foundation are Copyright (c) 2011. All Rights Reserved.

 * EXHIBIT B. Attribution Information
 * Attribution Copyright Notice: Copyright 2011 Oxwall Foundation. All rights reserved.
 * Attribution Phrase (not exceeding 10 words): Powered by Oxwall community software
 * Attribution URL: http://www.oxwall.org/
 * Graphic Image as provided in the Covered Code.
 * Display of Attribution Information is required in Larger Works which are defined in the CPAL as a work
 * which combines Covered Code or portions thereof with code not governed by the terms of the CPAL.
 */

/**
 * @author Sardar Madumarov <madumarov@gmail.com>
 * @package ow_utilities
 * @since 1.0
 */
class UTIL_HtmlTag
{

    /**
     * Generates and returns HTML tag code.
     *
     * @param string $tag
     * @param array $attrs
     * @param boolean $pair
     * @param string $content
     * @return string
     */
    public static function generateTag( $tag, $attrs = null, $pair = false, $content = null )
    {
        $attrString = '';
        if ( $attrs !== null && !empty($attrs) )
        {
            foreach ( $attrs as $key => $value )
            {
                $attrString .= ' ' . $key . '="' . self::escapeHtmlAttr($value) . '"';
            }
        }

        return $pair ? '<' . $tag . $attrString . '>' . ( $content === null ? '' : $content ) . '</' . $tag . '>' : '<' . $tag . $attrString . ' />';
    }

    /**
     * Generates randow ID for HTML tags.
     *
     * @param string $prefix
     * @return string
     */
    public static function generateAutoId( $prefix = null )
    {
        $prefix = ( $prefix === null ) ? 'auto_id' : trim($prefix);

        return $prefix . '_' . UTIL_String::getRandomString(8, UTIL_String::RND_STR_ALPHA_NUMERIC);
    }
    /**
     * @var Jevix
     */
    private static $jevix;

    /**
     * @return Jevix
     */
    private static function getJevix( $tagList = null, $attrList = null, $blackListMode = false,
        $mediaSrcValidate = true )
    {
        if ( self::$jevix === null )
        {
            require_once OW_DIR_LIB . 'jevix' . DS . 'jevix.class.php';

            self::$jevix = new Jevix();
        }

        $tagRules = array();
        $commonAttrs = array();

        if ( !empty($tagList) )
        {
            foreach ( $tagList as $tag )
            {
                $tagRules[$tag] = array(Jevix::TR_TAG_LIST => true);
            }
        }

        if ( $attrList !== null )
        {
            foreach ( $attrList as $attr )
            {
                if ( strstr($attr, '.') )
                {
                    $parts = explode('.', $attr);

                    $tag = trim($parts[0]);
                    $param = trim($parts[1]);

                    if ( !strlen($tag) || !strlen($attr) )
                    {
                        continue;
                    }

                    if ( $tag === '*' )
                    {
                        $commonAttrs[] = $param;
                        continue;
                    }

                    if ( !isset($tagRules[$tag]) )
                    {
                        $tagRules[$tag] = array(Jevix::TR_TAG_LIST => true);
                    }

                    if ( !isset($tagRules[$tag][Jevix::TR_PARAM_ALLOWED]) )
                    {
                        $tagRules[$tag][Jevix::TR_PARAM_ALLOWED] = array();
                    }

                    $tagRules[$tag][Jevix::TR_PARAM_ALLOWED][$param] = true;
                }
                else
                {
                    $commonAttrs[] = trim($attr);
                }
            }
        }

        $shortTags = array('img', 'br', 'input', 'embed', 'param', 'hr', 'link', 'meta', 'base', 'col');
        foreach ( $shortTags as $shortTag )
        {
            if ( !isset($tagRules[$shortTag]) )
            {
                $tagRules[$shortTag] = array();
            }

            $tagRules[$shortTag][Jevix::TR_TAG_SHORT] = true;
        }

        $cutWithContent = array('script', 'embed', 'object', 'style');

        foreach ( $cutWithContent as $cutTag )
        {
            if ( !isset($tagRules[$cutTag]) )
            {
                $tagRules[$cutTag] = array();
            }

            $tagRules[$cutTag][Jevix::TR_TAG_CUT] = true;
        }

        self::$jevix->blackListMode = $blackListMode;
        self::$jevix->commonTagParamRules = $commonAttrs;
        self::$jevix->tagsRules = $tagRules;
        self::$jevix->mediaSrcValidate = $mediaSrcValidate;
        self::$jevix->mediaValidSrc = BOL_TextFormatService::getInstance()->getMediaResourceList();

        return self::$jevix;
    }

    /**
     * Removes all restricted HTML tags and attributes. Works with white and black lists.
     *
     * @param string $text
     * @param array $tagList
     * @param array $attributeList
     * @param boolean $nlToBr
     * @param boolean $blackListMode
     * @param boolean $autoLink
     *
     * @return string
     */
    public static function stripTags( $text, array $tagList = null, array $attributeList = null, $blackListMode = false,
        $mediaSrcValidate = true )
    {
        // style remove fix
        if ( $blackListMode )
        {
            if ( $tagList === null )
            {
                $tagList = array();
            }

            $tagList[] = 'style';

//            if( $attributeList === null )
//            {
//                $attributeList = array();
//            }
//            
//            $attributeList[] = '*.style';
        }
        else
        {
            if ( is_array($tagList) )
            {
                if ( in_array('style', $tagList) )
                {
                    $tagList = array_diff($tagList, array('style'));
                }
            }

//            if( is_array( $attributeList ) )
//            {
//                foreach ( $attributeList as $key => $item )
//                {
//                    if( strstr($item, 'style') )
//                    {
//                        unset($attributeList[$key]);
//                    }
//                }
//            }
        }
        // fix end

        $jevix = self::getJevix($tagList, $attributeList, $blackListMode, $mediaSrcValidate);
        return $jevix->parse($text);
    }

    /**
     * Removes <script> tags and JS event handlers.
     *
     * @param string $text

     * @return string
     */
    public static function stripJs( $text )
    {
        $tags = array('script');

        $attrs = array(
            'onchange',
            'onclick',
            'ondblclick',
            'onerror',
            'onfocus',
            'onkeydown',
            'onkeypress',
            'onkeyup',
            'onload',
            'onmousedown',
            'onmousemove',
            'onmouseout',
            'onmouseover',
            'onmouseup',
            'onreset',
            'onselect',
            'onsubmit',
            'onunload');

        $jevix = self::getJevix($tags, $attrs, true, false);
        return $jevix->parse($text);
    }

    /**
     * Sanitizes provided html code to escape unclosed tags and params.
     * @param string $text
     * @return string
     */
    public static function sanitize( $text )
    {
        $jevix = self::getJevix(null, null, true, false);
        return $jevix->parse($text);
    }

    /**
     * Replaces all urls with link tags in the provided text.
     *
     * @param string $text
     * @return string
     */
    public static function autoLink( $text )
    {
        $jevix = self::getJevix(array(), array(), true, false);
        $jevix->isAutoLinkMode = true;

        return $jevix->parse($text);
    }

    /**
     * Escape a string for the URI or Parameter contexts. This should not be used to escape
     * an entire URI - only a subcomponent being inserted. The function is a simple proxy
     * to rawurlencode() which now implements RFC 3986 since PHP 5.3 completely.
     *
     * @param string $string
     * @return string
     */
    public static function escapeUrl( $string = null )
    {
        if ( !$string )
        {
            return;
        }

        return rawurlencode($string);
    }

    /**
     * Escape a string for the HTML Body context where there are very few characters
     * of special meaning. Internally this will use htmlspecialchars().
     *
     * @param string $string
     * @return string
     */
    public static function escapeHtml( $string = null )
    {
        if ( !$string )
        {
            return;
        }

        return htmlspecialchars($string, ENT_QUOTES);
    }

    /**
     * Escape a string for the HTML Attribute context. We use an extended set of characters
     * to escape that are not covered by htmlspecialchars() to cover cases where an attribute
     * might be unquoted or quoted illegally (e.g. backticks are valid quotes for IE).
     *
     * @param string $string
     * @return string
     */
    public static function escapeHtmlAttr( $string = null )
    {
        if ( !$string )
        {
            return;
        }

        return htmlspecialchars($string, ENT_COMPAT);
    }

    /**
     * Escapes chars to make sure that string doesn't contain valid JS code
     * 
     * @param string $string
     * @return string
     */
    public static function escapeJs( $string = null )
    {
        if ( !$string )
        {
            return;
        }

        return strtr($string,
            array('\\' => '\\\\', "'" => "\\'", '"' => '\\"', "\r" => '\\r', "\n" => '\\n', '</' => '<\/'));
    }
}
