

// if a string is valid urlsafe base64 ( and of a certain size, if specified )
function is_valid_base64 ( str, length ) {

	 // if we weren't passed a length parameter
    if ( arguments.length != 2 )
		  length = -1 ;

	 // all valid urlsafe base64 characters
	 var urlsafe_base64_str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" ;

	 // if a length argument was passed in and the lengths don't match
	 if ( length != -1 && str.length != length )
		  return false ;

	 // if the string is base64 encoded
	 for ( var i = 0; i < str.length; i++ )
		  if ( urlsafe_base64_str.indexOf( str.charAt( i ) ) == -1 )
				return false ;

	 // default return of true
	 return true ;

}


// returns an object container all of the url parameters as key/value pairs
function get_urlparamobj ( url ) {

	 // url parameter object to return
	 var urlparams = new Object ;

	 // grab the query string
	 var query = urlparse.urlsplit( url ).query ;
	 if ( query == '' )
		  return new Object ;

	 // get each url argument
	 var urlargs = query.split( '&' )
	 for ( var i = 0; i < urlargs.length; i++ ) {

		  // split this argument
		  var urlarg_pair = urlargs[ i ].split( '=' ) ;
		  if ( urlarg_pair.length != 2 )
				continue ;

		  // add this url parameter key/value pair
		  urlparams[ urlarg_pair[ 0 ] ] = urlarg_pair[ 1 ] ;

	 }

	 // return the url parameters object
	 return urlparams ;

}


// construct a url parameter string from an object of parameter names and values
//   if the values in this object are not url encoded, then the string might be mal-formatted
//   it is the user of this function's responsibility to make sure all names and values are properly url encoded
function url_construct_paramstr ( paramobj ) {
	 var paramstr = '' ; // the parameter string, like '?foo=a&blah=b'

	 // construct this parameter string
	 for ( var key in paramobj )
		  paramstr += '&' + key + '=' + paramobj[ key ] ;
	 
	 // replace the first '&' with ? and return the parameter string
	 if ( paramstr.length > 0 )
		  paramstr = '?' + paramstr.substring( 1 ) ; // replace the first '&' with '?'

	 return paramstr ;
}


// returns a url parameter parameter's value when passed its name
// if the url parameter doesnt exist, returns ''
//   ex: get_url_param( 'foo' ) returns 'asdf' when the window.location.href is 'www.blah.com?foo=asdf'
//   this function taken and modified from: http://www.netlobo.com/url_query_string_javascript.html
function get_url_param ( name ) {
	 name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
	 var regexS = "[\\?&]"+name+"=([^&#]*)";
	 var regex = new RegExp( regexS );
	 var results = regex.exec( window.location.href );
	 if( results == null )
		  return "";
	 else
		  return results[1];
}


// returns an array list of all of the url parameters
function get_url_params () {
	 var params = new Array( );
	 var regex = /[\?&]([^=]+)=/g;
	 while( ( results = regex.exec( window.location.href ) ) != null )
		 params.push( results[1] );
	 return params;
}


// sets (changes or adds) a url parameter of a url string
//   if the url doesnt have that url parameter originally, it is added
function url_setparam ( url, name, val ) {
	 var mainurl = '' ; // the base url, like 'http://dirpy.com/studio/'. no url parameters, no site anchor
	 var siteanchor = '' ; // the site anchor, like '#anchorme'

	 // get any url anchor
	 var urlhalfs = url.split( "#" ) ;
	 if ( urlhalfs.length >= 2 ) {
		  url = urlhalfs[ 0 ] ; // only care about everything before the site anchor now
		  for ( var i = 1; i < urlhalfs.length; i++ ) // assemble the site anchor string
				siteanchor += urlhalfs[ i ] ;
	 }

	 // get everything before the parameters ( split by '?' )
	 urlhalfs = url.split( '?' ) ;
	 if ( urlhalfs.length > 0 )
		  mainurl = urlhalfs[ 0 ] ;

	 // get the parameters for this url
	 params = get_urlparamobj( url ) ;

	 // set this parameters value
	 params[ name ] = val ;

	 // construct the url parameter string
	 paramstr = url_construct_paramstr( params ) ;

	 // return the fully reconstructed url ( main url + params + site anchor )
	 return mainurl + paramstr + siteanchor ;

}



// returns the highest order directory in a url
// e.g. when passed "http:// www.foo.com/dir/boo/blah.html" returns "http:// www.foo.com/dir/boo/" 
function highest_order_url_dir ( str ) {
	 // find the last '/' in the string
	 var loc ;
  
	 loc = str.lastIndexOf ( "/" ) ;

	 // if it wasn't found, return the original string
	 // or the first / of the protocol string was found
	 if ( loc == -1 ||
			loc == protocol_end_pos ( str ) ) {
		  return str ;
	 }

	 // if it exists, return that highest order dir url
	 return str.substring( 0, loc + 1 ) ;
}


// returns whether or not a string is a valid open directory title
// e.g. "Index of /foo" is a valid html directory title and "This my homepage" is not
// worthy links have their anchor content text begin with:
//    "Index of /" 
//    or "Index of ./" 
//    or "Index of ../" 
//    BUT NOT "Index of /resources", "Index of ./resources", or "Index of ../resources"
function is_valid_html_dir_title ( str ) {
    // test this anchor's content text
    if (
        // shorter than 10 characters ( smaller than "Index of /", the shortest valid title )
        ( str.length < 10 ) ||
				
		  (   // doesn't start with "Index of /"
				str.substring( 0, 10 ) != "Index of /" &&

				// doesnt start with "Index of ./"
				str.substring( 0, 11 ) != "Index of ./" &&

				// doesnt start with "Index of ../"
				str.substring( 0, 12 ) != "Index of ../" ) ||

        // starts with "Index of /resources"
        ( str.length >= 19 &&
          str.substring( 0, 19 ) == "Index of /resources" ) ||

        // starts with "Index of ./resources"
        ( str.length >= 20 &&
          str.substring( 0, 20 ) == "Index of ./resources" ) ||

        // starts with "Index of /resources"
        ( str.length >= 21 &&
          str.substring( 0, 21 ) == "Index of ../resources" ) ) {
  
        // invalid url directory title
        return false ;
    }

    // valid url directory title
    return true ;
}




