/*
 * Habana Avenue
 *
 * http://twitter.com/habanaavenue
 * http://twitter.com/statuses/user_timeline/24640208.rss
 *
 */


/*
 * TODO
 *
 * - preload the video player still images
 *
 */


/*
 * A general trace, info, status message function that
 * attempts to output to a JS console. If no console is
 * available, and the second parameter is set to true, it
 *pandora will use alert() to show the message instead (e.g. for IE)
 *
 * @param m {string}    the message to be shown
 * @param forceIfConsoleDisabled    (optional) show an alert() if no console is available
 *
 */
var _trace = function( m ) {
    if ( iOS() ) {
        $('div#idebug').html( $('div#idebug').html() + '<br />' + m );
        return;
    }
    if ( Android() ) {
        $('div#adebug').html( $('div#adebug').html() + '<br />' + m );
        return;
    }
    try { console.log( m ); }
    catch (e) {
        if ( (arguments.length >= 2) && (arguments[1] == true) ) {
            alert( "TRACE/DEBUG MESSAGE\n\n" + m );
        }
    }
};
var trace = function( m /* , forceIfConsoleDisabled = false */ ) {
    //m = ( "\n" + m );
    if ( settings._DEBUG_LEVEL_ >= 2 ) {
        _trace( m );
    }
};

/*
 * Shows a debug output message.
 * Inherits all properties from trace() but has a different runlevel.
 * Messages are prepended with "[DEBUG]" to differenciate them from regular trace() messages.
 * See trace() function for more information.
 *
 * @param m {string}    the message to be shown
 * @param forceIfConsoleDisabled    (optional) show an alert() if no console is available
 *
 */
var debug = function( m /* , forceIfConsoleDisabled = false */ ) {
    if ( settings._DEBUG_LEVEL_ >= 1 ) {
        if ( arguments.length <= 2 ) {
            _trace( '[DEBUG] ' + m );
        }
        else {
            _trace( m, arguments[1] );
        }
    }
};

/*
 * Shows an error output message.
 * Inherits all properties from trace() but has the lowest runlevel.
 * Messages are prepended with two returns before and after the message, and
 * "[ERROR]" directly before the message to differenciate them from trace() or debug() messages.
 * Usually used only for "critical" errors and show stoppers.
 * See trace() function for more information.
 *
 * @param m {string}    the message to be shown
 * @param forceIfConsoleDisabled    (optional) show an alert() if no console is available
 *
 */
var error = function( m /* , forceIfConsoleDisabled = false */ ) {
    if ( settings._DEBUG_LEVEL_ >= 1 ) {
        if ( arguments.length <= 2 ) {
            _trace( "\n[ERROR]" + m + "\n" );
        }
        else {
            _trace( m, arguments[1] );
        }
    }
};


var lastError;


/*
 * Global settings object for Habana Avenue
 * Most of these should be set at design-time. For run-time options,
 * see the "session" class object
 *
 */
var settings = {
    
    _DEBUG_LEVEL_: 4,
    
    /* TODO: set this in production */
    siteURL: 'http://habanaavenue.com/habana/',
    
    navigation: {
        hoverHiddenPosition: '-100px',
        /* JS is awesome, so these can be used as array indices too,
           for example: settings.navigation.hoverStates['current_LI_ID'] to get value */
        hoverStates: {
            adagencies: '-256px',
            brands:     '-166px',
            networks:   '-80px',
            live:       '-10px',
            meet:       '36px'
        },
        /* Animation for main menu */
        top_animation: {
           /* Delay before top animation triggers after mouseover event */
           delay: 1000,
           /* Delta in pixels (this is to animate #stage@top) */
           delta: 70
        },
        /* Animation for C-block (#bottom-decoration) */
        bottom_animation: {
            /* Delay before bottom animation triggers after mouseover event */
            delay: 500,
            speed: 500
        },
        /* the final opacity of the faded in big hover taglines for the main nav */
        taglineFadeInTargetOpacity: '1.0',
        /* for testing - this will disable the AJAXified main nav */
        enableAJAX: true,
        /* seperate check for IE only */
        enableAJAX_IE: true
    },
    
    /* the speed at which the features glow fades in and out */
    featuresGlowFadeInSpeed: 400,
    featuresGlowFadeOutSpeed: 600,
    
    testimonials: {
        /* data source to pull the testimonials JSON from * /
        dataURL: 'inc/debug_testimonials_sample.json',*/
        dataURL: 'inc/testimonials.json.php',
        /* whether or not to limit the # of visible testimonials */
        limitVisible: false,
        /* if settings.testimonials.limitVisible == true then this is how many to show */
        limitVisibleCount: 6
    },
    
    /* video related settings */
    videos: {
        defaultWidth: 640,
        defaultHeight: 360,
        /* if the video is allowed to continue
         * to the next, automatically when finished playing */
        automaticAdvance: false,
        /* if the video will loop from last to first on NEXT,
         * or from first to last on PREVIOUS */
        circularPlayback: true,
        /* whether or not to start auto playing video when a feature thumbnail is clicked */
        automaticFeatureVideoStart: true,
        /* meta info next to player - hover speed for home mini gallery */
        homeMiniGalleryMetaFadeSpeed: 200
    },
    
    /* Habana's public Twitter timeline in JSON format */
    twitterPublicTimeline: 'proxy.php?url=http://api.twitter.com/1/statuses/user_timeline.json?screen_name=habanaavenue&count=5',
    
    /* slide scrolling (instead of faux scrollbars) */
    slidescroll: {
        /* how far to scroll each time an up/down button is pressed */
        scrollAmountPress: 105,
        scrollAmountCategories: 187,
        /* speed of the animation, in milliseconds (too fast or slow will be choppy) */
        scrollSpeed: 500,
        /* TODO: these can probably be set permanently in the CSS instead of @ runtime */
        /* height of slidescrollable container (will hide any overflow) for PRESS */
        containerSizePress: '208px',
        /* height of slidescrollable container (will hide any overflow) for CATEGORIES */
        containerSizeCategories: '400px'
    },
    
    footerTopOffsets: {
        home: '665px',
        categories: '870px',
        about: '0px',
        news: '0px',
        contact: '0px'
    }
    
}; // settings


/*
 * Global attributes for the current user session of Habana Avenue
 * Most of these will be set at run-time. For design-time options,
 * see the "settings" class object.
 *
 */
var session = {
    
    /* prevent navigation animation from doubling up */
    isAnimatingNavigation: false,
    
    /* dynamically updated list of testimonials */
    testimonials: [],
    
    /* allow testimonials rotator to be paused (on mouse hover, for example) */
    testimonialsPaused: false,
    
    
    /* currently held values (e.g. indices) for this session */
    current: {
        
        /* the index of which testimonial is showing */
        testimonial: -1,
        
        /* video that is showing */
        video: -1,
        
        /* video object for DOM manipulation (mostly a QuickTime dependancy) */
        videoObject: null,
        
        /* meta that appears next to player */
        videoMeta: {
            title: '',
            video_meta1: '',
            video_meta2: '',
            video_meta3: '',
            video_meta4: ''
        }
        
    } /* session.current{} */,
    
    /* category specific video content - empty until populated when a page needs it, dynamically */
    videos: [],
    /* ALL videos, needs to be filtered for specific categories */
    _videos: [],
    
    /* tweets from Habana's public timeline */
    tweets: [],
    
    /* number of available rows of #features we can scroll */
    featuresRowCount: 0,
    /* #features carousel clicks - to tell if @ top or bottom */
    featuresCurrentRow: 2
    
}; // class session


/*
 * Global collection of timers (set at run-time) to allow for
 * starting and stopping window based loops.
 *
 */
var timers = {
    
    /* rotating testimonials */
    testimonials: -1
    
}; // class timers






/*
 * Testimonials class object for retrieving, displaying
 * and controlling playback of the rotating testimonials widget
 *
 * TODO: set the ul#dots li count to the total # of session.testimonials at runtime
 *
 */
var testimonials = {
    
    /*
     * TODO: randomize what 6 get shown
     * 
     * Retrieves the JSON data for the "testimonials" widget
     * from the data source (see global "settings" object)
     * and saves them into the global session.testimonials[]
     * array for later, client-side use.
     *
     * @param callback {function} Callback function to be triggered
     *      once the data has been loaded from the server and cached client-side
     *
     */
    load: function( /* callback = function(){} */ ) {
        
        trace( 'testimonials.load() : Loading Testimonials data' );
        
        var testimonialsLoadCallback = null;
        
        if ( (arguments.length == 1) ) {
            // wait until testimonials data is fetched to error check the callback
            testimonialsLoadCallback = arguments[0];
        }
        
        $.get( settings.testimonials.dataURL, {}, function(responseTestimonials) {
            
            trace( "\t>> " + responseTestimonials.length + 'bytes loaded' );
            
            session.testimonials = eval( '(' + responseTestimonials + ')' );
            
            trace( "\t>> " + responseTestimonials.length + ' testimonials found' );
            
            if ( responseTestimonials.length < settings.testimonials.limitVisibleCount ) {
                error( 'The number of visible testimonials (settings.testimonials.limitVisibleCount) ' +
                    'exceeds the number of testimonials found.' );
                debug( 'Setting the number of visible testimonials to the number of testimonials found. (' +
                    responseTestimonials.length + ')' );
                settings.testimonials.limitVisibleCount = responseTestimonials.length;
            }
            
            // only use the first 6
            if ( (settings.testimonials.limitVisible) && (session.testimonials.length > settings.testimonials.limitVisibleCount) ) {
                session.testimonials = session.testimonials.slice( 0, settings.testimonials.limitVisibleCount );
            }
            
            trace( "\t>> " + (session.testimonials.length + 1) + ' testimonials saved' );
            
            if ( testimonialsLoadCallback !== null ) {
                trace( "\t>> found possible callback function" );
                if ( typeof(testimonialsLoadCallback) !== 'function' ) {
                    error( 'Callback function for "testimonials.load()" is broken or not a function.' );
                }
                else {
                    testimonialsLoadCallback();
                }
            }
            
        }, 'text/javascript' );
    },
    
    /*
     * Starts the timer loop for updating the current (visible) testimonial on the page
     *
     */
    start: function() {
        trace( 'testimonials.start() : Starting "testimonials" timer.' );
        if ( timers.testimonials !== -1 ) {
            trace( "\t>> already started" );
            trace( "\t>> NOOP" );
        }
        else {
            testimonials.next();
            timers.testimonials = window.setInterval( function() {
                testimonials.next();
            }, 10000 );
            trace( "\t>> " + timers.testimonials );
        }
    },
    
    /*
     * Stops the timer loop for updating the current (visible) testimonial on the page
     *
     */
    stop: function() {
        trace( 'testimonials.stop() : Stopping "testimonials" timer.' );
        if ( timers.testimonials === -1 ) {
            trace( "\t>> already stopped" );
            trace( "\t>> NOOP" );
        }
        else {
            window.clearInterval( timers.testimonials );
            timers.testimonials = -1;
            trace( "\t>> " + timers.testimonials );
        }
    },
    
    /*
     * Updates the page DOM to show the testimonial object "objTestimonial"
     * on the page, using fade-out/fade-in
     *
     * @param objTestimonial {JSON} Testimonial object to be displayed
     *
     */
    update: function( objTestimonial ) {
        // actually visually updates the DOM on the page
        $('div#testimonials div#testimonials-content')
            .fadeOut( 1000, function() {
                $('div#testimonials div#testimonials-content')
                    .empty()
                    .html(
                        objTestimonial.quote +
                        '\n<br />' +
                        '<span id="testimonial-credit"> \
                            - ' + objTestimonial.credit + '\
                        </span>'
                    )
                    .fadeIn( 1000 );
            });
        // show current position in the testimonials queue using dots
        var testimonials = $('div#decoration-bottom div#content div#testimonials');
        
        var currentDot = $('ul#dots li.active', testimonials).prevAll().length || 6;
        
        $('ul#dots li.active', testimonials).removeClass( 'active' );
        var dots = $('ul#dots li');
        
        currentDot--;
        
        if ( (currentDot <= -1) || (currentDot > 5) ) {
            currentDot = 5;
        }
        
        // total - currentIndex because the dots are floated right, so they'd go in reverse otherwise
        $(dots[ currentDot ]).addClass( 'active' );
    },
    
    /*
     * Allows testimonials to be paused
     *
     */
    pause: function() {
        session.testimonialsPaused = true;
    },
    
    /*
     * Allows testimonials to continue rotating after being paused
     *
     */
    resume: function() {
        session.testimonialsPaused = false;
    },
    
    /*
     * Sets the current testimonial to the next logical item in the list,
     * optionally repeating the whole list from the beginning (see "circular" options
     * in the global "settings" class object, under testimonials)
     *
     */
    next: function() {
        // do not progress to the next testimonial if it is paused
        if ( session.testimonialsPaused ) return;
        if ( session.testimonials.length <= 0 ) {
            error( 'No testimonials are loaded.' );
        }
        else {
            if ( (session.current.testimonial <= -1) || (session.current.testimonial <= (session.testimonials.length - 2)) ) {
                // show the testimonial at the next index
                session.current.testimonial++;
            }
            else {
                // TODO: settings for looparound true/false
                // loop around and start from the beginning
                session.current.testimonial = 0;
            }
            //trace( 'current testimonial @ ' + session.current.testimonial + ' / ' + session.testimonials.length );
            testimonials.update( session.testimonials[session.current.testimonial] );
        }
    },
    
    /*
     * Sets the current testimonial to the previous logical item in the list,
     * optionally repeating the whole list from the end (see "circular" options
     * in the global "settings" class object, under testimonials)
     *
     */
    previous: function() {
        // do not receed to previous testimonial if it is paused
        if ( session.testimonialsPaused ) return;
        if ( session.testimonials.length <= 0 ) {
            error( 'No testimonials are loaded.' );
        }
        else {
            if ( session.current.testimonial >= 1 ) {
                // show the testimonial at the next index
                session.current.testimonial--;
            }
            else {
                // TODO: settings for looparound true/false
                // loop around and start from the beginning
                session.current.testimonial = ( session.testimonials.length - 1 );
            }
            testimonials.update( session.testimonials[session.current.testimonial] );
        }
    }
    
}; // class testimonials


