/**
 * Copyright (c) 2005 - 2009, James Auldridge
 * All rights reserved.
 *
 * Licensed under the BSD, MIT, and GPL (your choice!) Licenses:
 *  http://code.google.com/p/cookies/wiki/License
 *
 */
var jaaulde = window.jaaulde || {};
jaaulde.utils = jaaulde.utils || {};
jaaulde.utils.cookies = ( function()
{
        var cookies = [];

        var defaultOptions = {
                hoursToLive: null,
                path: '/',
                domain:  null,
                secure: false
        };
        /**
         * resolveOptions - receive an options object and ensure all options are present and valid, replacing with defaults where necessary
         *
         * @access private
         * @static
         * @parameter Object options - optional options to start with
         * @return Object complete and valid options object
         */
        var resolveOptions = function( options )
        {
                var returnValue;

                if( typeof options !== 'object' || options === null )
                {
                        returnValue = defaultOptions;
                }
                else
                {
                        returnValue = {
                                hoursToLive: ( typeof options.hoursToLive === 'number' && options.hoursToLive !== 0 ? options.hoursToLive : defaultOptions.hoursToLive ),
                                path: ( typeof options.path === 'string' && options.path !== '' ? options.path : defaultOptions.path ),
                                domain: ( typeof options.domain === 'string' && options.domain !== '' ? options.domain : defaultOptions.domain ),
                                secure: ( typeof options.secure === 'boolean' && options.secure ? options.secure : defaultOptions.secure )
                        };
                }

                return returnValue;
        };
        /**
         * expiresGMTString - add given number of hours to current date/time and convert to GMT string
         *
         * @access private
         * @static
         * @parameter Integer hoursToLive - number of hours for which cookie should be valid
         * @return String - GMT time representing current date/time plus number of hours given
         */
        var expiresGMTString = function( hoursToLive )
        {
                var dateObject = new Date();
                dateObject.setTime( dateObject.getTime() + ( hoursToLive * 60 * 60 * 1000 ) );

                return dateObject.toGMTString();
        };
        /**
         * assembleOptionsString - analyze options and assemble appropriate string for setting a cookie with those options
         *
         * @access private
         * @static
         * @parameter Object options - optional options to start with
         * @return String - complete and valid cookie setting options
         */
        var assembleOptionsString = function( options )
        {
                options = resolveOptions( options );

                return (
                        ( typeof options.hoursToLive === 'number' ? '; expires=' + expiresGMTString( options.hoursToLive ) : '' ) +
                        '; path=' + options.path +
                        ( typeof options.domain === 'string' ? '; domain=' + options.domain : '' ) +
                        ( options.secure === true ? '; secure' : '' )
                );
        };
        /**
         * splitCookies - retrieve document.cookie string and break it into a hash
         *
         * @access private
         * @static
         * @return Object - hash of cookies from document.cookie
         */
        var splitCookies = function()
        {
                cookies = {};
                var pair, name, value, separated = document.cookie.split( ';' );
                for( var i = 0; i < separated.length; i = i + 1 )
                {
                        pair = separated[i].split( '=' );
                        name = pair[0].replace( /^\s*/, '' ).replace( /\s*$/, '' );
                        value = decodeURIComponent( pair[1] );
                        cookies[name] = value;
                }
                return cookies;
        };

        var constructor = function(){};
        
        /**
         * get - get one, several, or all cookies
         *
         * @access public
         * @paramater Mixed cookieName - String:name of single cookie; Array:list of multiple cookie names; Void (no param):if you want all cookies
         * @return Mixed - String:if single cookie requested and found; Null:if single cookie requested and not found; Object:hash of multiple or all cookies
         */
        constructor.prototype.get = function( cookieName )
        {
                var returnValue;
                
                splitCookies();

                if( typeof cookieName === 'string' )
                {
                        returnValue = ( typeof cookies[cookieName] !== 'undefined' ) ? cookies[cookieName] : null;
                }
                else if( typeof cookieName === 'object' && cookieName !== null )
                {
                        returnValue = {};
                        for( var item in cookieName )
                        {
                                if( typeof cookies[cookieName[item]] !== 'undefined' )
                                {
                                        returnValue[cookieName[item]] = cookies[cookieName[item]];
                                }
                                else
                                {
                                        returnValue[cookieName[item]] = null;
                                }
                        }
                }
                else
                {
                        returnValue = cookies;
                }

                return returnValue;
        };
        /**
         * filter - get array of cookies whose names match the provided RegExp
         *
         * @access public
         * @paramater Object RegExp - The regular expression to match against cookie names
         * @return Mixed - Object:hash of cookies whose names match the RegExp
         */
        constructor.prototype.filter = function( cookieNameRegExp )
        {
                var returnValue = {};

                splitCookies();

                if( typeof cookieNameRegExp === 'string' )
                {
                        cookieNameRegExp = new RegExp( cookieNameRegExp );
                }

                for( var cookieName in cookies )
                {
                        if( cookieName.match( cookieNameRegExp ) )
                        {
                                returnValue[cookieName] = cookies[cookieName];
                        }
                }

                return returnValue;
        };
        /**
         * set - set or delete a cookie with desired options
         *
         * @access public
         * @paramater String cookieName - name of cookie to set
         * @paramater Mixed value - Null:if deleting, String:value to assign cookie if setting
         * @paramater Object options - optional list of cookie options to specify (hoursToLive, path, domain, secure)
         * @return void
         */
        constructor.prototype.set = function( cookieName, value, options )
        {
                if( typeof value === 'undefined' || value === null )
                {
                        if( typeof options !== 'object' || options === null )
                        {
                                options = {};
                        }
                        value = '';
                        options.hoursToLive = -8760;
                }
                
                var optionsString = assembleOptionsString( options );

                document.cookie = cookieName + '=' + encodeURIComponent( value ) + optionsString;
        };
        /**
         * del - delete a cookie (domain and path options must match those with which the cookie was set; this is really an alias for set() with parameters simplified for this use)
         *
         * @access public
         * @paramater MIxed cookieName - String name of cookie to delete, or Bool true to delete all
         * @paramater Object options - optional list of cookie options to specify ( path, domain )
         * @return void
         */
        constructor.prototype.del = function( cookieName, options )
        {
                var allCookies = {};

                if( typeof options !== 'object' || options === null )
                {
                        options = {};
                }

                if( typeof cookieName === 'boolean' && cookieName === true )
                {
                        allCookies = this.get();
                }
                else if( typeof cookieName === 'string' )
                {
                        allCookies[cookieName] = true;
                }

                for( var name in allCookies )
                {
                        if( typeof name === 'string' && name !== '' )
                        {
                                this.set( name, null, options );
                        }
                }
        };
        /**
         * test - test whether the browser is accepting cookies
         *
         * @access public
         * @return Boolean
         */
        constructor.prototype.test = function()
        {
                var returnValue = false, testName = 'cT', testValue = 'data';

                this.set( testName, testValue );

                if( this.get( testName ) === testValue )
                {
                        this.del( testName );
                        returnValue = true;
                }

                return returnValue;
        };
        /**
         * setOptions - set default options for calls to cookie methods
         *
         * @access public
         * @param Object options - list of cookie options to specify (hoursToLive, path, domain, secure)
         * @return void
         */
        constructor.prototype.setOptions = function( options )
        {
                if( typeof options !== 'object' )
                {
                        options = null;
                }

                defaultOptions = resolveOptions( options );
        };

        return new constructor();
} )();

