/*************************
 * REQUIRES jquery/jquery.js
 *************************/

/* Set up the object function to enable the JS class design pattern 
 * if it is not already initialized
 */
if (typeof object == "undefined") {
	function object ( o ) {
		function F() {};
		F.prototype = o;
		return new F();
	}
} 

/**
 * creates and returns a Balloon element
 * additionally acts as an interface to Balloons already generated
 * 
 */
function balloonNotice ( iBalloon ) {
	var that = object(this);
	var balloon;
	
	if ( typeof iBalloon == 'undefined' ) {
		makeBalloon();
	} else if ( ! $jq( iBalloon ).hasClass( 'luluBalloon' ) ) {
		makeBalloon( iBalloon );
	} else {
		balloon = iBalloon;
	}

	/*********************
	 * Private Functions *
	 *********************/

	function makeBalloon ( iBalloon ) {
		if ( typeof iBalloon == 'undefined' ) {
			balloon = $jq( '<div>' );
		} else if ( typeof iBalloon == 'string' ) {
			balloon = $jq( '<div>' ).html( iBalloon );
		} else if ( $jq( iBalloon ).is('div') ) {
			balloon = $jq( iBalloon );
		} else {
			balloon = $jq( iBalloon ).wrap('<div></div>');
		}
		$jq( '<img src="/images/balloon_anchor.gif" />' ).appendTo( balloon );
		$jq( '<a></a>' ).html("&times;").addClass('kill').appendTo( balloon ).click( function(){ balloonNotice( $jq( this ).parent() ).hide();return false; } );
		
		cssDefine( );
		var ts = new Date();
		balloon.addClass('luluBalloon').css( 'display', 'none' ).attr('id', 'balloonNotice_'+ts.getTime() ).appendTo( $jq( 'body' ) );
		balloon.bgiframe();
	}

	function cssDefine (  ) {
		balloon.css( {
			position : 'absolute'
		,	background : '#ffc'
		,	borderBottom : '#999 1px solid'
		,	padding : '15px 10px 10px'
		,	zIndex : '1000'
			})
			.find('img').css( {
				position : 'absolute'
			,	left : '15px'
			,	bottom : '-12px'
			}).end()
			.find('a.kill').css( {
				position : 'absolute'
			,	top : '2px'
			,	right : '2px'
			,	textDecoration : 'none'
			,	color : '#993'
			,	cursor : 'pointer'
			}).hover( function() { $jq( this ).css( 'color' , '#000' ); }, function() { $jq( this ).css( 'color' , '#993' ); });
			
	}

	function cssFixSafari (  ) {
	}

	function cssFixIE6 (  ) {
	}

	function cssFixIE7 (  ) {
	}
	
	function ballonPosition ( element ) {
		var anchor = element.offset();
		var thisH = $jq( balloon ).outerHeight();
		var offX = ( typeof iOffX == 'undefined') ? 0 : iOffX;
		var offY = ( typeof iOffY == 'undefined') ? 0 : iOffY;
        // console.log('element: ',element,'  offset: ',element.offset(),'  height:',thisH);
        $jq( balloon ).css( { top : anchor.top - thisH - 15 + offY +'px' , left : anchor.left - 18 + offX +'px' } );
        // $jq( balloon ).css( { top : anchor.top +'px' , left : anchor.left +'px' } );
    }

	/*********************
	 * Public Functions  *
	 *********************/
	
	that = {
		show : function ( ) {
			if ( $jq( balloon ).parent() ) {
				$jq( balloon ).css( 'display', 'block' );
                ballonPosition($jq( '#'+$jq( balloon ).attr('attachedtoid') ));
			} else {
				// console.log("balloon: attempted to show before attaching");
			}
			return that;
		}
	,
		hide : function ( ) {
			$jq( balloon ).css( 'display', 'none' );
			return that;
		}
	,
		setId : function ( iId ) {
			$jq( balloon ).attr('id', iId );
			return that;
		}
	,
		attachTo : function ( element, iOffX, iOffY ) {
			
			if ( element.css( 'overflow' ) == 'hidden' ) {
//				console.log("balloon: attempted to attach to element with overflow:hidden");
				return false;
			}
			if ( ( element.css( 'position' ) != 'relative' ) && ( element.css( 'position' ) != 'absolute' )) {
				// console.log("balloon: attempted to attach to element without position:aboslute or position:relative ");
				return false;
			}
			if ( element.attr('id') == '') { // if the element doesn't have an id, give it one
				element.attr('id', $jq( balloon ).attr('id') + '_attachment');
			}
			$jq( balloon ).attr('attachedToId', element.attr('id') );
			element.attr('attached', $jq( balloon ).attr('id') );
			ballonPosition(element);
			// var anchor = element.offset();
			// var thisH = $jq( balloon ).outerHeight();
			// var offX = ( typeof iOffX == 'undefined') ? 0 : iOffX;
			// var offY = ( typeof iOffY == 'undefined') ? 0 : iOffY;
			// $jq( balloon ).css( { top : anchor.top - thisH - 8 + offY +'px' , left : anchor.left - 10 + offX +'px' } );
			return that;
		}		
	,
		showOnHover : function( ) {
			if ( $jq( balloon ).attr('attachedToId') == '' ) {
				// console.log("balloon: can not showOnHover without being attached ");
				return false;
			}
			$jq( '#'+$jq( balloon ).attr('attachedToId') ).hover(
				function() {
					balloonNotice( $jq( '#'+$jq( this ).attr('attached') ) ).show();
				}
			,	function() {
					balloonNotice( $jq( '#'+$jq( this ).attr('attached') ) ).hide();
				}
			);
			return that;
		}
	,
		dismiss : function ( ) {
			$jq( '#'+ $jq( balloon ).attr( 'attachedToId' ) ).attr('attached', '' );
			$jq( balloon ).remove();
			return that;
		}		
	}
	
	return that;
}/*************************
 * REQUIRES jquery.js
 *************************/

/* Set up the object function to enable the JS class design pattern 
 * if it is not already initialized
 */
if (typeof object == "undefined") {
	function object ( o ) {
		function F() {};
		F.prototype = o;
		return new F();
	}
} 

/**
 * converts an existing select element with specific special attributes into a GUI font-picker
 * additionally acts as an interface to GUI pickers already generated
 * 
 */