/*
 * Twitter class object for retrieving Habana's public timeline
 *
 */
var twitter = {
    
    /*
     * Retrieves the JSON data from the public timeline defined
     * in the global "settings" class, and sets the global array
     * "session.tweets" with the necessary fields
     *
     */
    loadPublicTimeline: function( callback ) {
        
        // http://twitter.com/statuses/user_timeline/24640208.rss
        // http://twitter.com/statuses/user_timeline/24640208.json
        
        /* example tweet JSON
            {
                "geo":null,
                "in_reply_to_status_id":null,
                "favorited":false,
                "coordinates":null,
                "in_reply_to_screen_name":null,
                "in_reply_to_status_id_str":null,
                "in_reply_to_user_id":null,
                "source":"\u003Ca href=\"http:\/\/twitter.com\/\" rel=\"nofollow\"\u003ETwitter for iPhone\u003C\/a\u003E",
                "contributors":null,
                "user": {
                    "profile_background_image_url":"http:\/\/s.twimg.com\/a\/1290538325\/images\/themes\/theme5\/bg.gif",
                    "followers_count":6,
                    "url":"http:\/\/www.HabanaAvenue.com",
                    "show_all_inline_media":false,
                    "listed_count":0,
                    "geo_enabled":false,
                    "notifications":null,
                    "screen_name":"HabanaAvenue",
                    "lang":"en",
                    "profile_text_color":"3E4415",
                    "profile_sidebar_fill_color":"99CC33",
                    "profile_background_tile":false,
                    "time_zone":"Eastern Time (US & Canada)",
                    "following":null,
                    "favourites_count":0,
                    "friends_count":0,
                    "statuses_count":28,
                    "created_at":"Mon Mar 16 03:09:42 +0000 2009",
                    "profile_link_color":"D02B55",
                    "profile_sidebar_border_color":"829D5E",
                    "protected":false,
                    "id_str":"24640208",
                    "follow_request_sent":null,
                    "contributors_enabled":false,
                    "description":"",
                    "name":"Steven J. Levy",
                    "profile_use_background_image":true,
                    "location":"",
                    "id":24640208,
                    "is_translator":false,
                    "verified":false,
                    "utc_offset":-18000,
                    "profile_background_color":"352726",
                    "profile_image_url":"http:\/\/a3.twimg.com\/profile_images\/114758315\/HA_Crest_with_H___A_10-28-08_v2_normal.jpg"
                }
                ,
                "retweet_count":0,
                "in_reply_to_user_id_str":null,
                "created_at":"Wed Dec 22 14:35:36 +0000 2010",
                "place":null,
                "retweeted":false,
                "text":"Copy delivery on new site for january",
                "id_str":"17589074684551168",
                "id":17589074684551168,
                "truncated":false
            }
        */
        
        trace( 'twitter.loadPublicTimeline() : Retrieving Habana\'s public timeline from Twitter' );
        $.getJSON( settings.twitterPublicTimeline, {}, function(responseTwitter) {
            //alert( responseTwitter.data );
            session.tweets = eval( '(' + responseTwitter.data + ')' );
            trace( "\t>> loaded " + responseTwitter.data.length + ' tweets' );
            var tweets = [],
                tweetCount = ( (session.tweets.length > 5) ? 5 : session.tweets.length );
            for ( var i = 0; i < tweetCount; i++ ) {
                tweets.push( session.tweets[i].text );
            }
            callback();
            return tweets;
        });
        
    }
    
};



var scrolling = {
    /*
     * Gets the top offset (in pixels) of the vertical scrollbar
     * using multiple methods for cross browser compatibility
     *
     * @param onlyReturnObject {bool} When true, method returns the best object it was able
     *      to use to get the scrollTop offset (window, documentElement or body respectively)
     *
     */
    getTopOffset: function( /* onlyReturnObject = false */ ) {
        var possibleOffsets = {
            // prefered
            window: scrolling.getTopOffsetWindow(),
            // secondary
            document: scrolling.getTopOffsetDocument(),
            // auxilary
            body: scrolling.getTopOffsetBody()
        };
        // attempt window object first
        var offset = possibleOffsets.window;
        var offsetObject = window;
        // if that fails, check for document element
        if ( possibleOffsets.document && (!offset || (offset > possibleOffsets.document)) ) {
	    offset = possibleOffsets.document;
            offsetObject = document.documentElement;
        }
        //return possibleOffsets.body && (!offset || (offset > possibleOffsets.body)) ? possibleOffsets.body : offset;
        offset = ( possibleOffsets.body && (!offset || (offset > possibleOffsets.body)) ? possibleOffsets.body : offset );
        if ( (arguments.length === 1) && (arguments[0] === true) ) {
            return offsetObject;
        }
        else {
            return offset;
        }
    },
    /*
     * Gets the top offset of the vertical scrollbar
     * using the prefered method of invoking the "window" object
     *
     * (Note: this is a helper function for getTopOffset)
     *
     */
    getTopOffsetWindow: function() {
        return ( window.pageYOffset ? window.pageYOffset : 0 );
    },
    /*
     * Gets the top offset of the vertical scrollbar
     * using the secondary method of invoking the "documentElement" object
     *
     * (Note: this is a helper function for getTopOffset)
     *
     */
    getTopOffsetDocument: function() {
        return ( document.documentElement ? document.documentElement.scrollTop : 0 );
    },
    /*
     * Gets the top offset of the vertical scrollbar
     * using the auxilary method of invoking the "body" DOM element
     *
     * (Note: this is a helper function for getTopOffset)
     *
     */
    getTopOffsetBody: function() {
        return ( document.body ? document.body.scrollTop : 0 );
    },
    /*
     * Sets the top offset (in pixels) of the vertical scrollbar
     * using multiple methods for cross browser compatibility
     *
     */
    setTopOffset: function( offset ) {
        var objScrollable = scrolling.getTopOffset( true );
        if ( objScrollable === window ) {
            objScrollable.pageYOffset = offset;
        }
        else {
            objScrollable.scrollTop = offset;
        }
    },
    /*
     * (Same as setTopOffset, but animated)
     *
     */
    setTopOffsetAnimated: function( offset, speed ) {
        var objScrollable = scrolling.getTopOffset( true );
        if ( objScrollable === window ) {
            $(objScrollable).animate({
                pageYOffset: offset
            }, speed );
        }
        else {
            $(objScrollable).animate({
                scrollTop: offset
            }, speed );
        }
    }
};




/*
 * Videos class for dynamically loading and switching videos
 *
 * Note: not to be confused with session.videos which is an
 *      array of all videos loaded at runtime on a page.
 *
 * TODO: incorporate playVideo() function from standalone to a method in this class
 *
 */