( function()
{
        if( window.jQuery )
        {
                ( function( $ )
                {
                        $.cookies = jaaulde.utils.cookies;

                        var extensions = {
                                /**
                                 * $( 'selector' ).cookify - set the value of an input field or the innerHTML of an element to a cookie by the name or id of the field or element
                                 *                           (radio and checkbox not yet supported)
                                 *                           (field or element MUST have name or id attribute)
                                 *
                                 * @access public
                                 * @param Object options - list of cookie options to specify
                                 * @return Object jQuery
                                 */
                                cookify: function( options )
                                {
                                        return this.each( function()
                                        {
                                                var i, resolvedName = false, resolvedValue = false, name = '', value = '', nameAttrs = ['name', 'id'], nodeName, inputType;

                                                for( i in nameAttrs )
                                                {
                                                        if( ! isNaN( i ) )
                                                        {
                                                                name = $( this ).attr( nameAttrs[ i ] );
                                                                if( typeof name === 'string' && name !== '' )
                                                                {
                                                                        resolvedName = true;
                                                                        break;
                                                                }
                                                        }
                                                }

                                                if( resolvedName )
                                                {
                                                        nodeName = this.nodeName.toLowerCase();
                                                        if( nodeName !== 'input' && nodeName !== 'textarea' && nodeName !== 'select' && nodeName !== 'img' )
                                                        {
                                                                value = $( this ).html();
                                                                resolvedValue = true;
                                                        }
                                                        else
                                                        {
                                                                inputType = $( this ).attr( 'type' );
                                                                if( typeof inputType === 'string' && inputType !== '' )
                                                                {
                                                                        inputType = inputType.toLowerCase();
                                                                }
                                                                if( inputType !== 'radio' && inputType !== 'checkbox' )
                                                                {
                                                                        value = $( this ).val();
                                                                        resolvedValue = true;
                                                                }
                                                        }
                                                        
                                                        if( resolvedValue )
                                                        {
                                                                if( typeof value !== 'string' || value === '' )
                                                                {
                                                                        value = null;
                                                                }
                                                                $.cookies.set( name, value, options );
                                                        }
                                                }
                                        } );
                                },
                                /**
                                 * $( 'selector' ).cookieFill - set the value of an input field or the innerHTML of an element from a cookie by the name or id of the field or element
                                 *
                                 * @access public
                                 * @return Object jQuery
                                 */
                                cookieFill: function()
                                {
                                        return this.each( function()
                                        {
                                                var i, resolvedName = false, name = '', value, nameAttrs = ['name', 'id'], iteration = 0, nodeName;

                                                for( i in nameAttrs )
                                                {
                                                        if( ! isNaN( i ) )
                                                        {
                                                                name = $( this ).attr( nameAttrs[ i ] );
                                                                if( typeof name === 'string' && name !== '' )
                                                                {
                                                                        resolvedName = true;
                                                                        break;
                                                                }
                                                        }
                                                }

                                                if( resolvedName )
                                                {
                                                        value = $.cookies.get( name );
                                                        if( value !== null )
                                                        {
                                                                nodeName = this.nodeName.toLowerCase();
                                                                if( nodeName === 'input' || nodeName === 'textarea' || nodeName === 'select' )
                                                                {
                                                                    $( this ).val( value );
                                                                }
                                                                else
                                                                {
                                                                        $( this ).html( value );
                                                                }
                                                        }
                                                }

                                                iteration = 0;
                                        } );
                                },
                                /**
                                 * $( 'selector' ).cookieBind - call cookie fill on matching elements, and bind their change events to cookify()
                                 *
                                 * @access public
                                 * @param Object options - list of cookie options to specify
                                 * @return Object jQuery
                                 */
                                cookieBind: function( options )
                                {
                                        return this.each( function()
                                        {
                                                $( this ).cookieFill().change( function()
                                                {
                                                        $( this ).cookify( options );
                                                } );
                                        } );
                                }
                        };

                        $.each( extensions, function( i )
                        {
                                $.fn[i] = this;
                        } );

                } )( window.jQuery );
        }
} )();