function fontPicker ( iPicker ) {
	var that = object(this);
	var picker = iPicker;
	
	if ( $jq( iPicker ).is( 'select' ) ) {
		makeFontPicker ( iPicker );
	}
	
	/*********************
	 * Private Functions *
	 *********************/

	function makeFontPicker ( iSelect ) {
		var picker = document.createElement('span');
		$jq(picker)
			.addClass( $jq( iSelect ).attr( 'class' ) )
			.attr('id', $jq( iSelect ).attr('id') );
		
		$jq( '<img>' )
			.attr( 'src', $jq(iSelect).attr('spacerImg') )
			.attr('align','top')
			.appendTo( $jq( picker) );

		var activeOption = document.createElement('img');
		$jq( activeOption )
			.attr( 'src', $jq( iSelect ).find(':selected').attr('altImage') )
			.attr( 'alt', $jq( iSelect ).find(':selected').html() )
			.addClass('activeOption')
			.css( { position: 'absolute', left: '0', top: '0', height: 'auto' } );
		
		picker.appendChild( activeOption );
											
		var list = document.createElement( 'span' );
		$jq( list ).addClass( 'pickList' ).appendTo( $jq( picker ) ).css( 'display' ,'none');
						
		// Make the Options
		var iOptions = $jq( iSelect ).children().each(
			function() {
				var imgSRC = $jq( this ).attr('altImage');
				var value =  $jq( this ).attr('value');
				var title =  $jq( this ).text();
			
				$jq('<a>')
					.attr('val', value)
					.attr('title', title)
					.addClass('fontOption')
					.css({display: 'block', color: 'black', textDecoration:'none'})
					.bind( 'click', function() {
						$jq(this).mouseout().parent().css( 'display' ,'none')
							.prev()
								.attr( 'src', $jq(this).find('img').attr('src') )
								.attr( 'alt', $jq(this).find('img').attr('alt') );
							try {
								$jq(this).parent().next().next().val( $jq(this).attr('val') ).change();
							} catch(e) {
								//log this error
							}
						return false;
					})
					.append(
						$jq('<img border="0">')
							.attr('src', imgSRC)
							.attr('alt', title)	)
					.appendTo( $jq( list ) );
			}
		);
		

		$jq('<a class="toggle"></a>')
			.appendTo( $jq( picker ) )
				.append( $jq( '<img src="'+ $jq(iSelect).attr('discloseImg') +'" align="bottom" >' ) );
		$jq( picker ).bind( 'click', function(){ 
				if ( $jq(this).attr('class').indexOf( 'disabled' ) == -1 ) {
					if ($jq(this).find('.pickList').css( 'display' ) == 'none') {
						$jq(this).find('.pickList').css( 'display' ,'block');
					} else {
						$jq(this).find('.pickList').css( 'display' ,'none');
					}
				}
			} );
		
		$jq( '<input type="hidden">' )
			.attr('name', $jq( iSelect ).attr('name') )
			.val( $jq( iSelect ).val() )
			.change( iSelect.onchange )
			.appendTo( $jq( picker ) );

		// Set up CSS for the picker
		cssDefine( picker );
		
		// fixes for non FF platforms {{{
		if ( $jq.browser.safari ) {
			cssFixSafari( picker );
		} else if ( $jq.browser.msie ) {
			if ( parseInt( $jq.browser.version ) >= 7 ) {
				cssFixIE7( picker );
			} else if ( parseInt( $jq.browser.version ) >= 6 ) {
				cssFixIE6( picker );
			}
		}
		
		if ( $jq(iSelect).attr('disabled') ) {
			fontPicker( $jq(picker) ).disable();
		}

		// replace the old select element with the new picker
		iSelect.parentNode.replaceChild( picker, iSelect );
	}

	function cssDefine ( picker ) {
		$jq( picker )
			.css( {
				position: 'relative',
				lineHeight: '12px',
				overflow: 'visible',
				display: 'inline-block',
				padding: '0',
				border: '#ccc 1px inset',
				margin: '0 20px 0 0',
				padding: '1px 0',
				backgroundColor: '#fff',
				backgroundPosition: '0 0'
				} )
			.find( '.activeOption' )
				.css( {
					lineHeight: '.75em',
					margin: '1px 0 0',
					padding: '0'
				} ).end()
			.find( '.pickList')
				.css( {
					position: 'absolute',
					top: '20px',
					left: '-1px',
					width: '216px',
					height: 'auto',
					maxHeight: '220px',
					border: '#000 1px solid',
					backgroundColor: '#fff',
					overflow: 'auto',
					zIndex: '200',
					textAlign: 'left'
				} ).end()
				.find( '.fontOption' )
					.css( {
						padding: '5px 0 5px 5px',
						fontSize: '.9em',
						cursor: 'pointer'
					} )
					.hover( function() { 
							$jq(this).css( { backgroundColor: '#def'});
						}
						,
						function() { 
							$jq(this).css( { backgroundColor: '#fff'});
						}
						).end()
			.find( 'a.toggle' )
				.css( {
					position: 'relative',
					top: '0',
					right: '-18px',
					backgroundColor: '#eee',
					border: '#ccc 1px outset',
					padding: '1px',
					cursor: 'pointer'
				} )
	}

	function cssFixSafari ( picker ) {
		$jq(picker).css( { height: '18px', top: '-1px'} )
			.find('.toggle').css( { top: '3px'} );
	}

	function cssFixIE6 ( picker ) {
		$jq(picker).css( {
			padding: '0',
			top: '3px'
		})
			.find('.toggle').css( {
				padding: '4px 0',
				display: 'inline-block'
			});
	}

	function cssFixIE7 ( picker ) {
		$jq( picker ).css( {
			padding: '0',
			top: '3px'
		})
			.find('.toggle').css( {
				display: 'inline-block',
				padding: '5px 0'
			}).end()
			.find('.pickList').css( {
				top: '22px'
			})
	}

	/*********************
	 * Public Functions  *
	 *********************/
	
	that = {
		disable : function ( title ) {
			picker
				.addClass('disabled')
				.find('.toggle').css( { cursor: 'auto' } )
					.find('img').css( { opacity: '.3' }).end().end()
				.find('.pickList').css( 'display', 'none' ).end()
				.find( 'input' ).attr('disabled', 'disabled').end()
				.find('.activeOption').css( { opacity: '.3'} ).end()
				.css('background-color', '#efefef');
				if ( title ) {
					picker
						.attr('disabledtitle', (picker.attr('title'))? picker.attr('title'): '' )
						.attr('title', title);
				}
		}
	,
		enable : function ( ) {
			picker
				.removeClass('disabled')
				.find('.toggle').css( { cursor: 'pointer'})
					.find('img').css( { opacity: '1' }).end().end()
				.find( 'input' ).attr('disabled', '').end()
				.find('.activeOption').css( { opacity: '1'} ).end()
				.css('background-color', '#fff');
				picker.attr('title', (picker.attr('disabledtitle')) ? picker.attr('disabledtitle') : '');
		}
	,
		set : function ( value ) {
			picker.find('.fontOption').each(
				function() { 
					if ($jq(this).attr('val') == value ) {
						$jq(this).parent().prev().attr('src', $jq(this).find('img').attr('src') );
					}
				}
			);
			picker.find('input').val( value )
				.change();				
		}
	}
	
	return that;
}/*************************
 * REQUIRES jquery.js
 *************************/

/* Set up the object function to enable the JS class design pattern 
 * if it is not already initialized
 */
if (typeof object == "undefined") {
    function object ( o ) {
        function F() {};
        F.prototype = o;
        return new F();
    }
}

/**
 * converts an existing select element with specific special attributes into a GUI font-size combo
 * additionally acts as an interface to GUI sizers already generated
 * 
 */