var videos = {
    
    /*
     * Set a feature as "active" and show it's "Now Playing" overlay
     *
     * @param activeIndex {int} Index of video to be set as active **DEPRECATED**
     * @param activeIndex {bool} Set to <0 or False to remove all active videos
     *
     */
    setActive: function( activeIndex ) {
        
        //var activeFeature = $( $('ul.features li')[session.current.video] );
        var features = $('ul.features li');
        trace( '* videos.setActive()' );
        trace( '\t>> ' + features.length + ' features found' );
        var activeFeature = features.filter('.feature-active');
        trace( '\t>> active feature: ' + activeFeature );
        
        // hide the active feature's now playing info
        //$('a span.feature-hover p.feature-hover-nowplaying', activeFeature).fadeOut( 'slow' );
        $('ul.features li p.feature-hover-nowplaying').fadeOut( 'slow' );
        
        // hide the active feature's hover glow
        $('a span.feature-hover', activeFeature).stop(true, false).animate({
            opacity: '0'
        }, settings.featuresGlowFadeOutSpeed );
        
        // remove the active class from the active feature
        $(activeFeature).removeClass( 'feature-active' );
        $('.feature-active', features).removeClass('feature-active');
        $('span.feature-hover', features).css('opacity', '0');
        
        // set active to the new active feature
        activeFeature = $( features[session.current.video] );
        
        // make sure we have a valid index to set active
        debug( 'videos.setActive() activeIndex = ' + activeIndex );
        if ( (activeIndex !== false) && (activeIndex >= 0) ) {
            
            // add the active class the feature that was just clicked
            activeFeature.addClass( 'feature-active' );
            
            // show the now playing info for the newly active feature
            //$('a span.feature-hover', activeFeature).stop(true, false).fadeIn( settings.featuresGlowFadeOutSpeed );
            debug( 'showing feature-hover' );
            $('ul.features li.feature-active span.feature-hover')
                .stop(true, false)
                .css({
                    display: 'block',
                    opacity: '0'
                })
                .animate({
                    opacity: ($.browser.msie ? '0.94' : '1')
                }, settings.featuresGlowFadeOutSpeed);
            $('ul.features li.feature-active p.feature-hover-nowplaying').fadeIn( 'slow' );
            
        }
        
        
        //
        // features mini on home
        //
        if ( _page_ == 'home' ) {
            
            var minis = $('div#promenade div#player ul#player-features-mini li');
            
            //$('.feature-active', minis).removeClass('feature-active');
            $('.feature-active').removeClass('feature-active');
            
            $(minis[session.current.video]).addClass('feature-active');
            
        }
        
    }, /* videos.setActive */
    
    updateMeta: function( videoIndex ) {
        
        var pi = $('div#player div#player-right-panel div#player-info');
        
		pi.stop(true,false).fadeTo( settings.videos.homeMiniGalleryMetaFadeSpeed, '0', function() { 
			var video = session.videos[videoIndex]; 
			
			$(this).find('#player-info-title')
				.html(video.title).show(); 
			
			$(this).find('#player-info-brand span')
				.html(video.video_meta1).show(); 
			
			$(this).find('#player-info-client span')
				.html(video.video_meta2).show(); 
				
			$(this).find('#player-info-director span')
				.html(video.video_meta3).show(); 
			
			$(this).find('#player-info-comment span')
				.html(video.video_meta4).show(); 
			
			$(this).fadeTo( settings.videos.homeMinGalleryMetaFadeSpped, '1'); 
		}); 
		
		/*
        $('h3#player-info-title', pi).stop(true, false).fadeTo( settings.videos.homeMiniGalleryMetaFadeSpeed, '0', function() {
            $(this).empty().html(
                session.videos[videoIndex].title
            ).fadeTo( settings.videos.homeMiniGalleryMetaFadeSpeed, '1' );
        });
        
        try {
            $('div#player-info-brand span', pi).stop(true, false).fadeTo( settings.videos.homeMiniGalleryMetaFadeSpeed, '0', function() {
                $(this).empty().html(
                    session.videos[videoIndex].video_meta1
                ).fadeTo( settings.videos.homeMiniGalleryMetaFadeSpeed, '1' );
            });
        } catch (e) {}
        
        try {
            $('div#player-info-client span', pi).stop(true, false).fadeTo( settings.videos.homeMiniGalleryMetaFadeSpeed, '0', function() {
                $(this).empty().html(
                    session.videos[videoIndex].video_meta2
                ).fadeTo( settings.videos.homeMiniGalleryMetaFadeSpeed, '1' );
            });
        } catch (e) {}
        
        try {
            $('div#player-info-director span', pi).stop(true, false).fadeTo( settings.videos.homeMiniGalleryMetaFadeSpeed, '0', function() {
                $(this).empty().html(
                    session.videos[videoIndex].video_meta3
                ).fadeTo( settings.videos.homeMiniGalleryMetaFadeSpeed, '1' );
            });
        } catch (e) {}
        
        try {
            $('div#player-info-comment span', pi).stop(true, false).fadeTo( settings.videos.homeMiniGalleryMetaFadeSpeed, '0', function() {
                $(this).empty().html(
                    session.videos[videoIndex].video_meta4
                ).fadeTo( settings.videos.homeMiniGalleryMetaFadeSpeed, '1' );
            });
        } catch (e) {}
        */ 
    },
    
    /*
     * Determines what the next video in the list is
     * Note: this does NOT play the next video or change any "current" sessions
     *
     * @returns {boolean} false on error
     * @returns {JSON} object next video with all of it's properties
     *
     */
    next: function() {
        if ( session.videos.length <= 0 ) return false;
        if ( session.current.video >= (session.videos.length - 1) ) {
            // video playback is at the end of the queue
            if ( settings.videos.circularPlayback ) {
                // circular playback is enabled, so the "next" video
                // in the logical sequence is the first video in the list
                //session.current.video = 0;
                //return session.videos[0];
                return 0;
            }
            else {
                return false;
            }
        }
        else {
            // video playback is somewhere within the queue,
            // so advance to the next video
            //session.current.video++;
            //return session.videos[session.current.video];
            return ( session.current.video + 1 );
        }
    },
    
    /*
     * Determines what the previous video in the list is
     * Note: this does NOT play the previous video or change any "current" sessions
     *
     * @returns {boolean} false on error
     * @returns {JSON object} next video with all of it's properties
     *
     */
    previous: function() {
        if ( session.videos.length <= 0 ) return false;
        if ( session.current.video <= 0 ) {
            // video playback is at the beginning of the queue
            if ( settings.videos.circularPlayback ) {
                // circular playback is enabled, so the "previous" video
                // in the logical sequence is the last video in the list
                //session.current.video = session.videos.length;
                //return session.videos[session.current.video];
                return ( session.videos.length - 1 );
            }
            else {
                return false;
            }
        }
        else {
            // video playback is somewhere within the queue,
            // so receed to the previous video
            //session.current.video--;
            //return session.videos[session.current.video];
            return ( session.current.video - 1 );
        }
    },
    
    /*
     * Shows the next video in the queue and loads all associated meta data
     *
     * @returns {boolean} false on error
     * @returns {boolean} true on success
     *
     */
    showNext: function() {
        // attempt to get the next video index
        var nextVideo = videos.next();
        if ( nextVideo === false ) {
            // more verbose error messages
            if ( session.current.video === (session.videos.length - 1) ) {
                // session is already at the end of the queue
                debug( 'Session is already at the end of the queue, ' +
                    'and circular playback is not enabled.' );
            }
            else {
                // could not get the next video
                error( 'Could not determine next video.' );
            }
            // NOOP
            return false;
        }
        else {
            videos.showVideo( nextVideo );
            return true;
        }
    }, /* function videos.showNext */
    
    /*
     * Shows the previous video in the queue and loads all associated meta data
     *
     * @returns {boolean} false on error
     * @returns {boolean} true on success
     *
     */
    showPrevious: function() {
        // attempt to get the next video index
        var previousVideo = videos.previous();
        if ( previousVideo === false ) {
            // more verbose error messages
            if ( session.current.video === 0 ) {
                // session is already at the beginning of the queue
                debug( 'Session is already at the beginning of the queue, ' +
                    'and circular playback is not enabled.' );
            }
            else {
                // could not get the next video
                error( 'Could not determine next video.' );
            }
            // NOOP
            return false;
        }
        else {
            videos.showVideo( previousVideo );
            return true;
        }
    }, /* function videos.showPrevious */
    
    /*
     * TODO: documentation
     *
     *
     *
     */
    showVideo: function( index ) {
        
        // make sure the index is in bounds
        if ( (index < 0) || (index > session.videos.length) ) {
            return false;
        }
        
        // get the video's object for the index argument
        video = session.videos[index];
        
        trace(
            'Next video found\n' +
            '\tIndex: ' + index + '\n' +
            '\tTitle: ' + video.title + '\n' +
            '\tMedia: ' + video.video + '\n' +
            '\tStill: ' + video.still
        );
        
        // get the "now playing" section of the DOM
        var playerInfo = $(
            'div#player div#player-right-panel div#player-info'
        );
        
        // animate right panel (video information) out of view
        $('div#player div#player-right-panel').slideUp( 'slow', function() { 
            var pi = $(this).find('#player-info'); 
            pi.find('#player-info-title').html( video.title );
            pi.find('#player-info-client span').html( video.video_meta2 );
            pi.find('#player-info-brand span').html( video.video_meta1 );
            pi.find('#player-info-director span').html( video.video_meta3 );
            pi.find('#player-info-comment span').html( video.video_meta4 );
        });
        
        
        /* JK 3/5/11 - the below commented out block appears to be unecessary since we can just fade in the entire area when selecting the video, 
         * setting elements to display none rather than fading them out. 
        // update the current video's title
        $('h3#player-info-title', playerInfo)
            .animate({ opacity: '0' }, 'slow', function() {
                $(this).empty().html(
                    video.title
                ).animate({ opacity: '1' }, 'slow');
            });
        
        // update the current video's client
        // or hide it if no client is set for this video
        if ( video.video_meta2 == '' ) {
            $('div#player-info-client span', playerInfo)
                .empty().parent().fadeTo( 'fast', 0 );
        }
        else {
            $('div#player-info-client span', playerInfo).empty().html(
                video.video_meta2
            ).parent().fadeTo( 'fast', 1 );
        }
        
        // update the current video's brand
        // or hide it if no brand is set for this video
        if ( video.video_meta1 == '' ) {
            $('div#player-info-brand span', playerInfo)
                .empty().parent().fadeTo( 'fast', 0 );
        }
        else {
            $('div#player-info-brand span', playerInfo).empty().html(
                video.video_meta1
            ).parent().fadeTo( 'fast', 1 );
        }
        
        // update the current video's director
        // or hide it if no director is set for this video
        if ( video.video_meta3 == '' ) {
            $('div#player-info-director span', playerInfo)
                .empty().parent().fadeTo( 'fast', 0 );
        }
        else {
            $('div#player-info-director span', playerInfo).empty().html(
                video.video_meta3
            ).parent().fadeTo( 'fast', 1 );
        }
        
        // update the current video's comment
        // or hide it if no director is set for this video
        if ( video.video_meta4 == '' ) {
            $('div#player-info-comment span', playerInfo)
                .empty().parent().fadeTo( 'fast', 0 );
        }
        else {
            try {
            $('div#player-info-comment span', playerInfo).empty().html(
                video.video_meta4
            ).parent().fadeTo( 'fast', 1 );
            } catch (e) {}
        }
        */
	
        // update the current video's still image
        // and update the current video's FLV URL
        $('div#player div#player-video').empty().html(
            '<a href="' + video.video + '"> \
                <img src="images/' + video.still + '"> \
            </a>'
        );
        
        //
        // update our session to show the currently loaded video
        //
        session.current.video = index;
        
        // update the NEXT video title, or if the video about to be shown
        // is at the end of the queue (and circular playback is disabled), show nothing
        var playerPlaylistNextVideoTitle = $(
            'div#player div#player-right-panel ' +
            'div#player-playlist-simple div#player-playlist-next span'
        );
        if ( (index >= (session.videos.length - 1)) && !settings.videos.circularPlayback ) {
            playerPlaylistNextVideoTitle.empty();
        }
        else {
            playerPlaylistNextVideoTitle.empty().html(
                session.videos[videos.next()].title
            );
        }
        
        // update the PREVIOUS video title, or if the video about to be shown
        // is at the beginning of the queue (and circular playback is disabled), show nothing
        var playerPlaylistPreviousVideoTitle = $(
            'div#player div#player-right-panel ' +
            'div#player-playlist-simple div#player-playlist-previous span'
        );
        // TODO: recheck the logic here, since i'm very tired and it seems off...
        trace( 'cur: ' + session.current.video + "\n" + 'prev: ' + videos.previous() );
        if ( (index <= 0) && !settings.videos.circularPlayback ) {
            playerPlaylistPreviousVideoTitle.empty();
        }
        else {
            playerPlaylistPreviousVideoTitle.empty().html(
                session.videos[videos.previous()].title
            );
        }
        
        //
        // decide whether to show the still image or play a video
        //
        //if ( (_page_title_ == 'meet') || (_page_title_ == 'about') ) {
        function arrayIndexOf(a, q /*offset=0*/) {
            var o = ( (arguments.length >= 3) ? parseInt(arguments[2]) : 0 );
            if ( o > a.length ) return -1;
            for ( var i = o, m = a.length; i < m; i++ ) {
                if ( a[i] == q ) {
                    return i;
                }
            }
            return -1;
        }
        var mediaExt = video.video.split( '.' );
        mediaExt = mediaExt[mediaExt.length - 1].toLowerCase();
        if ( arrayIndexOf(['jpg', 'png', 'gif'], mediaExt) >= 0 ) {
            $('div#player div#player-video')
                .fadeTo( 1, '0.1', function() {
                    $(this).html(
                        '<img src="assets/thumbnails/' + video.still + '" />'
                    ).fadeTo( 'slow', '1.0' );
                });
        }
        else {
            // check if the video should be automatically started
            if ( settings.videos.automaticFeatureVideoStart ) {
                // trigger a faux click event on the video player
                debug( 'triggering #player-video faux click event' );
                //$('div#player div#player-video a').trigger( 'click' );
                debug( 'calling actual playVideo() function' +
                    '\n\t>> ' + session.videos[index].video);
                playVideo(
                    session.videos[index].video,
                    settings.videos.defaultWidth, settings.videos.defaultHeight, true
                );
            }
        }
        
        // somehow when everything's loaded in via AJAX, the #player gets hidden
        // even though it's set to absolute and z-indexed
        $('div#player').fadeIn( 'slow' );
        
        // animate right panel (video information) back into view
        debug( 'player-right-panel block?' );
		
        $('div#player div#player-right-panel').css('display', 'block').slideDown( 'slow' );
        
        
        /*
         * remove the previously "active" feature thumbnail, then
         * set the clicked item as "active" and reflect this by showing "now playing" label
         *
         */
        debug( 'videos.showVideo() calling videos.setActive(' +
            session.current.video + ')' );
        videos.setActive( session.current.video );
        
        return true;
        
    }, /* function videos.showVideo() */
    
    showStill: function( index ) {
        
        // make sure the index is in bounds
        if ( (index < 0) || (index > session.videos.length) ) {
            return false;
        }
        
        // get the video's object for the index argument
        video = session.videos[index];
        
        trace(
            'Next video found\n' +
            '\tIndex: ' + index + '\n' +
            '\tTitle: ' + video.title
        );
        
        // get the "now playing" section of the DOM
        var playerInfo = $(
            'div#player div#player-right-panel div#player-info'
        );
        
        // update the current video's title
        $('h3#player-info-title', playerInfo).empty().html(
            video.title
        );
        
        // update the current video's client
        // or hide it if no client is set for this video
        if ( video.video_meta2 == '' ) {
            $('div#player-info-client span', playerInfo)
                .empty().parent().fadeTo( 'fast', 0 );
        }
        else {
            $('div#player-info-client span', playerInfo).empty().html(
                video.video_meta2
            ).parent().fadeTo( 'fast', 1 );
        }
        
        // update the current video's brand
        // or hide it if no brand is set for this video
        if ( video.video_meta1 == '' ) {
            $('div#player-info-brand span', playerInfo)
                .empty().parent().fadeTo( 'fast', 0 );
        }
        else {
            $('div#player-info-brand span', playerInfo).empty().html(
                video.video_meta1
            ).parent().fadeTo( 'fast', 1 );
        }
        
        // update the current video's director
        // or hide it if no director is set for this video
        if ( video.video_meta3 == '' ) {
            $('div#player-info-director span', playerInfo)
                .empty().parent().fadeTo( 'fast', 0 );
        }
        else {
            $('div#player-info-director span', playerInfo).empty().html(
                video.video_meta3
            ).parent().fadeTo( 'fast', 1 );
        }
        
        // update the current video's still image
        // and update the current video's FLV URL
        $('div#player div#player-video').empty().html(
            '<a href="' + video.still + '"> \
                <img src="images/' + video.still + '"> \
            </a>'
        );
        
        //
        // update our session to show the currently loaded video
        //
        session.current.video = index;
        
        // update the NEXT video title, or if the video about to be shown
        // is at the end of the queue (and circular playback is disabled), show nothing
        var playerPlaylistNextVideoTitle = $(
            'div#player div#player-right-panel ' +
            'div#player-playlist-simple div#player-playlist-next span'
        );
        if ( (index >= (session.videos.length - 1)) && !settings.videos.circularPlayback ) {
            playerPlaylistNextVideoTitle.empty();
        }
        else {
            playerPlaylistNextVideoTitle.empty().html(
                session.videos[videos.next()].title
            );
        }
        
        // update the PREVIOUS video title, or if the video about to be shown
        // is at the beginning of the queue (and circular playback is disabled), show nothing
        var playerPlaylistPreviousVideoTitle = $(
            'div#player div#player-right-panel ' +
            'div#player-playlist-simple div#player-playlist-previous span'
        );
        // TODO: recheck the logic here, since i'm very tired and it seems off...
        trace( 'cur: ' + session.current.video + "\n" + 'prev: ' + videos.previous() );
        if ( (index <= 0) && !settings.videos.circularPlayback ) {
            playerPlaylistPreviousVideoTitle.empty();
        }
        else {
            playerPlaylistPreviousVideoTitle.empty().html(
                session.videos[videos.previous()].title
            );
        }
        
        //
        // show the still image instead of playing a video
        //
        //alert( video.still );
        $('div#player div#player-video').html(
            '<img src="' + video.still + '" />'
        );
        
        /*
         * remove the previously "active" feature thumbnail, then
         * set the clicked item as "active" and reflect this by showing "now playing" label
         *
         */
        debug( 'videos.showVideo() calling videos.setActive(' +
            session.current.video + ')' );
        videos.setActive( session.current.video );
        
        return true;
        
    }, /* function videos.showStill() */
    
    enableHandlers: function() {
        
        if ( _page_ == 'home' ) {
            $('div#introduction a').unbind('click').click( function(e) {
                e.preventDefault();
                setWindowURL( $(this).attr('href') );
                handleHashedURL(null);
            });
        }
        
        // add fadein/out animation instead
        // TODO: $.hover was acting funny, but switched from div to span, seems
        //      better... try that shorthand again?
        $('ul.features li a').mouseenter( function() {
            if ( !$(this).parent('li').hasClass('feature-active') ) {
                if ( $.browser.msie ) {
                    $('span.feature-hover', $(this)).css({
                        display: 'block',
                        opacity: '0.9',
                        filter: 'alpha(opacity=90)'
                    }).show();
                }
                else {
                    // the stop() prevents animations from doubling up
                    $('span.feature-hover', $(this))
                        .stop(true, false)
                        .animate({
                            opacity: '1'
                        }, settings.featuresGlowFadeInSpeed);
                }
            }
        });
        $('ul.features li a').mouseleave( function() {
            if ( !$(this).parent('li').hasClass('feature-active') ) {
                if ( $.browser.msie ) {
                    $('span.feature-hover', $(this)).css({
                        display: 'none',
                        opacity: '0',
                        filter: 'alpha(opacity=0)'
                    });
                }
                else {
                    // the stop() prevents animations from doubling up
                    $('span.feature-hover', $(this))
                        .stop(true, false)
                        .animate({
                            opacity: '0'
                        }, settings.featuresGlowFadeOutSpeed);
                }
            }
        });
        
        $('#player-features-mini').hover(
			function() { 
				$('#player-info-playing').fadeTo( 'slow', '0' )
			}, 
			function() { 
				$('#player-info-playing').fadeTo( 'slow', '1' );
			}
		); 
		
        $('div#player ul#player-features-mini li a').hover(
            function() {
                var index = $(this).parent('li').prevAll().length;
                // hide 'showing'
				trace('now playing opacity: ' + $('#player-info-playing').css('opacity')); 
				
				//$('div#player div#player-right-panel div#player-info span#player-info-playing').fadeTo( 'slow', '0' );
                videos.updateMeta( index );
            },
            function() {
                // show 'showing'
                //$('div#player div#player-right-panel div#player-info span#player-info-playing').fadeTo( 'slow', '1' );
                videos.updateMeta( session.current.video );
            }
        );
        
        
        /*
         * Show the video player with populated meta data
         * on click of a feature thumbnail
         * 
         */
        $('ul.features li a, ' +
          'div#promenade div#player ' +
          'ul#player-features-mini li a').click( function(e) {
            
            var parseQueryString = function( url, key ) {
                var qs = url.substring( url.indexOf('?') + 1 ),
                    qsParams = qs.split( '&' ),
                    kvp, retVal = '';
                for ( var i = 0, ii = qsParams.length; i < ii; i++ ) {
                    kvp = qsParams[i].split( '=' );
                    if ( kvp[0] === key ) {
                        retVal = kvp[1];
                    }
                }
                return retVal; 	
            }; 
            
            e.preventDefault();
            
            // TODO: consolidate these into global video class
            //if ( _page_title_ == 'meet' ) {
            //    videos.showStill( $(this).parent('li').prevAll('li').length );
            //}
            //else {
                // update the #player with the clicked video's content
                // - this was demonstrating odd behavior in IE- wasn't calculating the siblings correctly... 
                //videos.showVideo( $(this).parent('li').prevAll('li').length );
                // NO account for possible showing image instead of video (ATM, meet/live)
                var vtarget = $(this).attr('href').toLowerCase();
                //if ( ['jpg', 'png', 'gif'].indexOf( vtarget[vtarget.length - 1] ) >= 0 ) {
                //    // it's an image
                //    vtarget = vtarget.join('.').replace( '_S_', ''
                //}
                videos.showVideo( parseInt( parseQueryString( vtarget, 'vindex' ) ) ); 
            //}
            
            $('div#player').fadeIn( 400 );
            
            if ( $('div#player div#player-right-panel').css('display') != 'block' ) {
                $('div#player div#player-right-panel').show( 200 ).slideDown( 400 );
            }
            
            // make sure the viewport is at the top of the page so the video is visible
            if ( $(document).scrollTop() >= 1 ) {
                $('html, body').animate({
                    scrollTop: 0
                }, 'slow' );
            }
            
            //byC
            $(document).trigger('video-plays');
            
        });
        
        // Video player close button click
        $('div#player div#player-close a').click( function(e) {
            e.preventDefault();
            // animate right panel (video information) out of view
            $('div#player div#player-right-panel').slideUp( 'fast', function() {
                // hide the video player
                $('div#player').fadeOut( 300, function() {
                    // empty the player video container
                    $('div#player div#player-video').empty();
                    // remove the active state from the features gallery
                    videos.setActive( false );
                });
            });
        });
        
        // Video player large "still" image click (starts playing video)
        $('div#player div#player-video a, ' +
          'div#categories-feature a#categories-feature-play').click( function(e) {
            e.preventDefault();
            //debug( 'calling native playVideo() function' + '\n\t>> ' + session.videos[0].video );
            videos.showVideo( 0 );
        });
        
        
        // cache the simple playlist NEXT button DOM element
        var playerPlaylistSimpleNext = $(
            'div#player div#player-right-panel ' +
            'div#player-playlist-simple div#player-playlist-next a'
        );
        
        // cache the simple playlist PREVIOUS button DOM element
        var playerPlaylistSimplePrevious = $(
            'div#player div#player-right-panel ' +
            'div#player-playlist-simple div#player-playlist-previous a'
        );
        
        
        // determine what the next video's index is
        var nextVideo = videos.next();
        
        // event handler for simple playlist "NEXT" button
        playerPlaylistSimpleNext.click( function(e) {
            e.preventDefault();
            videos.showNext();
        });
        
        // event handler for simple playlist "PREVIOUSp" button
        playerPlaylistSimplePrevious.click( function(e) {
            e.preventDefault();
            videos.showPrevious();
        });
        
    } // function videos.enableHandlers()
    
}; // videos class


