/**
 * Copyright (c) 2009 Daylife, Inc.  All rights reserved.
 * Daylife Inc. located at 444 Broadway 5th Floor, NY, NY 10013
 *
 * Authors:
 * Scott Blumenthal (blumy) <scott@daylife.com>
 * Samuel Clay <samuel@daylife.com>
 * Pat Hensley <pat@daylife.com>
 */

// ------- CORE EXTENSIONS -------- //

(function($) {
    var _seq = (new Date()).getTime();
    $.extend({

        /*
        HTMLEncode - Encode HTML special characters.
        Copyright (c) 2006 Thomas Peri, http://www.tumuski.com/

        Permission is hereby granted, free of charge, to any person obtaining a
        copy of this software and associated documentation files (the
        "Software"), to deal in the Software without restriction, including
        without limitation the rights to use, copy, modify, merge, publish,
        distribute, sublicense, and/or sell copies of the Software, and to
        permit persons to whom the Software is furnished to do so, subject to
        the following conditions:

        The Software shall be used for Good, not Evil.

        The above copyright notice and this permission notice shall be included
        in all copies or substantial portions of the Software.

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
        OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
        MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
        IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
        CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
        TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
        SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
        */

        /**
         * HTML-Encode the supplied input
         *
         * Parameters:
         *
         * (String)  source    The text to be encoded.
         *
         * (boolean) display   The output is intended for display.
         *
         *                     If true:
         *                     * Tabs will be expanded to the number of spaces
         *                       indicated by the 'tabs' argument.
         *                     * Line breaks will be converted to <br />.
         *
         *                     If false:
         *                     * Tabs and linebreaks get turned into &#____;
         *                       entities just like all other control characters.
         *
         * (integer) tabs      The number of spaces to expand tabs to.  (Ignored
         *                     when the 'display' parameter evaluates to false.)
         *
         * v 0.3 - January 4, 2006
         */
        htmlencode: function(source, display, tabs) {
        	function special(source)
        	{
        		var result = '';
        		for (var i = 0; i < source.length; i++)
        		{
        			var c = source.charAt(i);
        			if (c < ' ' || c > '~')
        			{
        				c = '&#' + c.charCodeAt() + ';';
        			}
        			result += c;
        		}
        		return result;
        	}

        	function format(source)
        	{
        		// Use only integer part of tabs, and default to 4
        		tabs = (tabs >= 0) ? Math.floor(tabs) : 4;

        		// split along line breaks
        		var lines = source.split(/\r\n|\r|\n/);

        		// expand tabs
        		for (var i = 0; i < lines.length; i++)
        		{
        			var line = lines[i];
        			var newLine = '';
        			for (var p = 0; p < line.length; p++)
        			{
        				var c = line.charAt(p);
        				if (c === '\t')
        				{
        					var spaces = tabs - (newLine.length % tabs);
        					for (var s = 0; s < spaces; s++)
        					{
        						newLine += ' ';
        					}
        				}
        				else
        				{
        					newLine += c;
        				}
        			}
        			// If a line starts or ends with a space, it evaporates in html
        			// unless it's an nbsp.
        			newLine = newLine.replace(/(^ )|( $)/g, '&nbsp;');
        			lines[i] = newLine;
        		}

        		// re-join lines
        		var result = lines.join('<br />');

        		// break up contiguous blocks of spaces with non-breaking spaces
        		result = result.replace(/  /g, ' &nbsp;');

        		// tada!
        		return result;
        	}

        	var result = source;

        	// ampersands (&)
        	result = result.replace(/\&/g,'&amp;');

        	// less-thans (<)
        	result = result.replace(/\</g,'&lt;');

        	// greater-thans (>)
        	result = result.replace(/\>/g,'&gt;');

        	if (display)
        	{
        		// format for display
        		result = format(result);
        	}
        	else
        	{
        		// Replace quotes if it isn't for display,
        		// since it's probably going in an html attribute.
        		result = result.replace(new RegExp('"','g'), '&quot;');
        	}

        	// special characters
        	result = special(result);

        	// tada!
        	return result;
        },

        memoization: function(f, scope, postprocessor) {
            function newf() {
                var arg = Array.prototype.splice.call(arguments, 0, arguments.length),
                    args = arg.join("\u25ba");
                newf.cache = newf.cache || {};
                newf.count = newf.count || [];
                if (args in newf.cache) {
                    return postprocessor ? postprocessor(newf.cache[args]) : newf.cache[args];
                }
                if (newf.count.length > 1000) {
                    delete newf.cache[newf.count.unshift()];
                }
                newf.count.push(args);
                newf.cache[args] = f.apply(scope, arg);
                return postprocessor ? postprocessor(newf.cache[args]) : newf.cache[args];
            }
            return newf;
        },

		dlid: function(prefix){
		    prefix = prefix || "dlid_";
			_seq++;
			return prefix + _seq.toString();
		},

		keys: function(obj){
			if($.typeOf(obj) == 'object'){
				var keys = [];
				for(var k in obj){
					keys.push(k);
				}
				return keys;
			}else{
				return false;
			}
		},

		parseSubdomain: function(href){
			var match = href.match('://([^\.]+).');
			if(match && match[1]){
				return match[1];
			}else{
				return false;
			}
		},

		deepCopy: function(obj) {
			var type = $.typeOf(obj);
			switch (type) {
				case 'object':
					var o = {};
					for (key in obj) {
						o[key] = $.deepCopy(obj[key]);
					};
					return o;
				case 'array':
					var a = [];
					for (var i = 0; i < obj.length; i++) {
						a.push($.deepCopy(obj[i]));
					}
					return a;
				default:
					return obj;
			};
		},

		typeOf: function(value) {
		    var s = typeof value;
		    if (s == 'object') {
		        if (value) {
		            if (typeof value.length == 'number' &&
		                !(value.propertyIsEnumerable('length')) &&
		                typeof value.splice == 'function') {
		                    s = 'array';
		            }
		        } else {
		            s = 'null';
		        }
		    }
		    return s;
		},

        addCommas: function(nStr) {
            nStr += '';
            var x = nStr.split('.');
            var x1 = x[0];
            var x2 = x.length > 1 ? '.' + x[1] : '';
            var rgx = /(\d+)(\d{3})/;

            while (rgx.test(x1)) {
                x1 = x1.replace(rgx, '$1' + ',' + '$2');
            }

            return x1 + x2;
        },

		oneTarget: function(e, target_checks, preventDefault, cancelBubbling, stopPropagation){
			// each item in the array target_checks
			// is in the the following format:
			// [ tagSelector, childOf, callback ]

			for(var i=0;i<target_checks.length;i++){
				var opts = {
					'tagSelector': target_checks[i][0],
					'preventDefault': preventDefault,
					'cancelBubbling': cancelBubbling,
					'stopPropagation': stopPropagation
				};
				if(target_checks[i][1]){
					opts.childOf = target_checks[i][1];
				}
				if($.targetIs(e, opts, target_checks[i][2])){
					return opts;
				}
			}
		},

		targetIs: function(e, opts, callback){
			if(!e || !opts){ return false; }
			// defaults
			// (want to make this explicit, since it's a little weird)
			opts = {
				childOf: opts.childOf || null,
				tagSelector: opts.tagSelector || null,
				cancelBubbling: opts.cancelBubbling || false,
				preventDefault: opts.preventDefault || false,
				stopPropagation: opts.stopPropagation || false
			};
			var target = e.target;
			var $t = $(target);
			var $p = null;
			var fails = false;
			if(opts.childOf){
				$p = $t.parents(opts.childOf).eq(0);
				if(!$p[0]){
					fails = true;
				}
			}
			if(opts.tagSelector){
				var ts = opts.tagSelector;
				if(!$t.is(ts)){
					if(opts.cancelBubbling){
						fails = true;
					}else{
						$tp = $t.parents(ts).eq(0);
						if(!$tp[0]){
							fails = true;
						}else{
							// we are going to assume dev
							// wants the $elem we bubbled to
							$t = $tp;
						}
					}
				};
			}
			if(fails){
				return false;
			}else{
				if(callback && typeof callback == 'function'){
					callback($t, $p);
				}
				if(opts.preventDefault){
				    e.preventDefault();
				}
				if(opts.stopPropagation){
				    e.stopPropagation();
				}
				return true;
			}
		},

		make: function(){
			var $elem,text,children,type,name,props;
			var args = arguments;
			var tagname = args[0];
			if(args[1]){
				if (typeof args[1]=='string'){
					text = args[1];
				}else if(typeof args[1]=='object' && args[1].push){
				  children = args[1];
				}else{
					props = args[1];
				}
			}
			if(args[2]){
				if(typeof args[2]=='string'){
					text = args[2];
				}else if(typeof args[1]=='object' && args[2].push){
				  children = args[2];
				}
			}
			if(tagname == 'text' && text){
			    return document.createTextNode(text);
			}else{
    			$elem = $(document.createElement(tagname));
    			if(props){
    				for(var propname in props){
    				  if (props.hasOwnProperty(propname)) {
    				        if($elem.is(':input') && propname == 'value'){
    				            $elem.val(props[propname]);
    				        } else {
    				            $elem.attr(propname, props[propname]);
    				        }
    				        // give ie a hook to style inputs... sigh
    				        if(window.attachEvent && !window.opera){ // is IE7 and down
    				           if($elem.is(':input')){
    				               $elem.addClass('IE-input-' + $elem.attr('type'));
    				           }
    				        }
    					}
    				}
    			}
    			if(children){
    				for(var i=0;i<children.length;i++){
    					if(children[i]){
    						$elem.append(children[i]);
    					}
    				}
    			}
    			if(text){
    				$elem.text(text);
    			}
    			return $elem;
    		}
		},

		hash: function(hash_key, hash_value, options) {
		    var hash = window.location.hash;
		    var hash_array, hash_obj;
		    var options = $.extend({'clear': false}, options);

		    if (typeof hash_key == 'undefined') return hash;
            if (typeof hash_key == 'object') hash_obj = hash_key;

		    hash_array = (hash.length ? $.querystring_to_hash(hash) : {});

		    if (!hash_obj && typeof hash_value == 'undefined') {
		        // Get hash
                return hash_array[hash_key];
		    } else if (hash_obj || (hash_value && hash_key)) {
		        // Set hash

		        if (hash_obj) {
    		        for (h in hash_obj) hash_array[h] = hash_obj[h];
    		        for (a in hash_array) {
    		            if (!(a in hash_obj)) {
    		                DAYLIFE.log(['Removing from hash', a, hash_array, hash_obj]);
    		                delete hash_array[a];
    		            }
    		        }
		        } else {
		            hash_array[hash_key] = hash_value;
		            if (options.clear) {
        		        for (a in hash_array) {
        		            if (a != hash_key) {
        		                DAYLIFE.log(['Removing from hash (key)', a, hash_array, hash_key]);
        		                delete hash_array[a];
        		            }
    		            }
		            }
	            }



		        hash = $.hash_to_querystring(hash_array, false, true);
		        window.location.hash = hash;
		        return hash_value;

		    }
		},

		removeHash: function(hash_key) {
		    var hash = window.location.hash;
		    var hash_array = (hash.length ? $.querystring_to_hash(hash) : {});

            if (hash_key in hash_array) {
    	        delete hash_array[hash_key];
    	        hash = $.hash_to_querystring(hash_array, false, true);
    	        window.location.hash = hash;
            }
	        return;
		},

		serializeSearch: function(){
			return $.querystring_to_hash(window.location.search);
		},

		querystring_to_hash: function(str, hash_key){
			if(str.charAt(0) == '?' || str.charAt(0) == '#'){
				str = str.substr(1);
			}
			var hash = {};
			var kvs = str.split('&');
			for(var i=0, num_kvs=kvs.length; i < num_kvs; i++){
				var kvary = kvs[i].split('=');
				if(kvary && kvary[1]){
					var decoded_value = decodeURIComponent(kvary[1].replace(/\+/g, '%20'));
					var key = kvary[0].replace('[]','');
					if(hash[key] && kvary[0].indexOf('[]') != -1){
						hash[key].push(decoded_value);
					} else if (kvary[0].indexOf('[]') != -1) {
					    hash[key] = [decoded_value];
					} else {
						hash[key] = decoded_value;
					}
				}
			}

			if (hash_key) {
			    return hash[hash_key];
			}

			return hash;
		},

		hash_to_querystring: function(hash, bracket_array_values, is_hash){
			var counter = 0;
			var pieces;

			if (is_hash) {
			    pieces = ['#'];
			} else {
			    pieces = ['?'];
		    }

			for(var key in hash){
			    //DAYLIFE.log(['H2Q', key, typeof hash[key], $.typeOf(hash[key])]);
				if(counter > 0){
					pieces.push('&');
				}
				if(typeof hash[key] == 'string' || typeof hash[key] == 'number'){
					pieces.push(encodeURIComponent(key) + '=' + encodeURIComponent(hash[key]));
				}else if($.typeOf(hash[key]) == 'array'){
					for(var i=0;i<hash[key].length;i++){
						if(i > 0){
							pieces.push('&');
						}
						if(bracket_array_values){
						    pieces.push(encodeURIComponent(key) + '[]=' + encodeURIComponent(hash[key][i]));
						}else{
    						pieces.push(encodeURIComponent(key) + '=' + encodeURIComponent(hash[key][i]));
    					}
					}
				}
				counter++;
			}
			return pieces.join('');
		},

		update_querystring: function(href, update_hash, delete_keys, bracket_array_values){
		    update_hash = update_hash || {};
		    var updated = href;
		    var query_pos = href.indexOf('?');
			if(query_pos == -1){
				updated = href + $.hash_to_querystring(update_hash, bracket_array_values);
			}else{
				var qs = href.substr(query_pos);
				var query_hash = $.querystring_to_hash(qs);
				for(var k in update_hash){
				    if(update_hash[k]){
    				    query_hash[k] = update_hash[k];
    			    }
				}
				if(delete_keys && $.typeOf(delete_keys) == 'array'){
				    for (var i = delete_keys.length - 1; i >= 0; i--){
				        delete query_hash[delete_keys[i]];
				    };
				}
				updated = href.replace(qs, $.hash_to_querystring(query_hash, bracket_array_values));
			}
			return updated;
		},

		rescope: function(func, thisArg){
			return function(a, b, c, d, e, f){
			    // DAYLIFE.log([func, thisArg, this, a, b, c, d, e, f]);
				func.call(thisArg, this, a, b, c, d, e, f);
			};
		},

		topic_url: function(topic_name){
			if (DAYLIFE_Globals.use_hyphens){
				return '/topic/' + encodeURIComponent(topic_name.replace(/\s+/g,'-'));
			}else{
				return '/topic/' + encodeURIComponent(topic_name.replace(/\s+/g,'_'));
			}
		},

		get_standalone_custom_page_asset_name_from_url: function(){
			var match = window.location.href.match(/\page\/([^\?\/]+)/);
			if(match && match[1]){
				return 'daylife.page.custom.' + match[1];
			}else{
				return null;
			}
		},

		avoid_z_collisions: function(check_against, close_function){
			if(!close_function){
				for (var i = _registered_z_collisions.length - 1; i >= 0; i--){
					if (_registered_z_collisions[i]['check_against'] != check_against
					    && $.isFunction(_registered_z_collisions[i]['close_function'])){
						_registered_z_collisions[i]['close_function']
						    .apply(_registered_z_collisions[i]['check_against']);
					}
				};
			}else{
				_registered_z_collisions.push({"check_against": check_against, "close_function": close_function});
			}
		}

	});

	var _registered_z_collisions = [];
})($DL);