function fontSizer ( iSizer ) {
    var 
        that = object(this),
        sizer = iSizer,
        sizeList,
        sizerScreen;
    
    if ( $jq( iSizer ).is( 'select' ) ) {
        makeFontSizer ( iSizer );
    }

    /*********************
     * Private Functions *
     *********************/

    function makeFontSizer ( iSelect ) {
        
        /**
         * build container element
         */
        var sizer = document.createElement('span');
        var sizerId = $jq( iSelect ).attr('id');
        $jq(sizer)
            .addClass( $jq( iSelect ).attr( 'class' ) )
            .attr('id', sizerId );
        
        /**
         * build text input field
         */ 
        $jq( '<input type="text">' )
            .attr('name', $jq( iSelect ).attr('name') )
            .attr('size', '5')
            .attr('minValue', $jq( iSelect ).attr('minValue') )
            .attr('maxValue', $jq( iSelect ).attr('maxValue') )
            .val( $jq( iSelect ).val() )
            .bind('click', function() { $jq(this).attr('lastValue', $jq(this).val()).select()})
            .bind('originalOnChange', iSelect.onchange)
            .bind('change', function() {
                var val = Math.floor( parseInt( $jq(this).val() ) );
                if ( ( val >= $jq(this).attr('minValue')) && ( val <= $jq(this).attr('maxValue') ) ) {
                    $jq(this).val( val ).attr('lastValue', $jq(this).val())
                        .trigger('originalOnChange');
                    
                } else {
                    $jq(this).val( $jq(this).attr('lastValue') );
                }
            })
            .appendTo( $jq( sizer ) );
        
        /**
         * build font size list
         */
        var list = document.createElement( 'span' );
        sizeList = $jq( list );
        sizeList
            .attr('id', sizerId + 'List' )
            .addClass( 'pickList' )
            .css({
                visibility : 'hidden',
                position : 'absolute',
                height : 'auto',
                overflow : 'hidden',
                top : 0,
                left : 0
            })
            .appendTo( 'body' );
        
        var iOptions = $jq( iSelect ).children().each( 
            function () {
                
                var value =  $jq( this ).attr('value');
                var title =  $jq( this ).text();
                $jq(list).append('<a val="'+value+'" title="'+title+'" class="fontOption" style="display: block; text-decoration: none;">'+title+'</a>');

            }
        );
        
        $jq('#' + sizerId + 'List.pickList .fontOption').bind( 'click', function() {
            // $jq(this).mouseout().parent().css( 'display' ,'none');
            $jq(this).mouseout(closeSizer);
            try {
                $jq('#' + sizerId).children('input').val( $jq(this).attr('val') ).trigger('originalOnChange');
            } catch(e) {
                //log this error
            }
            return false;
        });
        
        /**
         * build list toggle
         */     
        $jq( sizer )
            .append('<a class="toggle"></a>')
            .children('a.toggle')
                .append('<img src="'+ $jq(iSelect).attr('discloseImg') +'" align="bottom" >')
                .bind( 'click', function(){ 
                    if ( $jq(this).attr('class').indexOf( 'disabled' ) == -1 ) {
                        // sizeList = $jq('#' + $jq(this).parent('span').attr('id') + 'List');
                        if ( sizeList.css( 'visibility' ) == 'hidden' ) {
                            
                            var textBox = $jq(this).siblings('input');
                            var boxOffset = textBox.offset();
                            var boxHeight = textBox.outerHeight();
                            var windowHeight = $jq(window).height();
                            var bottomRoom = windowHeight - ((boxOffset.top + boxHeight) - $jq(window).scrollTop());
                            var topRoom = boxOffset.top - $jq(window).scrollTop();
                            var listLeft = boxOffset.left;
                            var listExtraSpace = parseInt(sizeList.css('borderTopWidth')) + parseInt(sizeList.css('borderBottomWidth')) + parseInt(sizeList.css('paddingTop')) + parseInt(sizeList.css('paddingBottom'));
                            var listHeight = sizeList.height();
                            var moreBottomRoom = true;
                            var listMinHeight = 150;
                            var listMaxHeight = 300;
                            
                            if ( topRoom > bottomRoom ) {
                                moreBottomRoom = false;
                            }
                            if ( (bottomRoom >= listMinHeight) || (moreBottomRoom) ) {
                                var listTop = boxOffset.top + boxHeight;
                                listHeight = bottomRoom - listExtraSpace;
                                if ( listHeight > listMaxHeight ) {
                                    listHeight = listMaxHeight;
                                }
                            } else {
                                if ( (listHeight + listExtraSpace) > topRoom ) {
                                    listHeight = topRoom - listExtraSpace;
                                }
                                if ( listHeight > listMaxHeight ) {
                                    listHeight = listMaxHeight;
                                }
                                var listTop = boxOffset.top - listHeight - listExtraSpace;
                            }
                            sizeList.css({ 
                                visibility : 'visible', 
                                position : 'absolute', 
                                top : listTop, 
                                left : listLeft , 
                                height : listHeight, 
                                overflow : 'auto' 
                            }); 
                            sizerScreen.css({ display : 'block', top: $jq(window).scrollTop() });
                        } else {
                            closeSizer();
                        }
                    }
                });
        
        /**
         * build list screen
         */
        $jq('body').append('<div id="'+sizerId +'Screen" class="fontSizeScreen"></div>');
        sizerScreen = $jq('#'+sizerId +'Screen')
        sizerScreen.click(function () {
            closeSizer();
        })
        
        // alert($jq.browser.version);
        
        $jq(window)
            .bind('resize', function () {
                closeSizer();
            });
        
        if ( $jq.browser.msie ) {
            sizerScreen.css({
                background : 'white',
                filter : 'alpha(opacity=1)'
            })
        }
        
        // Set up the CSS for the Sizer
        cssDefine( sizer );

        // fixes for non FF platforms {{{

        if ( $jq.browser.safari ) {
            cssFixSafari(sizer);
        } else if ( $jq.browser.msie ) {
            if ( parseInt( $jq.browser.version ) >= 7 ) {
                cssFixIE7( sizer );
            } else if ( parseInt( $jq.browser.version ) >= 6 ) {
                cssFixIE6( sizer );
            }
        }

        if ( $jq(iSelect).attr('disabled') ) {
            fontSizer( $jq(sizer) ).disable();
        }

        // replace the old select element with the new sizer
        iSelect.parentNode.replaceChild( sizer, iSelect );
        
    }
    
    function closeSizer () {
        sizeList.css({ visibility : 'hidden', top : 0, left : 0 , overflow : 'hidden', height : 'auto' });
        sizerScreen.css({ display : 'none' });
    }

    function cssDefine ( sizer ) {
        $jq( sizer )
            .css({
                position: 'relative',
                lineHeight: '12px',
                overflow: 'visible',
                display: 'inline-block',
                padding: '0',
                margin: '0'
            })
            .find( 'input' )
                .css({
                    padding: '0 2px 1px',
                    border: '#ccc 2px inset',
                    fontSize: '12px'
                }).end()
            .find( 'a.toggle' )
                .css( {
                    position: 'relative',
                    top: '0',
                    right: '-18px',
                    backgroundColor: '#eee',
                    border: '#ccc 1px outset',
                    padding: '1px',
                    cursor: 'pointer',
                    right: '0'
                });

        $jq('.pickList')
            .css({
                border: '#000 1px solid',
                backgroundColor: '#fff',
                zIndex: '200',
                textAlign: 'left',
                width: '4em',
                padding: '2px'
            })
            .find('.fontOption')
                .css({
                    padding: '5px 0 5px 5px',
                    fontSize: '.9em',
                    cursor: 'pointer'
                })
                .hover( 
                    function() { 
                        $jq(this).css({ backgroundColor: '#def' });
                    },
                    function() { 
                        $jq(this).css({ backgroundColor: '#fff' });
                    }
                );
        $jq('.fontSizeScreen')
            .css({
                position : 'absolute',
                top : '0',
                left : '0',
                zIndex : '175',
                height : '100%',
                width : '100%',
                display : 'none'
            })

    }

    function cssFixSafari ( sizer ) {
        $jq(sizer)
            .find('.toggle').css( { left: '-2px'} ).end()
            .find('.pickList').css( { top: '22px'} );
    }

    function cssFixIE6 ( sizer ) {
        $jq( sizer )
            .find('input').css( {
                fontSize: '14px',
                width: '2em'
            }).end()
            .find('.toggle').css( {
                display: 'inline-block',
                padding: '5px 0',
                top: '3px',
                left: '-1px'
            }).end()
            .find('.pickList').css( {
                top: '22px'
            })
    }

    function cssFixIE7 ( sizer ) {
        $jq( sizer )
            .find('input').css({
                fontSize: '14px',
                width: '2em'
            }).end()
            .find('.toggle').css({
                display: 'inline-block',
                padding: '5px 0',
                top: '3px',
                left: '-1px'
            }).end()
            .find('.pickList').css( {
                top: '22px'
            })
        
    }

    /*********************
     * Public Functions  *
     *********************/
    
    that = {
        disable : function ( title ) {
            sizer.addClass('disabled')
                .find('.toggle').addClass('disabled')
                    .css({cursor: 'auto'})
                    .find('img').css( { opacity: '.3' }).end().end()
                .find('.pickList').css( 'display', 'none' ).end()
                .find( 'input' ).attr('disabled', 'true');                  
            if ( title ) {
                sizer
                    .attr('disabledTitle', (sizer.attr('title'))? sizer.attr('title'): '' )
                    .attr('title', title);
            }
        }
    ,
        enable : function ( ) {
            sizer.removeClass('disabled')
                .find('.toggle').removeClass('disabled')
                    .css( { cursor: 'pointer'})
                    .find('img').css( { opacity: '1' }).end().end()
                .find( 'input' ).attr('disabled', '');
            sizer.attr('title', (sizer.attr('disabledtitle')) ? sizer.attr('disabledtitle') : '');
        }
    ,
        set : function ( value ) {
            sizer.find('input').val( value )
                .change();                                  
        }       
    }
    
    return that;
}/****************************************************
 * singleton Dialog Box Manager class
 ****************************************************/