var iPhone = function() {
    return navigator.userAgent.toLowerCase().match( /(iphone|ipod)/ );
};
var iPad = function() {
    return navigator.userAgent.toLowerCase().match( /ipad/ );
};
var iOS = function() {
    //return navigator.userAgent.toLowerCase().match( /(iphone|ipod)/ ); // removed |ipad  cc
    return ( iPhone() || iPad() );
};
var Android = function() {
    return ( navigator.userAgent.toLowerCase().indexOf('android') >= 0 );
};
var isMobile = function() {
    return ( iOS() || Android() );
};


var playVideo = function( videoURL, width, height, autoPlay ) {
    
    trace( 'playVideo() : playing video \n\t>> ' + videoURL );
    
    if ( Android() || iPhone() ) {
        // use smaller vid
        videoURL = videoURL.substring(0, videoURL.lastIndexOf('.')) +
            '_m' + videoURL.substring(videoURL.lastIndexOf('.'));
        if ( (videoURL.indexOf('assets') <= -1) || (videoURL.indexOf('videos') <= -1) ) {
            videoURL = ( 'assets/videos/' + videoURL );
        }
    }
    
    // check for iOS devices
    //debug( 'checking for iOS device' );
    if ( iOS() ) {
        trace( '\t>> iOS device detected' );
        playVideoQuicktime( videoURL, width, height, autoPlay );
        return;
    }
    
    $('div#player div#player-video').empty();
    $('div#player div#player-video').width( width ).height( height );
    flowplayer( 'player-video', {src: 'flash/flowplayer.commercial-3.2.7.swf', wmode: 'opaque'}, {
        key: '#$614ab401df3ccc7f615',
        //play: { opacity: 0 },
        /*logo: {
            url: '/images/custom_logo_here.png',
            /*top: 20,
            right: 20,
            opacity: 0.4,
            width: '6.5%',
            height: '6.5%',* /
            fullscreenOnly: true,
            displayTime: 2000
	}*/
        contextMenu: [
	    'HabanaAvenue.com'
	],
        clip: {
            url: 'assets/videos/' + videoURL,
            autoPlay: autoPlay,
            autoBuffering: true,
            /*bufferLength: 6, /* seconds */
            /*live: false,
            onStart: function(){},
            onBegin: function(){},
            onResume: function(){},
            onPause: function(){},
            onFinish: function(){},
            onStop: function(){},
            onBegin: function () {},*/
            onFinish: function() {
                var nextVideo = videos.next();
                if ( nextVideo !== false ) {
                    videos.showNext();
                }
            }
        },
        /*playlist: [{
            url: 'images/video.png',
            scaling: 'orig',
        }, {
            url: videoURL,
            autoPlay: autoPlay,
            autoBuffering: true
        }],*/
        plugins: {
            controls: {
                url: 'flash/flowplayer.controls-3.2.5.swf',
                bottom: 0,
                opacity: 0.85,
                fullscreen: true,
                autoHide: 'always',
                hideDelay: 1000,
                playlist: false,
                backgroundGradient: 'low',
                fastForward: false,
                fastBackward: false,
                slowFoward: false,
                slowBackward: false
            }
        },
        onLoad: function() {
            this.setVolume( 90 );
        }
    });
};