// --------- WRAPPED ELEMENT EXTENSIONS --------------- //

(function($) {
	var _$bin;
 	// register jQuery extension
	$.fn.bin = function(){
		if(!_$bin){
			_$bin = $.make('div', { className: 'bin' }).css({
				'visibility': 'hidden',
				'height': 1,
				'width': 1,
				'overflow': 'hidden'
			});
			$('body').append(_$bin);
		}
		this.appendTo(_$bin);
		return this;
	};

    $.fn.sort = function() {
	    return this.pushStack(
	        $DL.makeArray(
	            [].sort.apply( this, arguments )
	        )
	    );
	};

	$.fn.toggleAttr = function(name, a, b){
		(this.attr(name) == a) ? this.attr(name, b) : this.attr(name, a);
		return this;
	};

	$.fn.dlid = function(prefix){
		this.each(function(){
		    $(this).attr('id', $.dlid(prefix));
		});
		return this;
	};

	$.fn.open_externally = function(){
		if(this.is('a')){
			this.click(function(e){
				window.open($(this).attr('href'), $.dlid('daylife_external_'));
				e.preventDefault();
			});
		}
		return this;
	};

	$.fn.flash = function(duration, color){
		duration = duration || 1000;
		color = color || '#ffff27';
		var offset = this.offset();
		var $flasher = $.make('div').css({
			'position': 'absolute',
			'top': offset.top,
			'left': offset.left,
			'zIndex': '10',
			'width': this.width(),
			'height': this.height(),
			'backgroundColor': color,
			'opacity': .7,
			'display': 'none'
		});
		this.parent().append($flasher);
		$flasher.fadeIn(duration, function(){
			$flasher.fadeOut(duration, function(){
				$flasher.remove();
			});
		});
		return this;
	};

	$.fn.clear_default_value = function(default_class){
		default_class = default_class || 'default';
		function clear(e){
			if($(this).hasClass(default_class)){
				$(this).removeClass(default_class).val('');
			}
		}

		function test_query(e){
			var $input_field = $(this).siblings(':text');
			if($input_field.hasClass(default_class) || $input_field.val() == ''){
				$input_field.removeClass(default_class).val('').focus();
				return false;
			}
		}

		if(this.is('form')){
			$(':text, textarea', this).focus(clear);
			$(':submit', this).click(test_query);
		}else if(this.is(':input')){
			this.focus(clear);
		}

		return this;
	};

	$.fn.serializeForm = function(selector){
		var data = {};
		if(this.is('form')){
			selector = selector || ':input';
			$.each($(selector, this), function(){
				var $this = $(this);
				var name = $this.attr('name');
				if(name){
					if($this.is(':checkbox') && name.indexOf('[]')!=-1){
						name = name.replace('[]', '');
						if(!data[name]){
							data[name] = [];
						}
						if($this.attr('checked')){
							data[name].push($this.val());
						}
					}else{
						if($this.is(':checkbox') && !$this.attr('checked')){
							data[name] = ($this.attr('value') == 1) ? 0 : false;
						} else if ($this.is(':radio') && $this.attr('checked')
						      || (!$this.is(':radio') || $this.attr('checked'))) {
						    data[name] = $this.val();
						}
					}
				}
			});
		}
		return data;
	};

	$.fn.unserialize = function(data, callback){
		if(data && this.is('form')){
			for(var name in data){
				var $field = $(':input[name='+name+']', this);
				if($field.length == 0 && $.typeOf(data[name]) == 'array'){
					// see if there are multiple select as checkboxes:
					var $checkboxes = this.find(':checkbox');
					$checkboxes.each(function(){
						var $this = $(this);
						if($this.attr('name') == name+'[]'){
							// alert('is '++' in data[name]?')
							if($.inArray($this.val(), data[name]) != -1){
								$this.attr('checked', true);
							}else{
								$this.attr('checked', false);
							}
						}
					});
				}
				if($field.length > 0){
					if($field.is(':checkbox')){
						if(data[name]===true || data[name]==$field.attr('value')){
							$field.attr('checked', true);
						}else{
							$field.attr('checked', false);
						}
					}else if($field.is(':radio')){
					    var value = data[name];
					    if (value == true) value = '1';
					    if (value == false) value = '0';
						$(':input[name='+name+'][value='+value+']', this).attr('checked', true);
					}else{
						var update_to = data[name];
						if($field.is(':text')){
							if(update_to === null || update_to === false || update_to === true || $.typeOf(update_to) == 'array'){
								update_to = '';
							}
						}
						$field.val(update_to);
					}
				}
			}
		}
		if(callback && typeof callback == 'function'){
			callback(data);
		}
		return data;
	};
})($DL);