function UIDialogBoxManager ( )
{
    var obj = $L.object( this, new LManager('UIDialogBox') );
    
    /** public variables */
    // none
    
    /** public methods */
    
    obj.open = function() {
        for ( var i = 0; i < obj._selected.length; ++i ) {
            var thisBox = obj._selected[i];
            if ( ! obj._isOpen( thisBox.id ) ) {
                var shown = obj.getById(thisBox.id);
                obj._openDialogBoxes.push(shown);
                obj._initBox(thisBox);
                thisBox.willOpen();
                obj._$show( thisBox.id );
                thisBox.didOpen();
            }            
        }
        
        return obj;
    };
    
    obj.close = function() {
        for ( var i = 0; i < obj._selected.length; ++i ) {
            var thisBox = obj._selected[i];
            if ( obj._isOpen( thisBox.id ) ) {
                thisBox.onCancel();
                thisBox.onClose();
                obj._$hide( thisBox.id );
            }            
        }
    
        return obj;
    };
    
    obj.zoom = function() {
        for ( var i = 0; i < obj._selected.length; ++i ) {
            var thisBox = obj._selected[i];
            
            if ( obj._$isZoomed( thisBox ) ) {
                obj._$setMinMode( thisBox );
                obj._$updateDOM( thisBox );
            } else {
                obj._$setMaxMode( thisBox );
                obj._$maximize( thisBox );
            }
        }
    
        return obj;
    };
    
    obj.accept = function() {
        for ( var i = 0; i < obj._selected.length; ++i ) {
            var thisBox = obj._selected[i];
            if ( obj._isOpen( thisBox.id ) ) {
                thisBox.onAccept();
                thisBox.onClose();
                obj._$hide( thisBox.id );
            }            
        }
    
        return obj;
    };
    
    obj.openModal = function() {
        obj._$showModalScreen();
        for ( var i = 0; i < obj._selected.length; ++i ) {
            var thisBox = obj._selected[i];
            if ( ! obj._isOpen( thisBox.id ) ) {
                var shown = obj.getById(thisBox.id);
                shown.isModal = true;
                obj._openDialogBoxes.push(shown);
                obj._initBox(thisBox);
                thisBox.willOpen();
                obj._$show( thisBox.id, true );
                thisBox.didOpen();
                var thisId = thisBox.id
                $jq(window).bind("scroll", function() {obj._$positionDialog(thisId);});
            }            
        }
        
        return obj;
    };

    obj.modifiedContent = function () {
        for ( var i = 0; i < obj._selected.length; ++i ) {
            var thisBox = obj._selected[i];
            obj._$adjContentHeight(thisBox);
        }
        return obj;
    };
           
    obj.setTitle = function ( dialogTitle ) {
        obj._set('title', dialogTitle, true);
        return obj;
    };
    
    obj.setContent = function ( dialogContent ) {
        obj._set('content', dialogContent, true);
        obj._newContent = true;
        return obj;
    };
     
    obj.setHeight = function ( dialogHeight ) {
        obj._set('height', dialogHeight, true);
        return obj;
    };
    
    obj.setWidth = function ( dialogWidth ) {
        obj._set('width', dialogWidth, true);
        return obj;
    };
    
    obj.setWillOpen = function ( willOpenFunc ) {
        obj._set('willOpen', willOpenFunc);
        return obj;
    };
    
    obj.setOnOpen = function ( onOpenFunc ) {
        obj.setDidOpen(onOpenFunc);
    }
    
    obj.setDidOpen = function ( didOpenFunc ) {
        obj._set('didOpen', didOpenFunc);
        return obj;
    };
    
    obj.setOnFocus = function ( onFocusFunc ) {
        obj._set('onFocus', onFocusFunc);
        return obj;
    };
    
    obj.setOnAccept = function ( onAcceptFunc ) {
        obj._set('onAccept', onAcceptFunc);
        return obj;
    };
    
    obj.setOnCancel = function ( onCancelFunc ) {
        obj._set('onCancel', onCancelFunc);
        return obj;
    };
    
    obj.setOnClose = function ( onCloseFunc ) {
        obj._set('onClose', onCloseFunc);
        return obj;
    };
    
    obj.clearDidOpen = function () {
        obj._set('didOpen', obj._nullCallback);
        return obj;
    };
    
    obj.clearWillOpen = function () {
        obj._set('willOpen', obj._nullCallback);
        return obj;
    };
    
    // obj.clearOnOpen = function () {
    //     obj._set('onOpen', obj._nullCallback);
    //     return obj;
    // };  
    
    obj.clearOnAccept = function () {
        obj._set('onAccept', obj._nullCallback);
        return obj;
    };  
    
    obj.clearOnCancel = function () {
        obj._set('onCancel', obj._nullCallback);
        return obj;
    };  
    
    obj.clearOnClose = function () {
        obj._set('onClose', obj._nullCallback);
        return obj;
    };  
    

    /** private variables */
    
    obj._openDialogBoxes = new Array();
    obj._modalScreen;
    obj._modalZ = 10000;
    obj._nullCallback = function () {};
    obj._willOpen = function () {};
    obj._didOpen = obj._nullCallback();
    
    /** private methods */
    
    obj._checkDataBeforeAdd = function ( datastruct ) {
        $jq(document).ready(function () {
            obj._$moveDialog(datastruct.id);   
        });
        
        return datastruct;
    };
    
    obj._initBox = function ( box ) {
        obj._$makeManipulatable(box);
        if (!box.initialized) {
            
            headerHeight = $jq('#'+box.id+' .blockHead').outerHeight();
            footerHeight = $jq('#'+box.id+' .blockFoot').outerHeight();
            if ( box.isDraggable ) {
               obj._$setDraggable(box);
            }
            if ( box.isResizable ) {
                obj._$setResizable(box, headerHeight, footerHeight);
            }
            if ( $jq.browser.msie ) {
                $jq('#'+box.id).bgiframe();
            }
            
            box.initialized = true;
            obj._$applyBtnEventHandlers(box);
            
            obj._$setDropShadow(box);
            if (typeof(box.willOpen) == 'undefined') {
                obj.clearWillOpen();                
            }
            if (typeof(box.didOpen) == 'undefined') {
                obj.clearDidOpen();
            }
        }
        if ( box.isResizable ) {
            obj._$setMinMode( box );
        }
        obj._$updateDOM(box);
    };
    
    obj._set = function ( attr , val, update ) {
        for ( var i = 0; i < obj._selected.length; ++i ) {
            var thisBox = obj._selected[i];
            thisBox[attr] = val;
            if (typeof thisBox[attr+'New'] != 'undefined') {
                thisBox[attr+'New'] = true;
            }
            if ( (typeof update != 'undefined') && update ) {
                obj._$updateDOM(thisBox);
            }
        }
    };
    
    obj._isOpen = function( id ) {
        var isOpen = false;
        for (var i=0; i < obj._openDialogBoxes.length; i++) {
            if (obj._openDialogBoxes[i].id == id) {
                isOpen = true;
            }
        };
        
        return isOpen;
    };
    
    obj._getModalZ = function() {
        return obj._modalZ;
    };
    
    /** encapsulated calls to 3rd party libraries */
    
    obj._$applyBtnEventHandlers = function ( box ) {
        $jq('#'+box.id).find('.applySettings').unbind('click').click(function(){
            obj.onAccept();
        });
    
        $jq('#'+obj.id).find('.cancelSettings').unbind('click').click(function(){
            obj.onCancel();
        });
    };
    
    obj._$updateDOM = function ( box ) {
        if (typeof box.title != 'undefined') {
            if (box.titleNew) {
                $jq('#'+box.id+' .blockHead h2').text(box.title); 
                box.titleNew = false;               
            }
        }
        if (typeof box.content != 'undefined') {
            if (box.contentNew) {
                $jq('#'+box.id+' .blockBody').empty().append(box.content);
                box.contentNew = false;
            }
        }
        if (box.heightNew) {
            $jq('#'+box.id).height(box.height);
            box.heightNew = false;
        }
        if (box.widthNew) {
            $jq('#'+box.id).width(box.width); 
            box.widthNew = false;          
        }
        obj._$adjContentHeight(box);
        obj._$positionDialog(box.id);
    };
    
    obj._$makeManipulatable = function (box) {
        $jq('#'+box.id).css( { visibility: 'hidden', display: 'block' } );
    };
    
    obj._$adjContentHeight = function ( box, height ) { // removed _reposition flag, may need to further modify function based on dialogManager
        if ( typeof(height) == 'undefined') {
            var thisHeight = obj._castToInt(box.height);
        } else {
            var thisHeight = obj._castToInt(height);
        }

        var headerElement = $jq('#'+box.id+' .blockHead');
        if (headerElement.css('position') != 'absolute') { // absolutly positoned headers don't cont for height calculations
            var headerHeight = obj._castToInt(headerElement.outerHeight());            
        } else {
            var headerHeight = 0;
        }
        var footerHeight = obj._castToInt($jq('#'+box.id+' .blockFoot').outerHeight());
        var contentDiv = $jq('#'+box.id+' .blockBody');
        contentDiv.height('auto');
        var contentPadding = obj._castToInt(contentDiv.css('paddingTop')) + obj._castToInt(contentDiv.css('paddingBottom'));
        var contentBorder = obj._castToInt(contentDiv.css('borderTopWidth')) + obj._castToInt(contentDiv.css('borderBottomWidth'));
        var minHeight = obj._castToInt(contentDiv.outerHeight()) + headerHeight + footerHeight;
        if ( (minHeight > thisHeight) && !box.isResizable ) {
            obj._$adjContentHeight(box, minHeight);
        } else {
            var contentHeight = thisHeight - headerHeight - footerHeight - contentPadding - contentBorder;
            $jq('#'+box.id).height(thisHeight);
            contentDiv.height(contentHeight);
        }
    };

    obj._castToInt = function ( value ) {
        var intval = parseInt(value);
        return (isNaN(intval)) ? 0 : intval;
    };
    
    obj._$setDraggable = function (box) {

        $jq('#'+box.id).draggable({
            handle: '.blockHead',
            cursor: 'move'
        });

    };
    
    obj._$setDropShadow = function (box) {
        $jq('#'+box.id)
            .addClass('UIDialogShadow')
            .append('<div class="shadow1"><div class="shadow2"><div class="shadow3"><div class="shadow4"></div></div></div></div>');
    };
    
    obj._$moveDialog = function (id) {
        $jq('#'+id).appendTo('body');
    };
    
    obj._$setResizable = function ( box, headerHeight, footerHeight ) {
        $jq('#'+box.id)
            .resizable({
                resize: function () {
                    obj._$adjContentHeight(box, $jq('#'+box.id).outerHeight());
                },
                stop: function () {
                    obj._$setMinMode(box);
                },
                handles: "se",
                minHeight: box.minHeight + headerHeight + footerHeight,
                minWidth: box.minWidth
            });
        $jq('#'+box.id).find('.blockBody').css('overflow', 'auto');
    };
    
     obj._$createModalScreen = function() {
         obj._modalScreen = $jq('<div id="UIDialogBoxModalScreen" style="visibility: hidden; width: 100%; position: absolute; top: 0px; left: 0px;"></div>');
         $jq('body').append(obj._modalScreen);
     };
     
     obj._$hide = function( id ) {
         $jq( '#'+id ).css( { display: 'none' } );
         var box = obj.getById(id);
         if (box.isModal) {
             box.isModal = false;
             $jq( obj._modalScreen ).css( { display: 'none' } );
         }
         obj._openDialogBoxes.pop();
         $jq('textarea').css({overflow : 'auto'}); // this addresses a bug in FF 2 where horizontal scroll bars overlap the dialog box
     };
     
     obj._$hideModalScreen = function() {
         $jq( obj._modalScreen ).css( { visibility: 'hidden' } );
     };
     
     obj._$show = function( id ) {
         $jq( '#'+id ).css( { visibility : 'visible' } );
         $jq('textarea').css({overflow : 'hidden'}); // this addresses a bug in FF 2 where horizontal scroll bars overlap the dialog box
     };
     
     obj._$isZoomed = function( box ) {
         return $jq('#'+box.id).hasClass('zoomed');
     };
     
     obj._$maximize = function ( box ) {
         var margin = 40;
         var thisWin = $jq(window); 
         var dialogWidth = thisWin.width() - (margin * 2);
         var dialogHeight = thisWin.height() - (margin * 2);
         var dialogScroll = thisWin.scrollTop() + margin;
         
         $jq('#'+box.id)
             .css({width: dialogWidth+'px', top: dialogScroll+'px', left: margin+'px'});
         obj._$adjContentHeight(box, dialogHeight);
     };
     
     obj._$setMaxMode = function ( box ) {
         $jq('#'+box.id)
             .addClass('zoomed')
             .find('.zoomIcon').attr('src', 'http://static.lulu.com/images/components/UIDialogBox/minDialog.png?20091119133755');
     };
     
     obj._$setMinMode = function ( box ) {
         box.heightNew = true;
         box.widthNew = true;
         $jq('#'+box.id)
             .removeClass('zoomed')
             .find('.zoomIcon').attr('src', 'http://static.lulu.com/images/components/UIDialogBox/maxDialog.png?20091119133755');
     };
     
     obj._$showModalScreen = function() {
         if ( typeof obj._modalScreen == 'undefined' ) {
             obj._$createModalScreen();
         }
         $jq('.UIDialogBox').css({zIndex: obj._getModalZ() + 100})
         $jq( obj._modalScreen ).css( { display: 'block', visibility: 'visible', zIndex: obj._getModalZ().toString() } );
     };
     
     obj._$positionDialog = function( id ) {
        var panel = $jq('#'+ id );
        var thisWin = $jq(window); 
        var winWidth = thisWin.width();
        var winHeight = thisWin.height();
        var winScroll = thisWin.scrollTop();
        var panelWidth = panel.outerWidth();
        var panelHeight = panel.outerHeight();
        var leftOff = (winWidth/2)-(panelWidth/2);
        if (winHeight <= panelHeight) {
            var topOff = winScroll+5;
        } else {
            var topOff = (winHeight/2)-(panelHeight/2)+winScroll;             
        }
        panel.css({top: topOff+'px', left: leftOff+'px'});
        $jq('#UIDialogBoxModalScreen').css({top: winScroll+'px', height: winHeight+'px'});
     };

    return obj;
}

