/*
 * @(#) StringUtil.js
 *
 * String Utility package
 * Copyright (c) 2007, 2008 Peter Wall
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

var net;
if (!net)
    net = {};
else if (typeof net != 'object')
    throw new Error('net prefix exists but is not an object');
if (!net.pwall)
    net.pwall = {};
else if (typeof net.pwall != 'object')
    throw new Error('net.pwall prefix exists but is not an object');
if (net.pwall.StringUtil)
    throw new Error('net.pwall.StringUtil already exists');

/*
 * This package consists of a number of functions for general string processing.
 */
net.pwall.StringUtil =  {

    /*
     * Return the input string with special characters escaped for HTML.  If
     * there are no special characters the input string is returned unmodified.
     * Only a small subset of the HTML entity names are implemented here.
     */
    escapeHTML: function(str) {
        if (str == null)
            return null;
        for (var i = 0; i < str.length; ++i) {
            var ch = str.charAt(i);
            if (ch < ' ' && !net.pwall.StringUtil.isSpaceHTML(ch) ||
                    ch == '<' || ch == '>' || ch == '&' || ch == '"' ||
                    ch >= '\u007F') {
                var s = [];
                if (i > 0)
                    s.push(str.substring(0, i));
                for (;;) {
                    if (ch == '<')
                        s.push('&lt;');
                    else if (ch == '>')
                        s.push('&gt;');
                    else if (ch == '&')
                        s.push('&amp;');
                    else if (ch == '"')
                        s.push('&quot;');
                    else if (ch == '\u00A0')
                        s.push('&nbsp;');
                    else if (ch >= ' ' && ch < '\u007F' ||
                            net.pwall.StringUtil.isSpaceHTML(ch))
                        s.push(ch);
                    else if (ch > '\u00A0')
                        s.push('&#', str.charCodeAt(i), ';');
                    if (++i >= str.length)
                        break;
                    ch = str.charAt(i);
                }
                return s.join('');
            }
        }
        return str;
    },

    /*
     * Return true if the character is a space according to the HTML
     * specification.
     */
    isSpaceHTML: function(ch) {
        return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' ||
                ch == '\f' || ch == '\u200B';
    },

    /*
     * Return the input string with special characters escaped for XML.  If
     * there are no special characters the input string is returned unmodified.
     */
    escapeXML: function(str) {
        if (str == null)
            return null;
        for (var i = 0; i < str.length; ++i) {
            var ch = str.charAt(i);
            if (ch < ' ' && !net.pwall.StringUtil.isSpaceXML(ch) || ch == '<' ||
                    ch == '>' || ch == '&' || ch == '"' || ch == '\'' ||
                    ch >= '\u007F') {
                var s = [];
                if (i > 0)
                    s.push(str.substring(0, i));
                for (;;) {
                    if (ch == '<')
                        s.push('&lt;');
                    else if (ch == '>')
                        s.push('&gt;');
                    else if (ch == '&')
                        s.push('&amp;');
                    else if (ch == '"')
                        s.push('&quot;');
                    else if (ch == '\'')
                        s.push('&apos;');
                    else if (ch >= ' ' && ch < '\u007F' ||
                            net.pwall.StringUtil.isSpaceXML(ch))
                        s.push(ch);
                    else if (ch >= '\u007F')
                        s.push('&#', str.charCodeAt(i), ';');
                    if (++i >= str.length)
                        break;
                    ch = str.charAt(i);
                }
                return s.join('');
            }
        }
        return str;
    },

    /*
     * Return true if the character is a space according to the XML
     * specification.
     */
    isSpaceXML: function(ch) {
        return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
    },

    /*
     * Return the input string with special characters escaped for use in a URI.
     * If there are no special characters the input string is returned
     * unmodified.
     */
    escapeURI: function(str) {
        if (str == null)
            return null;
        for (var i = 0; i < str.length; ++i) {
            var ch = str.charAt(i);
            if (!net.pwall.StringUtil.unreservedURI(ch)) {
                var s = [];
                if (i > 0)
                    s.push(str.substring(0, i));
                var hex = '0123456789ABCDEF';
                for (;;) {
                    if (net.pwall.StringUtil.unreservedURI(ch))
                        s.push(ch);
                    else if (ch == ' ')
                        s.push('+');
                    else {
                        var code = str.charCodeAt(i);
                        s.push('%', hex.charAt((code >> 4) & 0xF),
                                hex.charAt(code & 0xF));
                    }
                    if (++i >= str.length)
                        break;
                    ch = str.charAt(i);
                }
                return s.join('');
            }
        }
        return str;
    },

    /*
     * Return true if the character is unreserved for URI usage.
     */
    unreservedURI: function(ch) {
        return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' ||
                ch >= '0' && ch <= '9' || ch == '-' || ch == '.' || ch == '_' ||
                ch == '~';
    }

};