// ---------------- SCRIPT INCLUDES -------------------- //

(function($) {
	var _includes = [];

	// possible opts:
	// 'load' - executes only after first include, when script loading is complete
	// 'ready' - added to $(document).ready() only after first include
	// 'reload' - executes only on includes subsequent to the first, after script loading is complete
	// 'complete' - executes after all other callbacks, any time include is called and script loading is complete

	$.extend({
        include: function(path, opts){
            if(!path){
				return false;
			}
			opts = opts || {};
			var included;
			for (var i = _includes.length - 1; i >= 0; i--){
				if(_includes[i].path == path){
					included = _includes[i];
					break;
				}
			};

			if(!included){
				var id = $.dlid();
				included = {
					'path': path,
					'id': id
				};
				var includes_length = _includes.push(included);
				var script_index = includes_length - 1;
				var check_preloaded = (typeof(DAYLIFE_Globals) != 'undefined' && DAYLIFE_Globals.included_js) ? true : false;
				var complete_include = function(){
					included.complete = true;
					if(opts.load && typeof opts.load == 'function'){
						opts.load();
					}
					if(opts.ready && typeof opts.ready == 'function'){
						$(document).ready(opts.ready);
					}
					if(opts.complete && typeof opts.complete == 'function'){
						opts.complete();
					}
				};
				if(!check_preloaded
				    || (check_preloaded
				        && $.inArray(path, DAYLIFE_Globals.included_js) == -1
						&& $.inArray(path, DAYLIFE_Globals.included_smartgalleries_js) == -1
				        && $.inArray(path, DAYLIFE_Globals.included_wizard_js) == -1)){
					included.complete = false;
					$.ajax({
						'type': 'GET',
						'url': path,
						'success': complete_include,
						'dataType': 'script',
						'cache': true
					});
				}else{
					complete_include();
				}
			}else{
				var complete_include = function(){
					if(opts.reload && typeof opts.reload == 'function'){
						opts.reload();
					}
					if(opts.complete && typeof opts.complete == 'function'){
						opts.complete();
					}
				};
				if(opts.reload || opts.complete){
					if(included.complete){
						complete_include();
					}else{
						included.load_interval = window.setInterval(function(){
							if(included.complete){
								window.clearInterval(included.load_interval);
								complete_include();
							}
						}, 1000);
					}
				}
			}
			return included;
		}
    });
})($DL);