/* instantiate the "singleton" */
$L.addManager('dialogBoxManager', new UIDialogBoxManager());function UIDialogBox ( dataStruct ) 
{
    var obj = $L.object( this );
    
    /** public member variables **/
    
    obj.id = dataStruct.id;
    obj.title = dataStruct.title;
    obj.titleNew = false;
    obj.content = dataStruct.content;
    obj.contentNew = false;
    obj.height = dataStruct.height;
    obj.minHeight = dataStruct.minWidth;
    obj.heightNew = true;
    obj.width = dataStruct.width;
    obj.minWidth = dataStruct.minWidth;
    obj.widthNew = true;
    obj.willOpen = dataStruct.willOpen;
    obj.didOpen = dataStruct.didOpen;
    obj.onFocus = dataStruct.onFocus;
    obj.onAccept = dataStruct.onAccept;
    obj.onCancel = dataStruct.onCancel;
    obj.onClose = dataStruct.onClose;
    obj.initialized = false;
    obj.isModal = false;
    obj.isDraggable = dataStruct.isDraggable;
    obj.isResizable = dataStruct.isResizable;
    
    return obj;
}var LDisclosureContentBlock = {
    /**
    * Operates as a static behavior constructor to hide/show a disclosure content block when any controller is clicked.
    */
    create : function ( dataStruct ) {

        var id = '#' + dataStruct.id;
        if ( $L.isArray( dataStruct.controllers ) ) {
            var controllers = dataStruct.controllers;
        } else {
            var controllers = [ dataStruct.controllers ];
        }
        var hidden = dataStruct.hidden;
        var exclusiveClass = dataStruct.exclusiveClass;
        var animate = dataStruct.animate;
        
        for ( var i=0; i < controllers.length; ++i ) {
            // used mouseup instead of click or mousedown, click caused the help box to open if the user hits enter while the cursor is in a form field, mousedown prevents the use from clicking on any nested text input field
            var controllerType = controllers[i].type;
            $jq( '#' + controllers[i].id ).mouseup( 
                function() {
                    if ( exclusiveClass != false ) {
                        LDisclosureContentBlock.hideByClass( id, exclusiveClass, animate );
                    }
                    if ( controllerType == 'open' ) {
                        LDisclosureContentBlock.open( id, animate );
                    } else if ( controllerType == 'toggle' ) {
                        LDisclosureContentBlock.toggle( id, animate, exclusiveClass );
                    }
                    
                    // this event listener can block click events for nested elements, the following line insures that a click event is triggered
                    $jq(this).find('input').click();
                    
                    return false;
                }
            );
        }

        if ( hidden ) {
            LDisclosureContentBlock.hide( id );
        } else {
            LDisclosureContentBlock.show( id );
        }
    },
    hideByClass : function ( id, className, animate ) {
        $jq('.'+className+':not('+id+')').each(function(){
            if (animate && LDisclosureContentBlock.animate()) {
                $jq(this).slideUp('fast');
            } else {
                $jq(this).css( {display: 'none'} );
            }
        });
    },
    hide : function ( id, animate ) {
        if (animate && LDisclosureContentBlock.animate()) {
            $jq(id).slideUp('fast');
        } else {
            $jq( id ).css( {display: 'none'} );
        }
    },
    show : function ( id, animate ) {
        if (animate && LDisclosureContentBlock.animate()) {
            $jq(id).slideDown('fast');
        } else {
            $jq( id ).css( {display: 'block'} );
        }
    },
    toggle : function ( id, animate, exclusiveClass ) {      
        if ( $jq( id ).css( 'display' ) != 'none' ) {
            LDisclosureContentBlock.hide( id, animate );
        } else {
            LDisclosureContentBlock.show( id, animate );
        }
    },
    open : function ( id, animate ) {
        if ( $jq( id ).css( 'display' ) == 'none' ) {
            LDisclosureContentBlock.show( id, animate );
        } 
    },
    animate : function () {
        var animate = true;
        if ( $jq.browser.safari ) {
            animate = false;
        }
        
        return animate;
    }
};
function LFilterSelector ( targetClass, active )
{
	var obj = $L.object( this );

	// public methods

	obj.update = function ( id, active ) {
		obj._$updateSelectedFilter(id);
		obj._setActive(active);
	}

	obj.addTrigger = function ( id, value, active ) {
		obj._$addOnclick(id, value);
		obj._triggerIds[obj._triggerIds.length] = id;
		if ( active ) {
			obj.update(id, value);
		}
	}

	// private methods

	obj._setActive = function ( active ) {
		obj._active = active;
		obj._$applyFilter(active);
	}

	obj._$addOnclick = function ( id, value ) {
		$jq('#'+id).click( function() { obj.update(id, value); } );
	}

	obj._$updateSelectedFilter = function ( id ) {
		var ids = '#' + obj._triggerIds.join(',#');
		$jq(ids).removeClass('selected')
			.filter('#'+id).addClass('selected');
	}

	obj._$applyFilter = function ( active ) {
		$jq('.'+obj._target).children().css('display', 'none')
			.filter('.'+active).css('display', 'block');
	}

	// private members

	obj._target = targetClass;
	obj._active = active;
	obj._triggerIds = new Array();

	return obj;
};
function LFormElementManager ( )
{
	var obj = $L.object( this, new LManager('LFormElement') );
	
	obj.validateForm = function( form ) {
		var formValid = true;
		obj.select( obj._$getFormElementIdsByForm( form ) );

		for ( var i = 0; i < obj._selected.length; ++i ) {
			var element = obj._selected[i];
			if ( ( element ) && ( ! element.validate() ) ) {
				formValid = false;
			}
		}
		return formValid;
    }
	
	/****************************************************
	 * Library Interfaces
	 ****************************************************/
	
	obj._$getFormElementIdsByForm = function( form ) {
		var ids = [];
		$jq( form ).find( '[id]:enabled' ).each( function() {
			ids.push( this.id );
		} );
		return ids;
	}
	
	return obj;
};
$L.addManager( 'FormElementManager', new LFormElementManager() );function LFormElement ( dataStruct )
{
	var obj = $L.object( this );

	obj.id;
	obj.required;
	obj.validator;

	obj.init = function( dataStruct ) {
		obj.id = dataStruct.id;
		obj.required = ( dataStruct.required === false ) ? false : true;
		obj._defineValidator( dataStruct.validator );
	};

	obj.validate = function() {
		var value = obj._$getValue();
		var valid = true;
		if ( obj.required || value != '' ) {
			valid = obj.validator( value );
		}
		return valid;
	};

/****************************************************
 * Private Functions
 ****************************************************/
	
	obj._defineValidator = function( validatorName ) {
		if ( obj._validators[ validatorName ] ) {
			obj.validator = obj._validators[ validatorName ];
		} else {
			if ( obj.required ) {
				obj.validator = obj._validators.notNull;
			} else {
				obj.validator = obj._validators.noValidation;
			}
		}
	};

	obj._validators = {
		noValidation: function( val ) { 
			return true;
		},
		notNull: function( val ) {
			var valid = true;
			if ( ( val == null ) || ( val == '' ) ) {
				valid = false;
			}
			return valid;
		}
	};
	
	
	/****************************************************
	 * Library Interfaces
	 ****************************************************/
	
	obj._$getValue = function() {
		return $jq( '#'+obj.id ).val();
	};
	
	obj.init( dataStruct );
	return obj;
}function LSearchInput ( dataStruct )
{
	var obj = $L.object( this, new LFormElement(dataStruct) );

	obj._populatedFromServer;
	obj.typeOf = 'LFormElement';
	
	obj.init = function( dataStruct ) {
		obj._populatedFromServer = dataStruct._populatedFromServer;
	};

	obj.validate = function() {
		var value = obj._$getValue();
		var valid = true;
		if ( obj.required || value != '' ) {
		    if ( !obj._populatedFromServer && (( val == null ) || ( val == '' )) ) {
    			valid = false;
    		}
		}
		return valid;
	};
	
	obj.cancelButton = function() {
	    if (obj._$getValue() != '') {
	        obj._$showCancel();
	    } else if (!obj._populatedFromServer) {
	        obj._$hideCancel();
	    }
	};
	
	obj.cancelSearch = function() {
	    obj._$clearValue();
	    obj._$hideCancel();
		if (obj._populatedFromServer) {
		    obj._$submitSearch();
		}
	};

    obj._$showCancel = function() {
        $jq( '#'+obj.id+'_cancelBtn' ).css({visibility:'visible'});
    };
    
    obj._$hideCancel = function() {
        $jq( '#'+obj.id+'_cancelBtn' ).css({visibility:'hidden'});
    };
    
	obj._$submitSearch = function() {
		return $jq( '#'+obj.id+'_submitBtn' ).click();
	};
	
	obj._$clearValue = function() {
		return $jq( '#'+obj.id+'_input' ).val('');
	};
	
	obj._$getValue = function() {
		return $jq( '#'+obj.id+'_input' ).val();
	};

	obj.init( dataStruct );
	return obj;
}function object ( o, hostObject ) {
	if ( typeof hostObject == 'undefined' ) {
		function F() {};
		F.prototype = o;
		that = new F();
	} else {
		that = hostObject;
	}
	that.typeOf = o.constructor.name;
	return that;
};