// for quicktime support, since jQuery doesn't play nice
var addEventClassic = function( obj, evt, handler, captures ) {
    if ( document.addEventListener ) {
        trace( 'safari/ff/chrome/opera: using addEventListener()' );
        obj.addEventListener( evt, handler, captures );
    }
    else { /* IE */
        obj.attachEvent( ('on' + evt), handler );
    }
};

// all except autoPlay should be strings; autoPlay is boolean
var playVideoQuicktime = function( url, width, height, autoPlay ) {
    
    //QT_WriteOBJECT(
    //    url, '100%', '100%', '',
    //    'AUTOPLAY', 'True', 'SCALE', 'Aspect'
    //);
    
    trace( 'QuickTime video trying to load URL:\n\t' + url );
    
    var vw = width;
    var vh = height;
    
    var w = ( (width == '') ? vw.toString() : width ); /* actual width 579 - player controls bar */
    var h = ( (height == '') ? vh.toString() : height ); /* actual height 450 */
    
    trace( 'QuickTime video player dimensions: ' + w + '/' + h );
    
    var params = [
        url, w.toString(), h.toString(), '',
        'autoplay', (autoPlay ? 'true' : 'false'),
        'scale', 'aspect', /*aspect, tofit*/
        'autohref', 'true',
        'kioskmode', 'false',
        'BGCOLOR', '#000000',
        'postdomevents', 'true'
    ];
    
    if ( arguments.length > 4 ) {
        for ( var i = 0; i < arguments.length; i++ ) {
            params.push( arguments[i] );
        }
    }
    
    var code = _QTGenerate( 'QT_WriteOBJECT_XHTML', true, params );
    
    // stage prom player player-video
    var player = $('div#stage div#promenade div#player div#player-video');
    player.empty().html( code );
    
    // allow the player to be accessed via JS
    $('object', player).attr('id', 'videoQT');
    $('embed', player).attr('name', 'videoQT');
    
    // update global access to current video
    session.current.videoObject = getVideoObject( 'videoQT' );
    
    $('object, embed').height( $('#playerContainer').height() );
    
    // start circular playlist
    $(session.current.videoObject).ready( function() {
        
        trace( 'QuickTime is ready, adding onFinished event' );
        
        addEventClassic( session.current.videoObject, 'qt_ended', function() {
            
            trace( 'QuickTime video finished playback' );
            
            debug( 'TODO: play next video automatically' );
            
        }, false );
        
    });
    
};


// gets the controllable video object (cross browser)
var getVideoObject = function( elementName ) {
    var v = document.getElementById( elementName );
    if ( typeof v == 'object' ) {
        return v;
    }
    else {
        if ( document.getElementsByName ) {
            return document.getElementsByName('videoQT')[0];
        }
        else {
            // OLD school
            var e = document.getElementsByTagName('embed')[0];
            for ( var i = 0; i < e.length; i++ ) {
                if ( e[i].name ) {
                    if ( e[i].name == 'videoQT' ) {
                        v = e[i];
                    }
                }
                else if ( e[i].getAttribute('name') ) {
                    if ( e[i].getAttribute('name') == 'videoQT' ) {
                        v = e[i];
                    }
                }
                else {
                    if ( e[i].getPropertyValue('name') == 'videoQT' ) {
                        v = e[i];
                    }
                }
            }
        }
    }
    return v;
    //return ( window[elementName] ? window[elementName] : document[elementName] );
};


/*
 * fancy special effects class
 *
 */
var effects = {
    
    mainNavigationDropInCascaded: function() {
        var navigationOldMarginTop = $('ul#navigation li').css('margin-top');
        var navigationFancyAnimationDelay = 500;
        if ( !$.browser.msie ) {
            $('ul#navigation li').each( function() {
                $(this).css({
                    marginTop: '-300px',
                    opacity: '0'
                });
                var currentItem = $(this);
                window.setTimeout( function() {
                    currentItem.animate({
                        marginTop: navigationOldMarginTop,
                        opacity: '1'
                    }, 'slow', 'easeInOutCirc' );
                }, (navigationFancyAnimationDelay * ($(currentItem).prevAll('li').length)) );
            });
        }
    }, /* function mainNavigationDropInCascaded() */
    
    /*
    featuresSlideFadeInOLD: function() {
        // fancy animate in #features effect
        var featuresOldMarginLeft = $('ul.features').css('margin-left');
        //var promenadeOldBackgroundImage = $('ul#promenade').css('background-image')
        $('ul.features').css({
            marginLeft: '-1000px',
            opacity: '0',
            filter: 'alpha(opacity=0)'
        });
        window.setTimeout( function() {
            $('ul.features').animate({
                marginLeft: /*featuresOldMarginLeft* / 0,
                opacity: '0.4',
                filter: 'alpha(opacity=40)'
            }, 'slow', 'easeInOutCirc', function() {
                //$('div#promenade').css( 'background-image', 'url()' );
                debug( 'fade back in of features complete (effects.featuresSlideFadeIn())' );
            });
        }, 1000 );
    },*/
    
    featuresSlideFadeIn: function() {
        
        //debug( 'featuresSlideFadeIn() : init' );
        
        var loc = window.location.href,
            prom = $('div#promenade, div#promenade div.dynamic-container ul.features'),
            con = $('div#decoration-bottom');
        
        prom.css({
            marginLeft: ( (parseInt(prom.css('margin-left')) >= 1000) ? '-1000px' : prom.css('margin-left') )/*,
            opacity: '0',
            filter: 'alpha(opacity=0)'*/
        });
        con.css({
            marginBottom: ( (parseInt(con.css('margin-bottom')) >= 1000) ? '-1000px' : con.css('margin-bottom') )/*,
            opacity: '0',
            filter: 'alpha(opacity=0)'*/
        });
        
        window.setTimeout( function() {
            
            //debug( 'featuresSlideFadeIn() : animating prom' );
            if ( $.browser.msie ) {
                prom.animate({ marginLeft: '0px' }, 600, 'easeInOutCirc');
            }
            else {
                prom.animate({
                    marginLeft: '0px',
                    opacity: '1'
                }, 600, 'easeInOutCirc');
            }
            
            //debug( 'featuresSlideFadeIn() : animating decoration bottom' );
            if ( $.browser.msie ) {
                con.animate({ marginBottom: '0px' }, 600, 'easeInOutCirc');
            }
            else {
                con.animate({
                    marginBottom: '0px',
                    opacity: '1'
                }, 600, 'easeInOutCirc');
            }
            
        }, 1000 );
        
    }
    
};


var slideScrollUp = function( /* optional element to remove wait flag from */ ) {
    var el = null;
    if ( arguments.length === 1 ) {
        el = arguments[0];
    }
    var scrollAmount = ( (_page_ == 'press') ? settings.slidescroll.scrollAmountPress : settings.slidescroll.scrollAmountCategories );
    if ( session.featuresCurrentRow < session.featuresRowCount ) {
        var ss = $('div#decoration-bottom div.slidescroll'),
            mt = parseInt( ss.css('margin-top') );
        if ( iOS() ) {
            ss.css('margin-top', (parseInt(ss.css('margin-top')) - scrollAmount) + 'px');
            $('div#decoration-bottom a.slidescroll-external-up').removeClass('pleasewait');
        }
        else {
            ss.animate({
                marginTop: (parseInt(ss.css('margin-top')) - scrollAmount) + 'px'
            }, settings.slidescroll.scrollSpeed, function() {
                $('div#decoration-bottom a.slidescroll-external-up').removeClass('pleasewait');
            });
        }
        session.featuresCurrentRow++;
        trace( 'enableSlideScroll() : Features gallery currently on row #' + session.featuresCurrentRow );
    }
    else {
        trace( 'enableSlideScroll() : Features has reached the end' );
    }
    trace( 'slideScrollUp() : Readjusting up/down controls' );
    slideScrollToggleControls();
    if ( el === null ) {
        $(el).removeClass('pleasewait');
    }
};


var slideScrollToggleControls = function() {
    var up = $('div#gallery-controls a.slidescroll-external-up'),
        down = $('div#gallery-controls a.slidescroll-external-down');
    if ( /*($('ul.features li').length <= 6) ||*/ (session.featuresCurrentRow >= session.featuresRowCount) ) {
        // hide the up button
        trace( 'hiding up slide button' );
        up.fadeTo( 'fast', '0' );
        if ( $.browser.msie ) up.css('visibility', 'hidden');
    }
    else {
        // show
        trace( 'slideScrollToggleControls() : Showing up slide button' );
        //$('div#gallery-controls a.slidescroll-external-up').fadeTo( 'fast', '1' );
        $('div#gallery-controls a.slidescroll-external-up').animate({
            opacity: '1'
        }, 'fast' );
        if ( $.browser.msie ) up.css('visibility', 'visible');
    }
    if (  (session.featuresCurrentRow <= 2) ) {
        // hide the down button
        trace( 'slideScrollToggleControls() : Hiding down slide button' );
        $('div#gallery-controls a.slidescroll-external-down').fadeTo( 'fast', '0' );
        if ( $.browser.msie ) down.css('visibility', 'hidden');
    }
    else {
        // show
        trace( 'slideScrollToggleControls() : Showing down slide button' );
        $('div#gallery-controls a.slidescroll-external-down').animate({
            opacity: '1'
        }, 'fast' );
        if ( $.browser.msie ) down.css('visibility', 'visible');
    }
    
    if ( $.browser.msie ) {
        window.setTimeout( function() {
            //http://chirpcreative.com/habana/images/x.gif
            $('body').supersleight({
                imgs: true,
                backgrounds: true,
                shim: 'images/x.gif',
                apply_positioning: true
            });
            if ( _page_ == 'home' ) {
                $('div#introduction, div#testimonials').fixPNG({
                    blankGIF:       'images/fixPNG_blank.gif',
                    sizingMethod:   'image',
                    forceBG:        true
                });
            }
        }, 2000 );
    }
    
};