// ---------------- GENERIC BINDING -------------------- //

(function($){
    var _bindings = {};
	var _obj_map = {};

	$.extend({
        anybind: function(obj, event, callback){
        	if(!_bindings[event]){
        		_bindings[event] = {};
        	}
        	var id;
        	for(var k in _obj_map){
        		if(_obj_map[k]==obj){
        			id = k;
        			break;
        		}
        	}
        	if(!id){
        		id = $.dlid();
        		_obj_map[id] = obj;
        	}
        	if(!_bindings[event][id]){
        		_bindings[event][id] = [];
        	}
        	var bound = false;
        	for(var i=_bindings[event][id].length; i>=0; i--){
        		if(callback == _bindings[event][id][i]){
        			bound = true;
        			break;
        		}
        	}
        	if(!bound){
        		_bindings[event][id].push(callback);
        	}
        },

        anytrigger: function(obj, event, args){
        	if(_bindings[event]){
        		var id;
        		for(var k in _obj_map){
        			if(_obj_map[k]==obj){
        				id = k;
        				break;
        			}
        		}
        		if(id && _bindings[event][id]){
					args = args || [];
        			for(var i=0;i<_bindings[event][id].length;i++){
        				args.unshift(event);
        				_bindings[event][id][i].apply(obj, args);
        			}
        		}
        	}
        },

        anyunbind: function(obj, event, callback){
        	if(_bindings[event]){
        		var id;
        		for(var k in _obj_map){
        			if(_obj_map[k]==obj){
        				id = k;
        				break;
        			}
        		}
        		if(id  && _bindings[event][id]){
        			for(var i=0;i<_bindings[event][id].length;i++){
        				if(_bindings[event][id][i] == callback){
        					_bindings[event][id].splice(i,1);
        					break;
        				}
        			}
        			if(_bindings[event][id].length == 0){
        				delete _bindings[event][id];
        			}
        		}
        		i = 0;
        		for(var k in _bindings[event]){
        			i++;
        		}
        		if(i == 0){
        			delete _bindings[event];
        		}
        	}
        }
    });
})($DL);