function LProgressComponentManager() {
	
	var that = object( this );

	/** private variables */
	that._components = new Array();
	that._lastAdded = null;

	/** private methods */
	// none

	/** public variables */
	that.add = function( component ) {
		if ( component.typeOf == 'LProgressComponent' ) {
			that._components[ component.tokenKey ] = component;
			that._lastAdded = that._components[ component.tokenKey ];
		} else {
			throw new Error( "LProgressComponentManager.add() was not passed a valid LProgressComponent object" );
		}
		return that;
	};

	that.remove = function( token ) {
		if ( token.typeOf == 'LProgressComponent' ) {
			var tokenKey = token.tokenKey;
		} else {
			var tokenKey = "_" + token;
		}
		that._components[ tokenKey ] = undefined;

		return that;
	};

	that.getLast = function() {
		return that._lastAdded;
	};

	that.getByToken = function( token ) {
		return that._components[ "_"+token ];
	};

	that.each = function( inFunc ) {
		for ( x in that._components ) {
			that._components[x].__func = inFunc;
			that._components[x].__func();			
		}
		return that;
	};

	that.startAll = function() {
		that.each( function() { this.start(); } );
		return that;
	};

	that.stopAll = function() {
		that.each( function() { this.stop(); } );
		return that;
	};
	
	return that;
}
var luluProgressComponentManager = new LProgressComponentManager();function object ( o, hostObject ) {
	if ( typeof hostObject == 'undefined' ) {
		function F() {};
		F.prototype = o;
		that = new F();
	} else {
		that = hostObject;
	}
	that.typeOf = o.constructor.name;
	return that;
};