var enableSlideScroll = function() {
    //if ( iOS() && (_page_ == 'press') ) return;
    var list = ( (_page_ == 'press') ? $('ul#press-articles li') : $('ul.features li') );
    // 3 features per row, 2 rows visible at a time
    session.featuresRowCount = ( Math.ceil(list.length / 3) /*- 2*/ );
    trace( 'enableSlideScroll() : There are ' + session.featuresRowCount +
        ' rows available to scroll.   (' + list.length + ' features)' );
    
    if ( (_page_ != 'categories') && (_page_ != 'press') && (_page_ != 'about') ) {
        return;
    }
    
    $('div#content').css({
        /* TODO: these offsets are total guesses */
        height: (
            (_page_ == 'press') ?
            settings.slidescroll.containerSizePress :
            settings.slidescroll.containerSizeCategories
        ),
        overflow: 'hidden'
    });
    
    var gc = $('div#gallery-controls'),
        up = $('.slidescroll-external-up', gc),
        down = $('.slidescroll-external-down', gc),
        rh = list.parent('ul').height();
    
    up.click( function(e) {
        e.preventDefault();
        trace( '[EVENT] slidescroll up click event' );
        if ( !$(this).hasClass('pleasewait') ) {
            $(this).addClass('pleasewait');
            slideScrollUp( $(this) );
        }
    });
    
    $('div#decoration-bottom a.slidescroll-external-down').click( function(e) {
        e.preventDefault();
        trace( '[EVENT] slidescroll down click event' );
        if ( !$(this).hasClass('pleasewait') ) {
            $(this).addClass('pleasewait');
            var scrollAmount = ( (_page_ == 'press') ? settings.slidescroll.scrollAmountPress : settings.slidescroll.scrollAmountCategories );
            var ss = $('div#decoration-bottom div.slidescroll'),
                mt = parseInt( ss.css('margin-top') );
            if ( (mt < 0) ) {
                if ( iOS() ) {
                    ss.css('margin-top', (parseInt(ss.css('margin-top')) + scrollAmount) + 'px');
                    $('div#decoration-bottom a.slidescroll-external-down').removeClass('pleasewait');
                }
                else {
                    ss.animate({
                        marginTop: (parseInt(ss.css('margin-top')) + scrollAmount) + 'px'
                    }, settings.slidescroll.scrollSpeed, function() {
                        $('div#decoration-bottom a.slidescroll-external-down').removeClass('pleasewait');
                    });
                }
                session.featuresCurrentRow--;
                trace( 'enableSlidescroll() : Features gallery currently on row #' + session.featuresCurrentRow );
            }
            slideScrollToggleControls();
        }
    });
    
    if ( list.length <= 2 ) {
        // hide the up/down slidescroll buttons
        $('div#gallery-controls a').fadeOut( 'slow' );
    }
    else {
        // show slidescroll buttons
        $('div#gallery-controls a').fadeIn( 'slow' );
    }
    
    slideScrollToggleControls();
    
}; // function enableSlideScroll()



var pulsate = function() {
    
    if ( $('div#branding a').hasClass('pulsate') ) {
        
        if ( $.browser.msie ) return;
        
        $('#light').animate({
            opacity: '1'
        }, {
            queue: true,
            duration: 300
        });
        
        $('#light').animate({
            opacity: '0.8'
        }, {
            queue: true,
            duration: 300,
            complete: function() {
                pulsate();
            }
        });
        
    }
    
};



var setWindowURL = function( url ) {
    
    if ( window.location.href === url ) {
        error( 'setWindowURL() : Window URL is already set; NOOP' );
        return;
    }
    
    window.location = url;
    window.location.href = url;
    
    // triggers
    handleHashedURL();
    
};

var vanillaURL = function() {
    var url = window.location.href;
    if ( url.indexOf('#') >= 0 ) {
        url = url.split('#');
        url.pop();
        url = url[0];
    }
    return url;
};


var handleHashedURL = function( navigationLink ) {
    
    trace( 'handleHashedURL() : Init "' + window.location.href + '"' );
    
    if ( window.location.href.indexOf('#') <= -1 ) {
        return;
    }
    
    // get the last hashed thing, in case of multiple hashes
    var hash = ( (window.location.href.indexOf('#') >= 0) ? window.location.href.split('#').pop() : '' );
    var action = hash.split(':').pop();
    var request = {
        URL: ( 'categories.php?page=' + action ),
        data: { ajax: 'true' },
        dataType: 'json'
    };
    
    trace( '\t>> AJAX loading page "' + action + '"' );
    
    debug( 'Hash detected @ ' + hash );
    
    if ( hash == '' ) {
        
        effects.featuresSlideFadeIn();
        
    }
    else {
        
        var pageName = hash.split(':')[1];
        
        debug( 'hash OK' );
        
        if ( $.browser.msie ) {
            
            request.URL += '&raw=true';
            request.data = {};
            request.dataType = 'html';
            
        }
        
        debug( 'AJAX requesting ' + request.URL );
        debug( '\t>> data: ' + request.data.toString() +
              '\n\t>> dataType: ' + request.dataType )
        
        //$.get( url, {}, function(rhtml) {
        $.ajax({
            url: request.URL,
            data: request.data,
            dataType: request.dataType,
            async: false,
            cache: false,
            error: function( xhr, status, message ) {
                //alert( message + '\n' + status + '\n' + xhr.statusText );
            },
            success: function( html, status, xhr ) {
                
                var p, c;
                
                if ( $.browser.msie ) {
                    // TODO: less error prone string parsing
                    c = html.indexOf('<ul class="features');
                    p = html.substring( 0, c );
                    c = html.substring( c );
                    debug( '#promenade content @ ' + p.length + 'bytes' );
                    debug( 'main content @ ' + c.length + 'bytes' );
                }
                else {
                    p = html.promenade.toString();
                    c = html.content.toString();
                }
                
                //var b = document.getElementsByTagName('body')[0];
                //var t = document.createElement('textarea');
                //t.rows = '50';
                //t.cols = '75';
                //t.value = p + '\n\n\n\n\n\n\n' + c;
                //b.innerHTML = '';
                //b.appendChild( t );
                //return;
                
                
                // update global variables so we know where we are
                $('body').attr('id', 'categories');
                //
                debug("\nPAGE IS NOW " + action + "\n");
                _page_ = 'categories';
                _page_title_ = action;
                //
                //debug( 'Changing videos category to ' + _page_title_ );
                session.videos = eval('session._videos.' + _page_title_);
                //debug( '\t>> Loaded ' + session.videos.length + ' videos in "' + _page_title_ + '".' );
                
                $('div#promenade div.dynamic-container')
                    .stop( true, false )
                    .animate({
                        opacity: '0',
                        marginLeft: '-1000px'
                    }, 1000, 'easeInOutCirc', function() {
                        // #prominade is now off the page
                        if ( $.browser.msie ) {
                            debug( 'Setting IE innerHTML for #promenade' );
                            var dp = document.getElementById('promenade');
                            dp = dp.getElementsByTagName('div');
                            for ( var i = 0, max = dp.length; i < max; i++ ) {
                                if ( dp[i].className == 'dynamic-container' ) {
                                    debug( '\n\t* found promenade in IE\n' );
                                    dp[i].innerHTML = p;
                                    break;
                                }
                            }
                        }
                        else {
                            $(this).empty().html( p );
                        }
                        // slide the #promenade back in
                        if ( $.browser.msie ) {
                            $(this).animate({
                                marginLeft: '0px'
                            }, 1000, 'easeInOutCirc' );
                            $(this).parent('div#promenade').animate({
                                marginLeft: '0px'
                            }, 1000, 'easeInOutCirc' );
                            $('ul.features', $(this)).animate({
                                marginLeft: '0px'
                            }, 1000, 'easeInOutCirc' );
                        }
                        else {
                            $(this).animate({
                                opacity: '1',
                                marginLeft: '0px'
                            }, 1000, 'easeInOutCirc' );
                            $(this).parent('div#promenade').animate({
                                opacity: '1',
                                marginLeft: '0px'
                            }, 1000, 'easeInOutCirc' );
                            $('ul.features', $(this)).animate({
                                opacity: '1',
                                marginLeft: '0px'
                            }, 1000, 'easeInOutCirc' );
                        }
                    });
                
                $('div#decoration-bottom div.dynamic-container')
                    .stop( true, false )
                    .animate({
                        opacity: '0',
                        marginBottom: '-1000px'
                    }, 800, 'easeInOutCirc', function() {
                        if ( $.browser.msie ) {
                            debug( 'Setting IE innerHTML for bottom content' );
                            var db = document.getElementById('decoration-bottom');
                            db = db.getElementsByTagName('div');
                            for ( var i = 0, max = db.length; i < max; i++ ) {
                                if ( db[i].className == 'dynamic-container' ) {
                                    debug( '\n\t* found bottom container in IE\n' );
                                    db[i].innerHTML = c;
                                    break;
                                }
                            }
                        }
                        else {
                            $(this).empty().html( c );
                        }
                        
                        $('ul.features').css({
                            opacity: '1',
                            marginLeft: '0px'
                        });
                        
                        if ( $.browser.msie ) {
                            $(this).css({
                                position: 'absolute',
                                left: '0px', /*($('div#promenade').offset().left + 'px'),*/
                                bottom: '-1000px',
                                marginLeft: '0px'
                            });
                            $(this).animate({
                                opacity: '1',
                                filter: 'alpha(opacity=100)',
                                bottom: '0px',
                                marginBottom: '10px'
                            }, 800, 'easeInOutCirc', function() {
                                enableSlideScroll();
                                // re-enable scrollbars
                                applyScrollbars();
                                // reapply the video gallery click handlers
                                videos.enableHandlers();
                                applyRoundedCorners();
                            });
                        }
                        else {
                            $(this).animate({
                                opacity: '1',
                                marginBottom: '10px'
                            }, 800, 'easeInOutCirc', function() {
                                enableSlideScroll();
                                // re-enable scrollbars
                                applyScrollbars();
                                // reapply the video gallery click handlers
                                videos.enableHandlers();
                                applyRoundedCorners();
                            });
                        }
                        
                    });
                
                // set active nav item
                debug( 'setting ' + _page_title_ + ' active in main nav' );
                $('ul#navigation li.active').removeClass( 'active' );
                $('ul#navigation li#' + _page_title_).addClass( 'active' );
                //subnav
                $('ul#navigation-secondary li.active').removeClass( 'active' );
                $('ul#navigation-secondary li#' + _page_title_).addClass( 'active' );
                
                session.featuresCurrentRow = 2;
                //if ( iOS() ) enableSlideScroll();
                slideScrollToggleControls();
                
                if ( isMobile() ) {
                    //var key = ( (_page_ === 'home') ? 'home' : ((_page_ === 'categories') ? 'categories' : 'contact') );
                    var key = ( (_page_ === 'home') ? 'home' : 'categories' );
                    //$('div#footer').css( 'top', settings.footerTopOffsets[key] );
                    //alert(
                    //    'you are in: ' + $('body').attr('id') +
                    //    '\n\nfooter is now at ' + $('div#footer').css('top') +
                    //    ',\nchanging to ' + settings.footerTopOffsets[key].toString()
                    //);
                    //if ( key == 'categories' ) {
                    //    $('div#footer').css('border', '1px #ff0000 solid');
                    //}
                    //else {
                    //    $('div#footer').css('border', '1px #00ff00 solid');
                    //}
                    if ( !iPad() ) {
                        $('div#footer').css('top', settings.footerTopOffsets[key].toString() + ' !important' );
                    }
                    //alert( 'footer top is now ' + $('div#footer').css('top') );
                    trace( 'key = ' + key );
                    trace( 'new footer top = ' + $('div#footer').css('top') );
                }
                
            } // AJAX success
            
        }); // AJAX call
        
    } // hash check
    
    
    
}; // function handleHashedURL()