// ---------------- FRAME -------------------- //
(function($){

	var _frame = [
		$.make('div'),
		$.make('div'),
		$.make('div'),
		$.make('div')
	];
	var _framed;
	var _frame_out_timer;
	for (var i = _frame.length - 1; i >= 0; i--){
		_frame[i].css({
			'backgroundColor': '#ffc300',
			'opacity': 0.3,
			'position': 'absolute',
			'zIndex': 800
		});
	};

	$(document).ready(function(){
		for ( var i = 0; i < _frame.length; i++ ) {
			$('body').append(_frame[i]);
		};
	});

	$(window).resize(function(){
		if(_framed){
			_framed.frame();
		}
	});

	var _Frame = function(){};
	_Frame.prototype = {
		nodes: [],
		frame_out_timer: null,
		make_nodes: function(){
			var base_css = {
				'backgroundColor': '#ffc300',
				'opacity': 0.8,
				'position': 'absolute',
				'zIndex': 800
			};
			var $body = $('body');
			this.nodes = [
				$.make('div').css(base_css).appendTo($body),
				$.make('div').css(base_css).appendTo($body),
				$.make('div').css(base_css).appendTo($body),
				$.make('div').css(base_css).appendTo($body)
			];
		}
	};

	$.fn.frame = function(padding, thickness, zindex, use_own_frame){
		var o = this.offset();
		if(o && this.length && this.css('display').toLowerCase() != 'none'){
			var frame = null;
			if(use_own_frame){
				var own_frame = this.data('frame');
				if(!own_frame){
					own_frame = new _Frame();
					own_frame.make_nodes();
					this.data('frame', own_frame);
				}else{
					window.clearTimeout(own_frame.frame_out_timer);
				}
				frame = own_frame.nodes;
			}else{
				frame = _frame;
				window.clearTimeout(_frame_out_timer);
				_framed = this;
			}
			var h = this.outerHeight();
			var w = this.outerWidth();
			var doc_h = $(document).height();
			var doc_w = $(document).width();
			if(padding && typeof padding == 'string'){
				var params = padding.split(' ');
				var last = params.length - 1;
				padding = [];
				var val, px;
				for(var i=0;i<4;i++){
					val = (params[i]) ? params[i] : ((!params[1]) ? params[0] : ((i==2) ? params[0] : params[1]));
					px = parseInt(val);
					padding[i] = px;
				}
			}else{
				padding = [0,0,0,0];
			}
			thickness = thickness || 20;
			zindex = zindex || 800;
			frame[0].css({
				height: thickness,
				width: w + (2 * thickness) + padding[1] + padding[3],
				top: o.top - thickness - padding[0],
				left: o.left  - thickness - padding[3]
			});
			frame[1].css({
				height: h + padding[0] + padding[2],
				width: thickness,
				top: o.top - padding[0],
				left: o.left + w + padding[3]
			});
			frame[2].css({
				height: thickness,
				width: w + (2 * thickness) + padding[1] + padding[3],
				top: o.top + h + padding[2],
				left: o.left  - thickness - padding[3]
			});
			frame[3].css({
				height: h + padding[0] + padding[2],
				width: thickness,
				top: o.top - padding[0],
				left: o.left  - thickness - padding[3]
			});
			for (var i = frame.length - 1; i >= 0; i--){
				frame[i].css({'display': 'block', 'zIndex': zindex});
			};
		}
		return this;
	};

	$.fn.unframe = function(destroy){
		if(this.data('frame')){
			var frame = this.data('frame');
			if(destroy){
				this.removeData('frame');
			}
			frame.frame_out_timer = window.setTimeout(function(){
				for (var i = frame.nodes.length - 1; i >= 0; i--){
					if(destroy){
						frame.nodes[i].remove();
					}else{
						frame.nodes[i].css('display', 'none');
					}
				}
			}, 200);
		}else{
			_frame_out_timer = window.setTimeout(function(){
				_framed = null;
				for (var i = _frame.length - 1; i >= 0; i--){
					_frame[i].css('display', 'none');
				}
			}, 200);
		}
	};

	$.fn.is_framed = function(){
		var framed = (_framed && this.get(0) == _framed.get(0)) ? true : false;
		return framed;
	};

	$.fn.slide_frame = function(top_delta, duration){
		if(this.is_framed()){
		    for (var i = _frame.length - 1; i >= 0; i--){
		      _frame[i].animate({
		          top: parseInt(_frame[i].css('top')) + top_delta
		      }, duration);
		    };
		}
	};
})($DL);

// ------------ CHANGE MONITOR ------------- //