function LProgressComponent ( dataStruct ) {

	var that = object( this );

	/** private member variables **/

	that._pollingDelay = 1000;
	that._pollingMissThreshold = 10;
	that._isStarted = false;
	that._isWaiting = false;
	that._missedQueuedRequest = 0;
	that._onCompleteFunc = dataStruct.onComplete;
	that._requestData = false;


	/** private member functions **/

	that._sendRequest = function () {
		if (( that._isStarted ) && ( ! that.isComplete )) {
			if ( that._isWaiting ) {
				++that._missedQueuedRequest;
				if ( that._missedQueuedRequest > that._pollingMissThreshold ) {
				// how many cycles must a progress bar walk down before you can call it fubar'd??
				}
			} else {
				that._post( that.restEndPoint, that.requestData, that.update );
				that._isWaiting = true;
				that._missedQueuedRequest = 0;
				that._queueNextRequest();
			}
		}
	};

	that._post = function ( endpoint, data, callback ) {
		$jq.post( endpoint, data, callback );	
	};

	that._timer = function ( delay, callback ) {
		$jq.timer( delay, callback );	
	};

	that._updateDOM = function ( object ) {
		$jq( '#'+object.id )
			.find( '.elapsedTime' ).text( object.elapsedTime );
	};

	that._queueNextRequest = function () {
		if ( that._isStarted ) {
			that._timer( that._pollingDelay, that._sendRequest );
		}
	};

	that._getFormattedElapsedTime = function () {
		var hours = 0;
		var minutes = 0;
		var seconds = ( parseInt( that.elapsedTime ) >= 0 ) ? Math.floor( parseInt( that.elapsedTime ) / 1000 ) : 0;
		if ( seconds > 3599 ) {
			hours = Math.floor( seconds / 3600 );
			minutes = Math.floor(( seconds % 3600 ) / 60 );
			seconds = seconds % 60;
		} else if ( seconds > 59 ) {
			minutes = Math.floor( seconds / 60 );
			seconds = seconds % 60;
		}
		return { s: seconds, m: minutes, h: hours };
	};

	/** public member variables **/

	that.id = dataStruct.id;
	that.token = dataStruct.token || "_" + dataStruct.id;
	that.isComplete = dataStruct.isComplete || false;
	that.restEndPoint = dataStruct.restEndPoint || "";
	that.startTime = dataStruct.startTime || 0;
	that.elapsedTime = dataStruct.elapsedTime || 0;
	that.tokenKey = "_" + that.token;

	/** public member functions **/

	that.start = function () { 
		that._isStarted = true;
		that._sendRequest();
		return that;
	};

	that.stop = function () {
		that._isStarted = false;
		return that;
	};

	that.update = function ( response ) {
		that._isWaiting = false;
	
		if ( that.elapsedTime < response.elapsedTime ) {
			that.elapsedTime = response.elapsedTime;
		}
	
		that._updateDOM( that );
	
		if ( response.isComplete ) {
			that.stop();
			that.onComplete();
		} else if ( that._missedQueuedRequest > 0 ) {
			that._sendRequest();
		}
		return that;
	};

	that.onComplete = function () {
		that._onCompleteFunc();
		return that;
	};
	return that;
}function LHelpPopup ( ) {
    var obj = $L.object(this);
    
    obj.init = function () {
        obj._$resizeEventHandler();
        
        return obj;
    }
    
    obj.open = function () {
        obj._$positionPopup();
        obj._$openPopup();
    }

    obj.close = function () {
        obj._$closePopup();
    }

    // private methods


    // encapsulated calls to 3rd party libraries
    
    obj._$openPopup = function () {
        $jq('#helpPopup').show();
        obj._isOpen = true;
    }
    
    obj._$closePopup = function () {
        $jq('#helpPopup').hide();
        obj._isOpen = false;
    }
    
    obj._$resizeEventHandler = function () {
        $jq(window).bind('resize', function(){
            if (obj._isOpen) {
                obj._$positionPopup();                
            }
        });
    }

    obj._$positionPopup = function () {
        var link = $jq('#helpLink');
        var popup = $jq('#helpPopup');
        
        var btnPosition = link.offset();
        var btnWidth = link.outerWidth();
        var btnHeight = link.outerHeight();
        var popupWidth = popup.outerWidth();
        var popupTop = btnPosition.top + btnHeight;
        var popupLeft = btnPosition.left - (popupWidth - btnWidth);
        
        popup.css({top: popupTop+'px', left: popupLeft+'px'});
    }

    // private members
    obj._isOpen = false;

    return obj;
};
$L.add('HelpPopup', new LHelpPopup().init());
/**
 * UIFormElementDependencyFilter.js
 * 
 * Use this object to construct a visibility dependency between the selected option of one select (the master) 
 * and the visible options of another select or the visibility of other elements (the slaves).
 * 
 * Note: All slaves must have a uniqe html id attribute, in addition to having the slave_class html attribute 
 * This relationship can be chained to produce a series of dependencies.
 * 
 * The class_value_graph should be in the following format:
 * 
 *   { filter_class : master_value, [etc...] }
 * 
 * where filter_class matches an html class attribute on any slave that should be visible when the master's value is equal to master_value.
 * 
 * @param string master_id the html id attribute of the master select element
 * @param string slave_class the html class attribute of any slave elements
 * @param Object class_value_graph a mapping of filter classes to master value. See above for format.
 */