var theaterMode = {
    
    init: function() {
        $("#curtain").css("height", $(document).height()).hide();
        $(".theater-switch").click(function(){
            $("#curtain").toggle();
            if ($("#curtain").is(":hidden"))
                $(this).html("Turn off the lights").removeClass("turnedOff");
             else
                $(this).html("Turn on the lights").addClass("turnedOff");
        });
    }
    
};


// preload an image
var preloadImage = function( src, callback ) {
    var img = new Image();
    img.onload = function() {
        callback();
        //trace( "\tpreload of " + src + ' finished' );
    };
    img.src = src;
};


var applyRoundedCorners = function() {
    if ( $.browser.msie ) return;
    $('ul.features li a img').imgr({
        size: '0',
        color: '#ffffff',
        radius: '4px'
    });
    $('ul.features li a img').width( '322px' )
    $('ul.features li a img').height( '180px' );
};


var applyScrollbars = function(/*options*/) {
    if ( iOS() ) return;
    if ( iOS() ) {
        var scrollables = document.getElementsByClassName('.scrollable');
        for ( var i = 0, m = scrollables.length; i < m; i++ ) {
            iScroll( scrollables[i] );
        }
        return;
    }
    trace( 'applyScrollbars() : Initializing scrollbars' );
    //$('.scrollable').scrollbars();
    //$('.scrollable').jScrollPane();
    $('.scrollable').jScrollPane({
        showArrows: true,
        maintainPosition: false,
        autoReinitialise: true,
        verticalDragMinHeight: 20,
        clickOnTrack: true
    });
    var p = $('div#promenade'),
        t = $('div.press-meta', p),
        c = $('div.scrollable', p),
        slh = 53, /* single line height */
        cho = 72; /* content height offset (height of #prom - h of #content) */
    //debug( 'applyScrollbars() : content height before: ' + c.height() );
    c.height( p.height() - (
        72 * parseInt(t.height() / slh)
    ));
    //debug( 'applyScrollbars() : content height after (adjusted): ' + c.height() );
};

/*
 * Determines if an object is within the viewport of the browser
 *
 */
var withinViewport = function( el /* return = false */ ) {
    var wh = viewportSize().height; //$(window).height(); // window height
    var ot = $(el).offset().top; // offset of object from top
    if ( (arguments.length >= 2) && (arguments[1] == true) ) {
        return Math.abs( (ot + $(el).height()) - wh );
    }
    else {
        // <= accepts 0 (flush against edge) too
        return ( (ot + $(el).height()) <= wh );
    }
};

var viewportSize = function() {
    var myWidth = 0, myHeight = 0;
    if( typeof( window.innerWidth ) == 'number' ) {
        //Non-IE
        myWidth = window.innerWidth;
        myHeight = window.innerHeight;
    } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
        //IE 6+ in 'standards compliant mode'
        myWidth = document.documentElement.clientWidth;
        myHeight = document.documentElement.clientHeight;
    } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
        //IE 4 compatible
        myWidth = document.body.clientWidth;
        myHeight = document.body.clientHeight;
    }
    return {
        width: myWidth,
        height: myHeight
    };
};



















// set to true to show error stack trace
var showErrorStackTrace = true;
if ( (window.location.href.indexOf('?jsdebug=') >= 0) || (window.location.href.indexOf('&jsdebug=') >= 0) ) {
    window.onload = function() {
        window.onerror = function(a, b, c) {
            if ( showErrorStackTrace ) {
                alert(
                    a + '\n' + b + '\n' + c + '\n\n' +
                    printStackTrace({e: lastError})
                );
                showErrorStackTrace = false;
            }
        };
    }
}

/*
 * This is the universal entry point for script execution.
 * All non-member, excutable code should be contained inside this
 * jQuery "DOM loaded" wrapper to allow for the page to be rendered
 * fully before any code is run.
 *
 */