(function($){

	var _monitoring = [];

	function Change_Monitor($form){
		this.success;
		this.failure;
		this.$form = $form;
		this.original_state = $form.serializeForm();
		this.changed = [];
		this.bindings = { // this is so I can UNBIND TOO
			'standard' : $.rescope(this.do_standard_check, this),
			'checkbox': $.rescope(this.do_checkbox_check, this),
			'radio': $.rescope(this.do_radio_check, this)
		};
		this.set_handlers();
	}

	Change_Monitor.prototype = {
		has_changed: function(field_name){
			if(field_name){
				return ($.inArray(field_name, this.changed) != -1);
			}else{
				return this.changed.length > 0;
			}
		},
		serialize_changed: function(){
		    var changes = this.$form.serializeForm();
            for(var k in changes){
                if($.inArray(k, this.changed) == -1){
                    delete changes[k];
                }
            }
            return changes;
		},
		unserialize: function(data){
			this.$form.unserialize(data);
			for(var name in data){
				this.update_changed($(':input[name='+name+']', this.$form), data[name]);
			}
		},
		restore: function(){
		    this.$form.unserialize(this.original_state);
		    this.changed = [];
		},
		reset: function(){
			this.original_state = this.$form.serializeForm();
			this.changed = [];
		},
		was: function(){
		  return this.original_state;
		},
		disable: function(){
			this.$form.find(':text, textarea').unbind('keyup', this.bindings.standard);
			this.$form.find('select, :file, :hidden').unbind('change', this.bindings.standard);
			if(DAYLIFE.Browser.IE){
				this.$form.find(':checkbox').unbind('click', this.bindings.checkbox);
				this.$form.find(':radio').unbind('click', this.bindings.radio);
			}else{
				this.$form.find(':checkbox').unbind('change', this.bindings.checkbox);
				this.$form.find(':radio').unbind('change', this.bindings.radio);
			}
		},
		enable: function(){
			this.$form.find(':text, textarea').bind('keyup', this.bindings.standard);
			this.$form.find('select, :file, :hidden').bind('change', this.bindings.standard);
			if(DAYLIFE.Browser.IE){
			    this.$form.find(':checkbox').bind('click', this.bindings.checkbox);
				this.$form.find(':radio').bind('click', this.bindings.radio);
			}else{
				this.$form.find(':checkbox').bind('change', this.bindings.checkbox);
				this.$form.find(':radio').bind('change', this.bindings.radio);
			}
		},
		enable_field: function($field){
			if($field.is(':radio')){
				$field.bind('change', this.bindings.radio);
			}else if($field.is(':checkbox')){
				$field.bind('change', this.bindings.checkbox);
				if(DAYLIFE.Browser.IE){
				    $field.bind('click', this.bindings.checkbox);
				}
			}else if($field.is(':text') || $field.is('textarea')){
				$field.bind('keyup', this.bindings.standard);
			}else{
				$field.bind('change', this.bindings.standard);
			}
		},
		set_handlers: function(success, failure, either){
			this.success = (success && typeof success == 'function') ? success : function(){ return true; };
			this.failure = (failure && typeof failure == 'function') ? failure : function(){ return false; };
			this.either = (either && typeof either == 'function') ? either : function(){ return false; };
			this.enable();
		},
		update_field: function($field, val){
		    $field.val(val);
		    if($field.is(':checkbox')){
		        this.do_checkbox_check($field);
		    }else if($field.is(':radio')){
		        this.do_radio_check($field);
		    }else{
		        this.do_standard_check($field);
		    }
		},
		update_changed: function($field, val){
			var name = $field.attr('name');
			var position = $.inArray(name, this.changed);
			if(name && name.indexOf('[]')!=-1){ // handle special case where field is part of an array (uses '[]' in name)
				name = name.replace('[]','');
				position = $.inArray(name, this.changed);
				var has_changed = ((!val && $.inArray($field.val(), this.original_state[name]) != -1) || (val && $.inArray($field.val(), this.original_state[name]) == -1)) ? true : false;
				if(!has_changed){ // above not thorough enough, so...
					var current_state = this.$form.serializeForm();
					for (var i = current_state[name].length - 1; i >= 0; i--){
						if($.inArray(current_state[name][i], this.original_state[name]) == -1){
							has_changed = true;
							break;
						}
					};
					if(!has_changed){ // still not thorough enough, so...
						for (var i = this.original_state[name].length - 1; i >= 0; i--){
							if($.inArray(this.original_state[name][i], current_state[name]) == -1){
								has_changed = true;
								break;
							}
						};
					}
				}
				if(has_changed){
					$field.trigger('DAYLIFE:Change_Monitor:has_changed', []);
				}
				if(position == -1 && has_changed){
					this.changed.push(name);
				}else if(position != -1 && !has_changed){
					this.changed.splice(position, 1);
				}
			}else if(val!=this.original_state[name]){
				$field.trigger('DAYLIFE:Change_Monitor:has_changed', []);
				if(position == -1){
					this.changed.push(name);
				}
			}else if(val==this.original_state[name] && position > -1){
				this.changed.splice(position, 1);
			}
			this.respond($field);
		},
		do_standard_check: function(elem, e){
			var $field = $(elem);
			this.update_changed($field, $field.val());
		},
		do_radio_check: function(elem, e){
			var $field = $(elem);
			var $checked = this.$form.find(':checked[name='+$field.attr('name')+']');
			this.update_changed($field, $checked.val());
		},
		do_checkbox_check: function(elem, e){
			var $field = $(elem);
			var val = ($field.attr('checked') == true) ? $field.val() : false;
			this.update_changed($field, val);
		},
		respond: function($field){
			if(this.either){
				this.either($field);
			}
			if(this.changed.length > 0 && this.success){
				this.success(this.changed);
			}else if(this.changed.length == 0 && this.failure){
				this.failure(this.changed);
			}
		},
		add_field: function($field){
			// not REAL robust:
			// this is meant to hook up fields
			// programmatically inserted into an
			// already-monitored form. - blumy
			var field_name = $field.attr('name');
			var field_value = $field.val();
			if(field_name && typeof this.original_state[field_name] == 'undefined'){
				// to make sure it is in the $form itself:
				if($field.parents('form').get(0) != this.$form.get(0)){
					$field.appendTo(this.$form);
				}
				if($field.is(':checkbox')){
					field_value = ($field.attr('checked')) ? field_value : 0;
				}
				this.original_state[field_name] = field_value;
				this.enable_field($field);
			}
		}
	};

	$.fn.monitor_change = function(opts){
		// accepts either:
		// options (success function and failure function)
		// or
		// string ("reset", "enable", "disable")
		var monitor;
		for (var i = _monitoring.length - 1; i >= 0; i--){
			if(_monitoring[i]['form'].get(0) == this.get(0)){
				monitor = _monitoring[i]['monitor'];
				break;
			}
		}
		if(!monitor){
			monitor = new Change_Monitor(this);
			_monitoring.push({
				'form': this,
				'monitor': monitor
			});
		}
		if(opts && typeof opts == 'string'){
			if(opts == 'enable'){
				monitor.enable();
			}else if(opts == 'disable'){
				monitor.disable();
			}else if(opts == 'reset'){
				monitor.reset();
			}
		}else if(opts){
			monitor.set_handlers(opts.success, opts.failure, opts.either);
		}
		return monitor;
	};

	// XXX TODO: Write more checks in test
	var _get_monitored_form = function($elem){
		// note: will also return false if $elem is not a form element
		var $form, monitor;
	    if ($elem.is('form')) {
	        $form = $elem;
	    } else if($elem.is(':input')){
	        $form = $elem.parents('form');
	    }else{
			// error
			return false;
		}
	    if ($form.length) {
    		for (var i = _monitoring.length - 1; i >= 0; i--){
    			if(_monitoring[i]['form'].get(0) == $form.get(0)){
    				monitor = _monitoring[i]['monitor'];
    				break;
    			}
    		}
    		if (!monitor) {
    		    // Error
    		    return false;
    		} else {
    		    return monitor;
    		}
	    }
        // Error
        return false;
	};

	$.fn.get_monitor = function(){
		return _get_monitored_form(this);
	};

	$.fn.has_changed = function(){
		var monitor = _get_monitored_form(this);
		if (!monitor) {
		    // Error
		    return false;
		} else if (this.is('form')){
		    return monitor.has_changed();
		} else {
		    return ($.inArray(this.attr('name'), monitor.changed) != -1);
		}
    };

	$.fn.monitor_reset = function(){
		// TODO: THIS HAS NO TEST!!!
		var monitor = _get_monitored_form(this);
		if (!monitor) {
		    // Error
		    return false;
		} else if (this.is('form')){
			monitor.reset();
		} else {
			var field_name = this.attr('name');
			if(monitor.original_state[field_name]){
				monitor.original_state[field_name] = this.val();
			}
			var changed_position = $.inArray(field_name, monitor.changed);
			if(changed_position != -1){
				monitor.changed.splice(changed_position, 1);
			}
			return this;
		}
	};

	$.fn.recheck = function(){
		var monitor = _get_monitored_form(this);
		if (!monitor) {
		    // Error
		    return false;
		} else if (this.is('form')){
			// recheck every :input in the form
			DAYLIFE.log('WWWWAAAAAA!  This doesn\'t work on the whole form yet!!!!');
		} else {
			if(this.is(':checkbox')){
				monitor.do_checkbox_check(this);
			}else if(this.is(':radio')){
				monitor.do_radio_check(this);
			}else{
				monitor.do_standard_check(this);
			}
			return this;
		}
    };

})($DL);