function UIFormElementDependencyFilter ( master_id, slave_class, class_value_graph ) {
    var obj = $L.object(this);
    
    obj._masterId = master_id;
    obj._slaveClass = slave_class;
    obj._optionGraph = class_value_graph;

    obj._$master;
    obj._slaves = {};
    obj._slaveClones = {};
    obj._initializing;

    obj.masterChanged = function ( ) {
        var filteredClass = obj._optionGraph[obj._tokenizeValue(obj._$findFieldIn(obj._$master).val())];
        for (x in obj._slaves) {
            if ( obj._$elementHasSelect(obj._slaves[x]) ) {
                obj._$filterSelectSlave( x, filteredClass );
            } else {
                obj._$filterNonSelectSlave( x, filteredClass );
            }
            obj._$findFieldIn(obj._slaves[x]).change();
        }
    };

	obj.reInit = function ( ) {
        obj._initializing = true;
        $L.executeFunctionWhenDocumentReady( function() {
            obj._$indexSlaves();
            obj.masterChanged();
            obj._initializing = false;
        });
    };

    obj._$filterSelectSlave = function ( elementIndex, filteredClass ) {
        var sel = obj._slaves[elementIndex].find('select');
        sel.empty();
        obj._slaveClones[elementIndex]
            .find('select option.'+filteredClass)
            .clone()
            .appendTo(sel);
        if (sel.children().size() == 0) {
            obj._$hide(obj._slaves[elementIndex]);
        } else {
            obj._$show(obj._slaves[elementIndex]);
        }
    };

    obj._$filterNonSelectSlave = function ( elementIndex, filteredClass ) {
        if (obj._slaves[elementIndex].hasClass(filteredClass)) {
            obj._$show(obj._slaves[elementIndex]);
        } else {
            obj._$hide(obj._slaves[elementIndex]);
        }
    };

    obj._$hide = function ( $element ) {
        if (obj._initializing || $jq.browser.msie) {
            $element.hide();
        } else {
            $element.slideUp("fast");
        }
        obj._$findFieldIn($element).val("");
    };

    obj._$show = function ( $element ) {
        if (obj._initializing || $jq.browser.msie) {
            $element.show();
        } else {
            $element.slideDown("fast");
        }
    };

    obj._tokenizeValue = function ( value ) {
        if (value == null || typeof value == 'undefined') {
            value = 'UIundefined_value';
        }
        return "_" + value.toString();
    };

    obj._processGraph = function ( ) {
        var unprocessed = obj._optionGraph;
        obj._optionGraph = {};
        for (x in unprocessed) {
            obj._optionGraph[ obj._tokenizeValue(unprocessed[x]) ] = x;
        }
    };

    obj._init = function ( ) {
        obj._initializing = true;
        $L.executeFunctionWhenDocumentReady( function() {
            obj._processGraph();
            obj._$initMasterById(obj._masterId);
            obj._$indexSlaves();
            obj.masterChanged();
            obj._$fixIeLayout();
            obj._initializing = false;
        });
    };
    
    obj._$initMasterById = function ( id ) {
        obj._$master = $jq('#' + id);
        obj._$findFieldIn(obj._$master).bind('change', obj.masterChanged);
    };

    obj._$findFieldIn = function ( $element ) {
        var field;
        if ($element.val()) {
            field = $element;
        } else if ($element.is('select') || $element.is('input')) {
            field = $element;
        } else if (obj._$elementHasSelect($element)) {
            field = $element.find('select');
        } else {
            field = $element.find('input');
        }
        if (typeof field == 'undefined') {
            throw new $L.Error("UIFormElementDependencyFilter assigned a master without a form element.", {masterId:obj._masterId, slaveClass:obj._slaveClass});
        }
        return field;
    }
    
    obj._$elementHasSelect = function ( $element ) {
        return $element.is('select') || ($element.find("select").size() > 0);
    };

    obj._$indexSlaves = function ( ) {
        $jq('.' + obj._slaveClass)
            .each(function(){
                var slave = $jq(this);
                if (slave.attr('id') == "" || typeof slave.attr('id') == 'undefined') {
                    throw new $L.Error("UIFormElementDependencyFilter identified a slave by class without an id.", {masterId:obj._masterId, slaveClass:obj._slaveClass});
                }
                obj._slaves[slave.attr('id')] = slave;
                if ( obj._$elementHasSelect(slave)) {
                    obj._$cloneSlave( slave );
                }
            });
    };

    obj._$cloneSlave = function ( $element ) {
        obj._slaveClones[$element.attr('id')] = $element.clone();
    };
    
    
    obj._$fixIeLayout = function ( ) {
     





        if ($jq.browser.msie && (typeof obj.__ieFixed == 'undefined')) {
            obj._$master.parents('form').append(obj._$master.clone().attr('id', "IE6_HACK")).parent().find('#IE6_HACK').remove();
            obj.__ieFixed = true;
        }
    };

    obj._init();
    return obj;
};

function UIRating ( id, initialRating ) {
    var obj = $L.object(this);

    obj.id = id;
    obj.initialRating = initialRating; 

    obj.setRating = function ( rating ) {
        if (typeof rating == 'undefined') {
            rating = obj.initialRating;
        }
        obj._$setRatingField(rating);
        obj._$rollRatingImagesTo(obj.id, rating);
    };

    obj.rollToRating = function ( rating ) {
        if (typeof rating == 'undefined') {
            rating = obj.initialRating;
        }
        obj._$rollRatingImagesTo(obj.id, rating);
    };

    obj._$setRatingField = function ( rating ) {
        $jq('#'+obj.id+'_inputField').val(rating).change();
        obj.initialRating = rating;
    };

    obj._$rollRatingImagesTo = function ( id, rating ) {
        var wholepart = parseInt(rating);
        var numEmpty = 5 - wholepart;
        var halfpart = (parseFloat(rating) > wholepart);
        if (halfpart) {
            numEmpty--;
        }
        
        for (var i=1; i<=wholepart; i++) {
            $jq('#'+id+' .stars .star_'+ (i)).attr('src', '/images/ui/controls/UIRating/star_full.png');
        }
        if (halfpart) {
            $jq('#'+id+' .stars .star_'+ i++).attr('src', '/images/ui/controls/UIRating/star_half.png');
        }
        for (var e=0; e<numEmpty; e++) {
            $jq('#'+id+' .stars .star_'+ (e+i)).attr('src', '/images/ui/controls/UIRating/star_zero.png');
        }
    };

    obj._$createSetters = function() {
        var inc = 1;
        $jq('#' + obj.id + ' .stars img').each(
            function ( ) {
                var rating = inc + "";
                $jq(this)
                    .attr('title', $L.UIRatingDictionary.setterTitle.replace('%numberOf', rating))
                    .bind('click', function(){obj.setRating(rating); return false;})
                    .bind('mouseover', function(){obj.rollToRating(rating);})
                    .bind('mouseout', function(){obj.rollToRating();});
                inc++;
            }
            );
    };
    
    obj._init = function ( ) {
        obj._$createSetters();
        return obj;
    };

    return obj._init();
};
$L.add('UIRatings', []);
$L.add('initUIRating', function (id, rating) { $L.UIRatings[id] = new UIRating(id, rating); });