var tt1 = -1;
$(function() {
    
    settings.navigation.enableAJAX_IE = ( $.browser.msie ? false : true );
    debug( 'Setting AJAX in IE to ' + settings.navigation.enableAJAX_IE );
    
    
    try {
        console.log( 'HABANA AVENUE' +
            '\n>> DEBUG LEVEL SET TO ' + settings._DEBUG_LEVEL_ + '\n' );
        console.log( ' ' );
    }
    catch (e) {}
    
    
    var loc = window.location.href;
    
    // this should be set in production, but just in case
    if ( loc.indexOf('localhost') >= 0 ) {
        settings.siteURL = 'http://localhost/habana/';
    }
    if ( loc.indexOf('chirpcreative.com') >= 0 ) {
        settings.siteURL = 'http://chirpcreative.com/habana/';
    }
    if ( loc.indexOf('habanaavenue.com') >= 0 ) {
        //settings.siteURL = 'http://test.habanaavenue.com/';
        settings.siteURL = 'http://habanaavenue.com/';
    }
    
    
    if ( (loc.indexOf('#') <= -1) ) {
        if ( (loc.indexOf('press.php') <= -1) && (loc.indexOf('contact.php') <= -1) /*&& (loc.indexOf('about.php') <= -1)*/ ) {
            if ( !iPhone() && settings.navigation.enableAJAX && settings.navigation.enableAJAX_IE && (loc.indexOf('debug=true') <= -1) ) {
                setWindowURL( 'index.php#' );
            }
        }
    }
    
    
    // no link focus rect
    $('body').delegate('a', 'click', function() {
        $(this).blur();
    });
    
    // no fake links!!
    $('body').delegate('a[href="#"]', 'click', function(e) {
        e.preventDefault();
        alert( '(not available yet)' );
    });
    
    // allow dead links to silently cancel, for debug
    $('body').delegate('a[href="#debug"]', 'click', function(e) {
        e.preventDefault();
        e.stopPropagation();
    });
    
    
    /*
     * CORNERS
     * global rounded corners for any CSS element with the class "corners-default"
     *
     */
    //$('.corners-default').corner( 4 );
    //$('div#promenade img, div.slidescroll ul li a img').imgr({
    applyRoundedCorners();
    
    /*
     * FEATURES
     * glow features on hover
     *
     */
    
    // first override the CSS hovers
    $('ul.features li a span.feature-hover').css({
        display: 'block',
        opacity: '0'
    });
    
    
    
    
    if ( !isMobile() ) {  
        var top_animation_timer,
            top_animation_active = false;
        $('ul#navigation li').hover(        
            function() {
                var self = this;
                if (top_animation_timer) {
                    clearTimeout(top_animation_timer);
                }
                top_animation_timer = setTimeout(function () {
                    $('#stage').stop().animate({'top': settings.navigation.top_animation.delta + 'px'}, settings.navigation.top_animation.speed);
                    $('#decoration-left').stop().animate({'top': settings.navigation.top_animation.delta + 80 + 'px'}, settings.navigation.top_animation.speed, function () {
                        top_animation_active = true;
                    });
                    
                    // show the appropriate large tagline
                    $('div#stage div#tagline')
                        .empty()
                        .html( $('span.tagline', $(self)).text() )
                        .stop(true, false)
                        .fadeTo( 200, settings.navigation.taglineFadeInTargetOpacity );
                    
                    //// slide the fancy underline to the currently hovered nav item
                    //$(self).parent('ul#navigation').stop(true, false).animate({
                    //    'background-position': settings.navigation.hoverStates[$(self).attr('id')]
                    //}, 'fast');
                    
                }, top_animation_active ? 0 : settings.navigation.top_animation.delay);
            },
            function() {
                var self = this;
                if (top_animation_timer) {
                    clearTimeout(top_animation_timer);
                }
                top_animation_timer = setTimeout(function () {
                    $('#stage').stop().animate({'top': '0px'},
                        settings.navigation.top_animation.speed);
                    $('#decoration-left').stop().animate({'top': '80px'},
                        settings.navigation.top_animation.speed, function () {
                        top_animation_active = false;
                    });
                    
                    // slide the fancy underline to the default / currently active nav item
                    $(self).parent('ul#navigation').stop(true, false).animate({
                        // debug: using brands as "current" page for now
                        backgroundPosition: '45px' /*settings.navigation.hoverHiddenPosition*/
                    }, 'slow');
                    
                    // hide the large tagline
                    $('div#stage div#tagline').stop(true, false).fadeOut( 200 );
                }, 300);
                
            }
            
        ); // navigation <li> hover
    }
    // sticky navigations
    $('li.active').removeClass('active');
    $('ul#navigation li#' + _page_title_).addClass( 'active' );
    // click delegate is below
    $('ul#navigation-secondary li#' + _page_title_).addClass( 'active' );
    $('ul#navigation-secondary li').delegate('a', 'click', function(e) {
        //e.preventDefault();
        // you only see this for a second when a subnavigation item
        // is clicked, but it's aesthetically pleasing
        $('ul#navigation-secondary li.active').removeClass( 'active' );
        $(this).parent('li').addClass( 'active' );
    });
    
    // ajaxify navigation + transitions
    //
    // AJAX a-go-go
    //
    $('ul#navigation li, ul#navigation-secondary li, div#introduction a').delegate( 'a', 'click', function(e) {
        
        e.preventDefault();
        //e.stopPropagation();
        
        // don't show top animation
        if ( !iOS() ) window.clearTimeout( top_animation_timer );
        
        // you only see this for a second when a navigation item
        // is clicked, but it's aesthetically pleasing
        $('ul#navigation li.active').removeClass( 'active' );
        $(this).parent('li').addClass( 'active' );
        
        debug( 'navigation click : Set ' + $(this).parent('li').attr('id') + ' to active' );
        
        var loc = window.location.href;
        var link = $(this).attr('href');
        //var isHome = false;
        //if ( (loc.indexOf('index.php') >= 0) || (loc.substring(loc.length-1) == '/') ) {
        //    isHome = true;
        //}
        var isCat = ( (link.indexOf('categories.php') >= 0) ? true : false );
        var isPress = ( (link.indexOf('press.php') >= 0) ? true : false );
        var isAbout = ( (link.indexOf('about.php') >= 0) ? true : false );
        var isContact = ( (link.indexOf('contact.php') >= 0) ? true : false );
        var isClientLogin = ( $(this).parent('li').attr('id') == 'client-login' );
        
        if ( iPhone() || !settings.navigation.enableAJAX || !settings.navigation.enableAJAX_IE || isCat || isPress || /*!isAbout ||*/ isContact || isClientLogin || (window.location.href.indexOf('debug=true') >= 0) ) {
            // follow link normally
            debug( 'page is not ajaxified; following normal link' +
                '\n\t>> ' + $(this).attr('href') );
            window.location = $(this).attr('href');
            return;
        }
        else {
            debug( 'page "' + $(this).attr('id') + '" (' + loc.substring(loc.lastIndexOf('/')) + ') IS SET AS AN AJAX LINK' );
        }
        
        var navigationLink = $(this);
        
        debug( 'Navigation AJAX intercept (attempt 01)' );
        
        setWindowURL( settings.siteURL + 'index.php#page:' + $(navigationLink).parent('li').attr('id') );
        // THIS IS CALLED ALREADY in setWindowURL() -- handleHashedURL( navigationLink );
        
        
        // sticky footer
        //if ( Android() ) {
        //    //if ( window.location.href.toLowerCase().indexOf('debug:true') >= 0 ) {
        //        var d = $('<div>').attr('id', 'adebug').css({
        //            position: 'absolute',
        //            top: '0px',
        //            left: '0px',
        //            width: '400px',
        //            height: '450px',
        //            color: '#000000',
        //            backgroundColor: '#ffffff',
        //            border: '1px #ff0000 solid',
        //            overflow: 'scroll',
        //            zIndex: '9999999',
        //            opacity: '0.7',
        //            fontFamily: 'Consolas, monospace'
        //        });
        //        $('body').append( d );
        //    //}
        //    var key = ( (_page_ === 'home') ? 'home' : ((_page_ === 'categories') ? 'categories' : 'contact') );
        //    $('div#footer').css( 'top', settings.footerTopOffsets[key] );
        //    //$('div#footer').css('top', '0px').animate({
        //    //    border: '1px #ff0000 solid',
        //    //    top: (settings.footerTopOffsets[key] + 'px')
        //    //}, 2000 );
        //    trace( 'key = ' + key );
        //    trace( 'new footer top = ' + settings.footerTopOffsets[key] );
        //}
        
    });
    
    
    // load testimonials
    testimonials.load( function() {
        
        // start rotating through the testimonials
        testimonials.start();
        
        // pause or resume testimonials on mouse hover
        $('div#testimonials').hover(
            function() {
                testimonials.pause();
            },
            function() {
                testimonials.resume();
            }
        );
        
    });
    
    
    //
    //
    //
    videos.enableHandlers();
    
    
    /*
     * Video player loading, previous and next functionalities
     *
     */
    
    // set the current video to the first in the list,
    // making sure the video queue has loaded properly
    if ( session.videos.length >= 1 ) {
        session.current.video = 0;
    }
    
    
    // on category pages, play video when feature's
    // image (or "watch" button) is clicked
    $('div#categories-feature').delegate('a#categories-feature-play', 'click', function(e) {
        e.preventDefault();
        // trigger faux click event for first (featured) video
        // note: div.scrollable intentionally left out of heirarchy, since it might be 'slidescroll'
        $($('div#decoration-bottom ul.features li a')[0]).trigger( 'click' );
    });
    
    
    /*
     * Universally apply scrollbars to anything with class "scrollable"
     *
     */
    trace( 'Determining if faux scrollbars are available' );
    if ( isMobile() ) $('.scrollable').css('overflow', 'auto');
    applyScrollbars();
    
    
    /*
     * fancy nav, features, etc. appearances
     * only on homepage
     *
     */
    if ( _page_ == 'home' ) {
        effects.mainNavigationDropInCascaded();
    }
    
    if ( window.location.href.indexOf('#') <= -1 ) {
        effects.featuresSlideFadeIn();
    }
    
    
    // contact QR code on hover
    $('div#contact li.QR-code a.show-QR-code').click( function(e) {
        e.preventDefault();
        $('div#contact li.QR-code div.QR-code-image').fadeOut('medium');
        $('li.QR-code, li.QR-code a').css('z-index', '40');
        $(this).parent('li').css('z-index', '51');
        $('div.QR-code-image', $(this).parent('li')).css('z-index', '50').fadeIn( 1, function() {
            // make sure QR code is not off the stage
            var pos = $(this).offset(),
                $qrimg = $(this).find('img'),
                qrtop = Math.ceil( pos.top + $qrimg.height() ),
                promtop = Math.ceil( $('div#promenade').offset().top + $('div#promenade').height() );
            if ( qrtop > promtop ) {
                trace( 'QR code is off the page... compensating' );
                trace( 'animating from ' + qrtop + ' to ' + ( parseInt($qrimg.css('top')) - parseInt($qrimg.height()) ) );
                //$qrimg.animate({
                //    top: ( parseInt($qrimg.css('top')) - parseInt($qrimg.height()) )
                //}, 500, 'easeInOutCirc' );
                $(this).animate({
                    marginTop: -( parseInt(qrtop - promtop) )
                }, 400);
            }
        });
        
        
    });
    
    $('div#contact li.QR-code div.QR-code-image a.hide-QR-code').click( function(e) {
        e.preventDefault();
        $(this).parent('div.QR-code-image').fadeOut( 'fast' );
    });
    
    
    //
    //
    //
    enableSlideScroll();
    
    
    
    
    // fun stuff
    var gl = new Image();
    gl.onload = function() {
        //
    };
    gl.src = 'images/light.png';
    $('div#branding a').hover(
        function() {
            //debug('lighting on');
            if ( $.browser.msie ) {
                $('div#light').stop(true, false).animate({
                    marginLeft: '-73px'
                }, 1000, function() {
                    $('div#branding a').addClass('pulsate');
                    //pulsate();
                });
            }
            else {
                $('div#light').stop(true, false).animate({
                    left: '-73px',
                    opacity: '1'
                }, 1000, function() {
                    $('div#branding a').addClass('pulsate');
                    pulsate();
                });
            }
        },
        function() {
            //debug('lighting off');
            $('div#branding a').removeClass('pulsate');
            if ( $.browser.msie ) {
                $('div#light').stop(true, false).animate({
                    marginLeft: '-156px'
                }, 600 );
            }
            else {
                $('div#light').stop(true, false).animate({
                    left: '-56px',
                    opacity: '0'
                }, 600 );
            }
        }
    );
    
    
    // ajaxify the nav if js is enabled
    $('ul#navigation li a, ul#navigation-secondary li#about a').each( function() {
        //$(this).attr( 'href', ('index.php?page=' + $(this).parent('li').attr('id')) );
        if ( !iPhone() && !$.browser.msie ) {
            $(this).attr( 'href', ('index.php#page:' + $(this).parent('li').attr('id')) );
        }
        //debug( 'ajax link set ' + $(this).parent('li').attr('id') + ' to ' + ('index.php#page:' + $(this).parent('li').attr('id')) );
    });
    
    
    //
    //
    //
    handleHashedURL( null );
    
    
    
    // preload all features gallery images
    for ( var i = 0, max = session.videos.length; i < max; i++ ) {
        trace( 'Preloading image #' + i + '/' + max + ' ' + session.videos[i].thumbnail );
        preloadImage( session.videos[i].thumbnail, function(){} );
    }
    // preload all thumbnails for every category for faster switching (prefetch)
    for ( var i = 0, max = session._videos.length; i < max; i++ ) {
        trace( 'Preloading image #' + i + '/' + max + ' ' + session_.videos[i].thumbnail );
        preloadImage( session._videos[i].thumbnail, function(){} );
    }
    
    
    //
    //
    //
    habanaEXP( settings );
    
    
    
    // twitter hangs ALOT so delay it until everything else is done loading
    $('ul#press-tweets').empty();
    if ( (window.location.href.indexOf('press.php') >= 0) || (_page_ == 'press') ) {
        window.setTimeout( function() {
            var tweets = twitter.loadPublicTimeline(function() {
                //for ( var i = 0; i < tweets.length; i++ ) {
                //    $('ul#press-tweets').add(
                //        '<li>' + tweets[i] + '</li>'
                //    );
                //}
                var s = '';
                // TODO: 5 needs to be settings.tweetsShowCount or something
                for ( var i = 0; i < 5/*session.tweets.length*/; i++ ) {
                    s += '\n<li style="margin:3px 0;">' + session.tweets[i].text + '</li>';
                }
                $('ul#press-tweets').html( s );
            });
        }, 3000 );
    }
    
    
    if ( iOS() ) {
        window.setTimeout( function() {
            var s = document.getElementsByClassName('scrollable');
            for ( var i = 0; i < s.length; i++ ) {
                new iScroll( s[i] );
            }
        }, 1000 );
    }
    
    if ( $.browser.msie ) {
        if ( _page_ == 'home' ) {
            $('div#light, div#introduction, div.dynamic-container').fixPNG({
                blankGIF:       'images/fixPNG_blank.gif',
                sizingMethod:   'image',
                forceBG:        true
            });
            // IE is dumb IE is dumb
            $('div#introduction').css('cursor', 'pointer').click( function() {
                //setWindowURL( $('a#intro-read-more-link', $(this)).attr('href') );
                setWindowURL( /*'about.php'*/ 'categories.php?page=about' );
            });
        }
    }
    
    
    //
    // faux debugger console for the iPad
    // (function _trace() works automatically)
    //
    if ( iOS() ) {
        if ( window.location.href.toLowerCase().indexOf('debug=true') >= 0 ) {
            var d = $('<div>').attr('id', 'idebug').css({
                position: 'absolute',
                top: '0px',
                left: '0px',
                width: '400px',
                minHeight: '450px',
                height: 'auto',
                color: '#000000',
                backgroundColor: '#ffffff',
                border: '1px #ff0000 solid',
                overflow: 'scroll',
                zIndex: '9999999',
                opacity: '0.7',
                fontFamily: 'Consolas, monospace'
            });
            $('body').append( d );
        }
    }
    
    
    //if ( iPad() ) {
    //    $('#branding').empty().html('<h3>stinky ios</h3>');
    //    //if ( window.location.href.toLowerCase().indexOf('debug:true') >= 0 ) {
    //        var d = $('<div>').attr('id', 'adebug').css({
    //            position: 'absolute',
    //            top: '0px',
    //            left: '0px',
    //            width: '400px',
    //            height: '450px',
    //            color: '#000000',
    //            backgroundColor: '#ffffff',
    //            border: '1px #ff0000 solid',
    //            overflow: 'scroll',
    //            zIndex: '9999999',
    //            opacity: '0.7',
    //            fontFamily: 'Consolas, monospace'
    //        });
    //        $('body').append( d );
    //    //}
    //    var key = ( (_page_ === 'home') ? 'home' : ((_page_ === 'categories') ? 'categories' : 'contact') );
    //    $('div#footer').css( 'top', settings.footerTopOffsets[key] );
    //    //$('div#footer').css('top', '0px').animate({
    //    //    border: '1px #ff0000 solid',
    //    //    top: (settings.footerTopOffsets[key] + 'px')
    //    //}, 2000 );
    //    trace( 'key = ' + key );
    //    trace( 'new footer top = ' + settings.footerTopOffsets[key] );
    //}
    
    
    
    if ( _page_title_ == 'contact' ) {
        
        // set QR code image by it's parent anchor's href URL
        //trace( $('li.QR-code a.show-QR-code').length + ' contacts found, setting qr codes...' );
        $('li.QR-code a.show-QR-code').each( function() {
            var src = $(this).attr('href');
            // prepend images/ if needed
            if ( src.substring(0, 'assets/qrcodes/'.length) != 'assets/qrcodes/' ) {
                src = 'assets/qrcodes/' + src;
            }
            //trace( 'setting QR image ' + src );
            $(this).parent('li').find('img').attr('src', src);
        });
        
        // auto save contacts order
        
        
        //$('ul li.QR-code').delegate( 'a.show-QR-code', 'click', function() {
        //    $(this).parent('li').parent('ul').find('li').css('z-index', '50');
        //    $($(this).parent(), $(this).parent().find('img')).css({
        //        border: '2px #ff0000 solid',
        //        zIndex: 999
        //    });
        //});
        
    } // contact page specific
    
    
    // auto advance to postion where news article is visible
    var curNewsItem = $('ul#press-articles li.current-article'),
        curNewsIndex = curNewsItem.prevAll().length,
        curNewsRow = parseInt( curNewsIndex / 3 /* items per row */ );
    if ( curNewsIndex >= 6 ) {
        session.featuresCurrentRow = ( curNewsRow || 0 );
        trace( 'Adjusting SlideScroll position to current article\n' +
            '\n>> Row: ' + curNewsRow + ', Index: ' + curNewsIndex );
        slideScrollUp();
    }
    
}); // jQuery DOM ready









/* nothing to see down here... move along. */