// ------------ EDIT IN PLACE ------------- //

(function($){

	// all the monitoring stuff is so we can close the EIP
	// if the position of the node being edited changes
	// (or, by extension, if it gets hidden)

	var _monitoring = [];
	var _monitor_timer;

	var _monitor_nodes = function(){
		for (var i = _monitoring.length - 1; i >= 0; i--){
			// check to see if offset changed:
			// should let us know if $node is hidden or moved
			var current_offset = _monitoring[i].$node.offset();
			if(current_offset.left != _monitoring[i].offset.left || current_offset.top != _monitoring[i].offset.top){
				_monitoring[i].$form.trigger('reset');
			}
		};
	};

	var _check_monitoring = function(){
		if(_monitoring.length == 0){
			window.clearInterval(_monitor_timer);
			_monitor_timer = null;
		}else{
			if(!_monitor_timer){
				_monitor_timer = window.setInterval(function(){
					_monitor_nodes();
				}, 500);
			}
		}
	};

	var _add_to_monitor = function($node, $form){
		for (var i = _monitoring.length - 1; i >= 0; i--){
			if(_monitoring[i].$form == $form){
				break;
			}
		};
		if(i < 0){
			_monitoring.push({
				'$form': $form,
				'$node': $node,
				'offset': $node.offset()
			});
		}
		_check_monitoring();
	};

	var _remove_from_monitor = function($node, $form){
		for (var i = _monitoring.length - 1; i >= 0; i--){
			if(_monitoring[i].$form == $form){
				_monitoring.splice(i,1);
				break;
			}
		};
		_check_monitoring();
	};

	$.fn.edit_in_place = function(opts){
		var $this = this.eq(0);
		if(!opts){ opts = {}; }
		var $form;
		var onclick = function(){
		    // only one eip open at a time:
			$('form.edit_in_place').each(function(){
				var $fieldsets = $('fieldset', $(this));
				$fieldsets.eq(1).css('display', 'none');
				$fieldsets.eq(0).css('display', 'block');
				$(this).css('display', 'none');
			});
			var offset = (opts.appendFormTo.is('body')) ? $this.offset() : $this.position();
			var z = 10000000;
			var $offset_parent = $this.offsetParent();
			// get highest z-index:
			// defined and html checks are there for IE7
			while($offset_parent && $offset_parent.length > 0 && !$offset_parent.is('body') && !$offset_parent.is('html')){
				var parent_z = parseInt($offset_parent.css('zIndex'));
				if(parent_z > z){
					z = parent_z;
				}
				$offset_parent = $offset_parent.offsetParent();
			}
			var reset = function(){
				var $fieldsets = $('fieldset', $form);
				$fieldsets.eq(1).css('display', 'none');
				$fieldsets.eq(0).css('display', 'block');
				$form.css('display', 'none');
				_remove_from_monitor($this, $form);
				$this.trigger('DAYLIFE:edit_in_place:reset', [$form]);
				if(opts.reset && typeof opts.reset == 'function'){
					opts.reset();
				}
				return false;
			};
			var complete = function(){
				$this.text($(':text', $form).val());
				var page_site = window.location.toString().match("http://(.*?)/")[1];
				var match = (typeof $this.attr('href') != 'undefined') ? $this.attr('href').toString().match("http://(.*?)/") : null;
				var link_site = (match && match[1]) ? match[1] : '';
				if ($('#returning_user_management').length && page_site == link_site) {
				    $('.DL-header .DL-header-title').text($(':text', $form).val());
				}
				$('input', $form).attr('disable', false);
				$form.css('display', 'none');
				_remove_from_monitor($this, $form);
				$this.trigger('DAYLIFE:edit_in_place:complete', [$form]);
				if(opts.success && typeof opts.success == 'function'){
					opts.success($(':text', $form).val(), $this);
				}
			};
			if(!$form){
				$form = $.make('form', { className: 'edit_in_place' }, [
					$.make('div').css({
						height: '100%',
						width: '100%',
						backgroundColor: '#000',
						opacity: .5,
						position: 'absolute',
						top: 0,
						left: 11,
						zIndex: -1
					}),
					$.make('div').css({
						height: '30px',
						width: '11px',
						backgroundImage: 'url('+DAYLIFE_Globals.img_path+'/eip_arrow.png)',
						opacity: .5,
						position: 'absolute',
						top: 6,
						left: 0,
						zIndex: -1
					}),
					$.make('fieldset', [
						$.make('input', { type: 'text', name: opts.fieldName }).css({
							border: '0px solid #ccc',
							padding: '4px',
							fontSize: '11px',
							margin: '0 5px 0 0',
							width: parseInt(opts.fieldWidth) + 'px'
						}),
						$.make('input', { type: 'submit', value: 'update'}).css({
							'backgroundColor': '#339933',
							'border': '1px solid #336600',
							'color': '#fff',
							'margin': '0 5px 0 0'
						}),
						$.make('input', { type: 'reset', value: 'cancel'}).css({
							'backgroundColor': '#ccc',
							'margin': '0 5px 0 0'
						})
					]).css({
						border: '0px',
						padding: '0px'
					}),
					$.make('fieldset', { className: 'error'}, [
						$.make('p', { className: 'error'},  'Edit failed.').css({
							fontSize: '11px',
							backgroundColor: 'red',
							padding: '3px',
							'float': 'left'
						}),
						$.make('input', { type: 'reset', value: 'dismiss' })
					]).css({
						'overflow': 'hidden',
						'display': 'none'
					})
				]).css({
					position: 'absolute',
					color: '#fff',
					left: offset.left + $this.outerWidth() + 5,
					zIndex: z,
					padding: '10px 10px 10px 21px',
					overflow: 'hidden'
				}).submit(function(e){
					if(opts.url){
						$('input', $form).attr('disable', true);
						var data = $form.serializeForm();
						for(var k in opts.postData){
							data[k] = opts.postData[k];
						}
						$.ajax({
							'type': 'post',
							'url': opts.url,
							'data': data,
							'success': complete,
							'error': function(data){
								var $fieldsets = $('fieldset', $form);
								$fieldsets.eq(0).css('display', 'none');
								$fieldsets.eq(1).css('display', 'block');
								$('input', $form).attr('disable', false);
							}
						});
					}
					if(opts.editapi){
						var api = new DAYLIFE.Class.EditApi();
						// replace argument placeholder with the user-supplied value
						for (var i = opts.editapi.args.length - 1; i >= 0; i--){
							if(opts.editapi.args[i] == opts.fieldName){
								opts.editapi.args[i] = $('[name='+opts.fieldName+']', $form).val();
								break;
							}
						};
						opts.editapi.args.push({
							onSuccess: complete
						});
						api[opts.editapi.method].apply(api, opts.editapi.args);
					}
					if(!opts.url && !opts.editapi){
						complete();
					}
					return false;
				}).bind('reset', reset);
				$(':submit, :reset', $form).css({
					padding: '3px',
					marginLeft: '5px',
					fontSize: '11px'
				});
				$(':reset', $form).css({
					border: '1px solid #ccc'
				});
				opts.appendFormTo.append($form);
				$form.css('top', offset.top - Math.floor((($form.outerHeight() - $this.outerHeight())/2)));
			}
			_add_to_monitor($this, $form);
			$this.trigger('DAYLIFE:edit_in_place:edit', [$form]);
			$form.css('display', 'block');
			$(':text', $form).focus().val($this.text());
			return false;
		};
		var $link = $.make('a', { href: '#', className: 'reveal' });
		opts = {
			linkPosition: opts.linkPosition || function(){
				$this.after($link);
			},
			linkText: opts.linkText || 'edit',
			linkHref: opts.linkHref || '#',
			url: opts.url || null,
			postData: opts.postData || {},
			editapi: opts.editapi || null,
			fieldName: opts.fieldName || 'name',
			fieldWidth: opts.fieldWidth || 150,
			success: opts.success || null,
			noLink: opts.noLink || false,
			appendFormTo: opts.appendFormTo || $('body')
		};
		$link.text(opts.linkText);
		$link.attr('href', opts.linkHref);
		if(opts.noLink){
		    this.click(onclick);
		}else{
		    $link.click(onclick);
    		opts.linkPosition($link);
		}
		return this;
	};

})($DL);

// ------- IE Debug -------- //

(function($) {
	var _$ied;
    $.extend({
		iedebug: function(msg){
			if(!_$ied){
				_$ied = $.make('div', [
					$.make('ol')
				]).css({
					'position': 'absolute',
					'top': 10,
					'left': 10,
					'zIndex': 20000,
					'border': '1px solid #000',
					'padding': '10px',
					'backgroundColor': '#fff',
					'fontFamily': 'arial,helvetica,sans-serif',
					'fontSize': '11px'
				});
				$('body').append(_$ied);
                // _$ied.draggable();
			}
			_$ied.find('ol').append($.make('li', msg).css({
				'borderBottom': '1px solid #999999'
			}));
		}
	});
})($DL);