// javascript urlparse - analog of python's urlparse
//   taken and modified from http://code.google.com/p/stringencoders/source/browse/trunk/javascript/urlparse.js
//
//	the common urlparse.urlsplit(...) takes a url formatted like
//
//   scheme://netloc/path;parameters?query#fragment
//
// and returns a javascript object with those same fields
//
//   scheme, netloc, hostname, port, path, query, fragment
//
//
// python's urlparse docs may also be helpful - http://docs.python.org/library/urlparse.html
//
var urlparse = {};
urlparse.urldefrag = function(url)
{
    var idx = url.indexOf('#');
    if (idx == -1) {
        return [ url, '' ];
    } else {
        return [ url.substr(0,idx), url.substr(idx+1) ];
    }
}

urlparse.urlsplit = function(url, default_scheme, allow_fragments)
{
    if (typeof allow_fragments === 'undefined') {
        allow_fragments = true;
    }

    // scheme (optional), host, port
    var fullurl = /^([A-Za-z]+)?(:?\/\/)([0-9.\-A-Za-z]*)(?::(\d+))?(.*)$/;
    // path, query, fragment
    var parse_leftovers = /([^?#]*)?(?:\?([^#]*))?(?:#(.*))?$/;

    var o = {};

    var parts = url.match(fullurl);
    if (parts) {
        o.scheme = parts[1] || default_scheme || '';
        o.hostname = parts[3].toLowerCase() || '';
        o.port = parseInt(parts[4],10) || '';
        // Probably should grab the netloc from regexp
        //  and then parse again for hostname/port

        o.netloc = parts[3];
        if (parts[4]) {
            o.netloc += ':' + parts[4];
        }

        var leftover = parts[5];
    } else {
        o.scheme = default_scheme || '';
        o.netloc = '';
        o.hostname = '';
        var leftover = url;
    }
    o.scheme = o.scheme.toLowerCase();

    parts = leftover.match(parse_leftovers);

    o.path =  parts[1];
    o.query = parts[2] || '';

    if (allow_fragments) {
        o.fragment = parts[3] || '';
    } else {
        o.fragment = '';
    }

    return o;
}

urlparse.urlunsplit = function(o) {
    var s = '';
    if (o.scheme) {
        s += o.scheme + '://';
    }

    if (o.netloc) {
        if (s == '') {
            s += '//';
        }
        s +=  o.netloc;
    } else if (o.hostname) {
        // extension.  Python only uses netloc
        if (s == '') {
            s += '//';
        }
        s += o.hostname;
        if (o.port) {
            s += ':' + o.port;
        }
    }

    if (o.path) {
        s += o.path;
    }

    if (o.query) {
        s += '?' + o.query;
    }
    if (o.fragment) {
        s += '#' + o.fragment;
    }
    return s;
}

urlparse.urljoin = function(base, url, allow_fragments)
{
    if (typeof allow_fragments === 'undefined') {
        allow_fragments = true;
    }

    var url_parts = urlparse.urlsplit(url);

    // if url parts has a scheme (i.e. absolute)
    // then nothing to do
    if (url_parts.scheme) {
        if (! allow_fragments) {
            return url;
        } else {
            return urlparse.urldefrag(url)[0];
        }
    }
    var base_parts = urlparse.urlsplit(base);


    // copy base, only if not present
    if (!base_parts.scheme) {
        base_parts.scheme = url_parts.scheme;
    }

    // copy netloc, only if not present
    if (!base_parts.netloc || !base_parts.hostname) {
        base_parts.netloc = url_parts.netloc;
        base_parts.hostname = url_parts.hostname;
        base_parts.port = url_parts.port;
    }

    // paths
    if (url_parts.path.length > 0) {
        if (url_parts.path.charAt(0) == '/') {
            base_parts.path = url_parts.path;
        } else {
            // relative path.. get rid of "current filename" and
            //   replace.  Same as var parts =
            //   base_parts.path.split('/'); parts[parts.length-1] =
            //   url_parts.path; base_parts.path = parts.join('/');
            var idx = base_parts.path.lastIndexOf('/');
            if (idx == -1) {
                base_parts.path = url_parts.path;
            } else {
                base_parts.path = base_parts.path.substr(0,idx) + '/' +
                    url_parts.path;
            }
        }
    }

    //
    // NORMALIZE PATH with "../" and "./"
    //   http://en.wikipedia.org/wiki/URL_normalization
    //   http://tools.ietf.org/html/rfc3986#section-5.2.3
    var parts = base_parts.path.split('/');

    var newparts = [];
    // make sure path always starts with '/'
    if (parts[0] != '') {
        newparts.push('');
    }

    for (var i = 0; i < parts.length; ++i) {
        if (parts[i] === '..') {
            if (newparts.length > 1) {
                newparts.pop();
            } else {
                newparts.push(parts[i]);
            }
        } else if (parts[i] != '.') {
            newparts.push(parts[i]);
        }
    }

    base_parts.path = newparts.join('/');

    // copy query string
    base_parts.query = url_parts.query;

    // copy fragments
    if (allow_fragments) {
        base_parts.fragment = url_parts.fragment;
    } else {
        base_parts.fragment = '';
    }

    return urlparse.urlunsplit(base_parts);
}

//
// end of urlparse
//
