/**
 * Globals (Defaults)
 */
var ISIE8 = false;
var TOUCHSUPPORT = false;
var TRANSITIONSUPPORT = false;


/**
 * Patching
 */
if (typeof console === 'undefined') {console = {log: function (msg) {/*$('#debug').text(msg);*/}};}
if (typeof Date.now === 'undefined') {Date.now = function () {return new Date().getTime();};}


/**
 * onDOMReady
 */
$(function () {
    // Debugging
    ///$(document).bind('keydown', function (e) {if (e.metaKey && e.which == 186) {e.preventDefault(); $('#guides').toggleClass('show');}});
    // $('*').each(function () {
    //     $(this).get(0).addEventListener('mousedown', function () {$('#debug').html($(this).attr('class'));}, false);
    // });
    
    // Set Globals
    ISIE8 = ($('#isIE8').css('display') == 'block');
    
    TOUCHSUPPORT = (typeof document.body.ontouchstart !== 'undefined');
    
    TRANSITIONSUPPORT = !!($('.header').getTransitionProperty());
    
    
    if (ISIE8) {
        $('body').addClass('ie8');
    }
    
    /***
    if (!TOUCHSUPPORT) {
        // Force Flash video on Desktop
        mejs.MediaElementDefaults.mode = 'shim';
    }
    */
    
    // Don't do fancy Masonry behaviors on iOS because they use left/top and suck
    if (!TOUCHSUPPORT) {
        // Animate from center-ish rather than left
        if (typeof $.Mason !== 'undefined') {
            $.Mason.prototype._appended = function ($content, callback) {
                var $newBricks = this._filterFindBricks($content)
                    .css({position: 'absolute', left: '45%'});
                var self = this;
                setTimeout(function () {
                    $newBricks.addClass('masonry-brick');
                    // add new bricks to brick pool
                    self.$bricks = self.$bricks.add($newBricks);
                    self.layout($newBricks, callback);
                }, 0);
            };
        }
    }
    
    if (TOUCHSUPPORT) {
        $('body').addClass('ios');
        
        // This fixes a bug with iOS5 fixed positioning.
        // Conditions of bug: Fixed position top bar, inital content height <= 100%, hidden content that scrolls, show hidden content, scroll to bottom
        // What happens: When you reload the page the fixed bar will flash at the bottom of the screen a second and then jump up back at the top... parts of the fixed bar will no longer be clickable until a second refresh
        // Possible cause: I believe the bug is created by the window's scroll position being set and then preserved on the first refresh, but when the page reloads the height is only 100% so the scroll position is somehow invalid.
        $('body').prepend('<div id="ios5fix" style="position: absolute; left: 0; top: 0; width: 100%; height: 101%;"></div>');
        setTimeout(function () {$('#ios5fix').remove();}, 100);
    
        $('a').each(function () {
            // Strangely, just putting a listener on links invokes the :hover and :active styles!
            $(this).get(0).addEventListener('touchstart', function () {}, false);
        });

        $('.header').get(0).addEventListener('touchmove', function (e) {e.preventDefault();}, false);
        if ($('.projects_nav').length) {
            $('.projects_nav').get(0).addEventListener('touchmove', function (e) {e.preventDefault();}, false);
        }
    }
    

    if ($('body.direct').length) {
        var $directOverlay = $('.direct .overlay').not('.project_details').first();
        if ($directOverlay.length) {
            $directOverlay.addClass('show current');
            $directOverlay.children('.inner').addClass('show');
        }
        $('body').removeClass('direct');
    }
    
    
    // Set a width on nav links so they bold without affecting layout
    $('.header .nav li a').each(function () {
        $(this).css('width', ($(this).width() + 8) + 'px');
    });
    $('.header .nav li a').last().each(function () {
        $(this).css('width', ($(this).width() + 1) + 'px');
    });
    
    // Overlays and Popovers
    $('.popover_screen').click(function (e) {_hidePopover();});
    
    
    // The first view to be shown is already loaded in the DOM, and thus does not need to be AJAX loaded
    // However, all subsequent loads (such as via back button) should behave as usual without this special condition
    // Some other pages should not be reloaded the first time they are shown if we are accessing
    // them directly, but should always be reloaded thereafter.
    // We also don't want to track this page view double in Google Analytics on initial page load,
    // but we do want to log subsequent view changes in Analytics
    var _skipReloadView = true;
    
    var _startURL = window.location.href;
    
    /**
     * A class to handle our dynamic view swapping, with AJAX loading and History.js integration
     */
    function View(url, viewClass, initFunc) {
        var self = this;
        
        // Not reliable until after activation
        this.isLoaded = false;
        
        this.init = function () {
            if (viewClass[0] == '.') {
                viewClass = viewClass.slice(1);
            }

            this.url = url;
            this.viewClass = viewClass;
            this.$view = $('.' + viewClass);
            this.initFunc = initFunc;
            
            if (this.url) {
                this.$links = $('a[href="' + this.url + '"]');
                this.bindLink();
                
            } else {
                this.$links = $(null);
            }
            
            if (this.url) {
                View.views[_getURI(this.url)] = this;
            }
        };
        
        this.bindLink = function () {
            this.$links.unbind('click.viewActivate');
            this.$links.bind('click.viewActivate', function (e) {e.preventDefault(); e.stopPropagation(); self.activate();});
        };
        
        this.highlightLink = function () {
            $('#topnav a').removeClass('current');
            this.$links.addClass('current');
        };
        
        this.activate = function () {
            if (window.History.enabled && this.url) {
                window.History.pushState(null, '', this.url);

            } else if (this.url && window.location.href != this.url) {
                window.location.href = this.url;
            }
        };
        
        // Will be called when view is shown directly OR when view is shown via browser back/forward button
        // Hence: this calls highlightLink()
        this.whenActivated = function () {
            if (View.active) {
                View.active.whenDeactivated();
            }
            View.active = this;

            this.highlightLink();
            
            if (_gaq && !_skipReloadView) {
		        _gaq.push(['_trackPageview', _getURI(this.url)]);
		    }
            
            if (!this.needsReload()) {
                _skipReloadView = false; // Do not skip subsequent loads
                this.isLoaded = true;
                this.show();
            
            } else {
                this.isLoaded = false;
                this.load();
            }
        };
        
        this.whenDeactivated = function () {    
        };
        
        this.beforeShow = function () {
            _hideSearch();
            _hidePopover();
        };
        
        this.beforeLoad = function () {
            _hideSearch();
            _hidePopover();
        };
        
        this.afterLoad = function () {
        };

        // show() and beforeShow() are not called when view is ajax loaded
        this.show = function () {
            this.initFunc(this.$view);
            
            this.beforeShow();
            
            _showOverlay(this.$view, this.afterShow);
        };
        
        this.afterShow = function () {};
        
        this.needsReload = function () {
            // If there's no content, then it needs a "reload" because it was never loaded
            return !(this.$view.length && this.$view.children().length);
        };
        
        this.load = function () {
            ///console.log('LOAD', this.viewClass, self.url);
            
            _transitionFadeIn($('p#loading'), function () {
                self.beforeLoad();

                // Scroll to top for new content
                window.scrollTo(0, 1);
                
                $.ajax({
                    url: self.url,
                    cache: false,
                    type: 'GET',
                    error: function (jqXHR, textStatus, errorThrown) {
                        alert(textStatus); // TODO... better error handling?
                        _transitionFadeOut($('p#loading'));
                    },
                    success: self.ajaxSuccess
                });
            });
        };
        
        this.ajaxSuccess = function (data, textStatus, jqXHR) {
            var $data = $(data);

            // Project (single)
            if ($data.find('.projects_nav').length && $data.find('#home_carousel').length && $data.find('.project_details').length) {
                $('body .projects_nav').empty();
                $('.projects_nav').html($data.find('.projects_nav').html());

                $('body #home_carousel').empty();
                $('#home_carousel').html($data.find('#home_carousel').html());

                $('#home_carousel').removeClass('initialized');

                $('body .project_details').empty();
                $('.project_details').html($data.find('.project_details').html());

                $('.project_details').removeClass('initialized');
                self.initFunc($('.project_details'));

                // TODO... load an un-cached copy of first carousel image and wait for it's onload event?
                // Or better: use imagesLoaded() jQuery plugin

                // Give DOM time to catch up to avoid flicker
                setTimeout(function () {
                    _transitionFadeOut($('p#loading'), function () {self.isLoaded = true; self.afterLoad();});
                }, 150);
                
                return;
                
            // Other
            } else if ($data.find('.overlay').length == 1) {
                $('.overlay, .inner').removeClass('show transitioned');
                ///$('#close_overlay').removeClass('show transitioned');

                var selector = '.' + $data.find('.overlay').attr('class').split(' ').join('.');
                if (selector != '.overlay') {
                    ///if (self.$view.length) {
                    // self.$view isn't reliable for blog posts because who know which blog post's
                    // view object we are in right now... it might not have $view set!
                    if ($(selector).length) {
                        $(selector).empty();
                        $(selector).html($data.find('.overlay').html());

                    } else {
                        // IE8 fails if there is a comment after the closing div.inner in ajax content
                        ///$('.overlay').last().after($data.find('.overlay'));
                        // IE8 also fails .after() sometimes... weird... using appendTo() instead I guess
                        $data.find('.overlay').appendTo($('body'));
                    }
                    
                    var $newOverlay = $(selector);
                    if ($newOverlay.length) {
                        // Store it so we don't do an ajax load again
                        self.$view = $newOverlay;

                        // Do this here while loading overlay is up to avoid flicker
                        self.$view.addClass('show current');
                        self.$view.children('.inner').addClass('show');

                        self.$view.removeClass('initialized');
                        self.initFunc(self.$view);

                        var delay = 350;
                        if (self.$view.hasClass('blog_post')) {
                            delay *= 2;
                        }

                        // Give DOM time to catch up
                        setTimeout(function () {
                            _transitionFadeOut($('p#loading'), function () {self.isLoaded = true; self.afterLoad();});
                        }, delay);

                        return;
                    }
                }
            }

            // Unknown Failure
            _transitionFadeOut($('p#loading'));
        };
    }
    View.views = {};
    View.active = null;
    window.View = View; // for debugging console access
    
    
    /**
     * Setup specific views
     */
    var blogView = new View('/blog', 'blog', _initBlog);
    blogView.afterShow = function () {
        $('#home_carousel').hide();
    };
    blogView.afterLoad = function () {
        $('#home_carousel').hide();
    };
    blogView.whenDeactivated = function () {
        $('#home_carousel').show();
    };
    blogView.init();
    
    var pressView = new View('/press', 'press', _initPress);
    pressView.afterShow = function () {
        $('#home_carousel').hide();
    };
    pressView.afterLoad = function () {
        $('#home_carousel').hide();
    };
    pressView.whenDeactivated = function () {
        $('#home_carousel').show();
    };
    pressView.init();
    
    new View('/about', 'about', _initAbout).init();
    
    new View('/contact', 'contact', _initContact).init();
    
    // Additional views setup in _initProjectLinks(), _initBlogLinks(), and _initProject()
    
    if ($('.ajax').length) {
        var homeView = new View('/', 'project_details', _initProject);
        homeView.needsReload = function () {
            // Blog posts need to be reloaded every time because you could load one blog post, then another, and then
            // hit back button...and the current blog post needs to be replaced with the contents of the previous one
            // ditto for 'project_details' and projects
            return !_skipReloadView;
        };
        homeView.beforeLoad = function () {
            _hideOverlay(true);
            _hideSearch();
            _hidePopover();
            _hideDrawer();
        };
        homeView.show = function () {}; // homepage will always be reloaded
        homeView.init();
    }
    
    $('#logo a').click(function () {window.location.href = '/';}); // Hard reload if logo is clicked
    
    
    // In a perfect world, we'd run these for the views that are preloaded,
    // but we can just run all of them like this, too.
    _initProject($('.project_details'));
    _initSearch();
    _initBrowse($('.browse_projects'));
    _initBlog($('.blog'));
    _initBlogPost($('.blog_post'));
    _initPress($('.press'));
    var _aboutTimer;
    _initAbout($('.about'));
    _initContact($('.contact'));
    
    
    // With views setup, and initialized, we can process the current URL and call _handleLocationChange explicitly to activate
    if (window.History.enabled) {
        $(window).bind('statechange', _handleLocationChange);

        // #hash style urls seem broken if you land on a project, so if we have one, do a hard redirect
        var hash = window.location.hash;
        if (hash[0] == '#') {
            hash = hash.slice(1);
        }
        if (hash.match(/^projects\/./)) {
            window.location.href = '/' + hash;
            return;
        }

        // Prep landing view
        _handleLocationChange();
    }
    
    function _getURI(url) {
        var uri = url.replace(/https?:\/\/[^\/]+/, '').replace(/[?#].*$/, '').replace(/\/$/, '');
        if (uri == '') {
            uri = '/';
        }
        
        return uri;
    }
    
    // When we have a URL change via History.js, activate the appropriate view
    function _handleLocationChange() {
		var state = window.History.getState(),
		    url = state.url,
		    uri = _getURI(state.url);
		
		///console.log(state);
		///console.log(url, uri);
				
		var view = View.views[uri];
		if (view) {
		    ///console.log(view);
		    view.whenActivated();
		    
		} else if (_startURL != url) {
            window.location.href = url;
        }
    }
    
    
    
    function _showDrawer($overlay) {
        ///console.log('_showDrawer');
        
        // We no longer want to stash when the drawers open, because we keep the nav bar there as a header
        clearTimeout(_stashTimer);
        
        // kinda hacky, but... hide home carousel nav assistants if a drawer is shown
        _transitionFadeOut($('#home_carousel .prevnext'));
        
        // .drawer .inner is not respecting min-height: 100%, so we'll force it
        if (!$('body').hasClass('ios')) {
            // The -160 accounts for top and bottom padding on .drawer .inner
            $('.overlay.drawer .inner').css('min-height', ($(window).height() - 160) + 'px');
        }
        
        if ($overlay.hasClass('project_details')) {
            $('.projects_nav').addClass('project_drawer_open');
            if (!TRANSITIONSUPPORT) {
                $('.toggle_arrow').animate({rotate: '180deg'}, 300);
                $('.browse_icon').animate({scale: '0'}, 300);
            }
            
        } else if ($overlay.hasClass('browse_projects')) {
            $('.projects_nav').addClass('browse_drawer_open');
            if (!TRANSITIONSUPPORT) {
                $('.toggle_arrow').animate({rotate: '180deg'}, 300);
            }
                        
            _transitionFadeOut($('.drawer_toggle .toggle_project'), function () {});
            _transitionFadeIn($('.drawer_toggle .toggle_browse, .projects_nav .browse_nav'), function () {});
        }
        
        var $inner = $overlay.children('.inner');
        
        // Overlay prep
        $('.overlay.current').removeClass('current');
        $overlay.addClass('current');
        $overlay.addClass('show');
        $inner.addClass('show');
        
        // Start drawer expanding
        $inner.transition(
            function () {
                $(this).addClass('transitionedDrawer animatingDrawer').addClass('expand');
            },
            function () {
                $(this).removeClass('transitionedDrawer animatingDrawer');
            },
            function () {
                // Prep for browsers that do not transition
                $inner.translate3d(0, '-100%', 0);
                
                $inner.addClass('expand');
                $inner.stop().animate({translateY3d: '0%'}, 700, function () {
                    $inner.translate3d(0, '0px', 0);
                });
            }
        );
                
        // Get rid of drop shadow on projects nav bar, and make sure it is not stashed
        $('.projects_nav .inner').removeClass('shadow stash');
    }
    
    function _hideDrawer(after) {
        ///console.log('_hideDrawer');
        
        $expandedInner = $('.drawer').not('.projects_nav').find('.inner.expand');
        
        // Get rid of open drawer classes on nav
        $('.projects_nav').removeClass('project_drawer_open browse_drawer_open')
        if (!TRANSITIONSUPPORT) {
            $('.toggle_arrow').animate({rotate: '0deg'}, 300);
            $('.browse_icon').animate({scale: '1'}, 300);
        }
        
        // Restore drop shadow on nav bar
        $('.projects_nav .inner').addClass('shadow');

        // Restore nav bar to project details state
        _transitionFadeOut($('.projects_nav .browse_nav'), function () {});
        _transitionFadeOut($('.drawer_toggle .toggle_browse'), function () {});
        _transitionFadeIn($('.drawer_toggle .toggle_project'), function () {});
        
        _stashDrawer($('.projects_nav'));
        
        var _after = function () {
            $expandedInner.removeClass('transitionedDrawer animatingDrawer show');
            $expandedInner.parent().removeClass('show');

            if (typeof after !== 'undefined') {
                after();
            }
        };
        
        if ($expandedInner.length) {
            // Collapse the open drawer
            $expandedInner.transition(
                function () {
                    $expandedInner.addClass('transitionedDrawer animatingDrawer').removeClass('expand');
                },
                _after,
                function () {
                    // Prep for browsers that do not transition
                    $expandedInner.translate3d(0, '0%', 0);
                    
                    $expandedInner.stop().animate({translateY3d: '-100%'}, 700, function () {
                        $expandedInner.removeClass('expand');
                        _after();
                    });
                }
            );
            
        } else if (typeof after !== 'undefined') {
            after();
        }
    }
    
    
    var _stashTimer;
    
    function _stashDrawer($overlay) {
        ///console.log('_stashDrawer');
        
        clearTimeout(_stashTimer);
        
        var $inner = $overlay.find('.inner');
        
        $inner.transition(
            function () {
                $(this).addClass('transitionedDrawer animatingDrawer').addClass('expand stash');
            },
            function () {
                $(this).removeClass('transitionedDrawer animatingDrawer');
            }, function () {
                // Prep for browsers that do not transition
                $inner.translate3d(0, '0px', 0);
                
                $inner.addClass('expand stash');
                $inner.stop().animate({translateY3d: '-33px'}, 700, function () {});
            }
        );
    }
    
    function _unstashDrawer($overlay, noAutoStash) {
        ///console.log('_ UN stashDrawer');
        
        var $inner = $overlay.find('.inner');
        
        $inner.transition(
            function () {
                $(this).addClass('transitionedDrawer animatingDrawer').removeClass('stash');
            },
            function () {
                $(this).removeClass('transitionedDrawer animatingDrawer');
            }, function () {
                // Prep for browsers that do not transition
                if ($inner.is(':animated')) {
                    return;
                } else if ($inner.translate3d().y != '0px') {
                    $inner.translate3d(0, '-33px', 0);
                }
                
                $inner.stop().animate({translateY3d: '0px'}, 700, function () {
                    $inner.removeClass('stash');
                });
            }
        );
        
        if (typeof noAutoStash == 'undefined' || noAutoStash === false) {
            clearTimeout(_stashTimer);
            _stashTimer = setTimeout(function () {
                _stashDrawer($overlay);
            }, 2000);
        }
    }
    
    
    function _showOverlay($overlay, after) {
        var $inner = $overlay.children('.inner');
        
        _hideDrawer();
        
        $('.overlay.current').removeClass('current');
        $overlay.addClass('current');
        
        var showInner = function () {
            // Scroll to top for new content
            window.scrollTo(0, 1);
            
            $overlay.removeClass('animating transitioned');
            _transitionFadeIn($inner, function () {
                // may still be up from a hanging ajax call, so hide it since
                // _showOverlay() is called for content that has already been loaded
                _transitionFadeOut($('p#loading'));
                after();
            });
            $('.overlay.show').not($overlay).removeClass('show animating transitioned');
            $('.inner.show').not($inner).removeClass('show animating transitioned');
        };
        
        if ($overlay.hasClass('show')) {            
            showInner();
            
        } else {
            $overlay.transition(
                function () {
                    $overlay.addClass('show animating transitioned');
                },
                showInner,
                function () {
                    // Prep for browsers that do not transition opacity
                    $overlay.css('opacity', 0);
                    
                    $overlay.addClass('show');
                    
                    $overlay.stop().animate({opacity: 1.0}, 700, function () {
                        showInner();
                    });
                }
            );
        }
    }
    
    function _hideOverlay(instantaneous) {
        var $overlay = $('.overlay.show');
        
        var removeShowStates = function () {
            $overlay.removeClass('show animating transitioned');
            $overlay.find('.inner').removeClass('show animating transitioned');
        };
        
        if (typeof instantaneous !== 'undefined' && instantaneous) {
            removeShowStates();
            return;
        }
        
        $overlay.transition(
            function () {
                $overlay.addClass('animating transitioned').removeClass('show');
            },
            removeShowStates,
            function () {
                $overlay.stop().animate({opacity: 0.0}, 700, function () {
                    removeShowStates();
                });
            }
        );
    }
    
    function _showSearch() {
        $('.search').addClass('show');
    }
    
    function _hideSearch() {
        $('.search').removeClass('show');
        $('#search_input').val('');
    }
    
    var _showPopoverTimer;
    var _doShowPopover;
    function _showPopover() {
        _doShowPopover = true;
        _transitionFadeIn($('.popover_screen'), function () {
            // Somebody could touch the screen to hide while it is still fading in
            // and before this callback executes, so we need to track state and check it
            if (_doShowPopover) {
                // Give DOM time to catch up to avoid flicker
                _showPopoverTimer = setTimeout(function () {
                    ///_transitionFadeOut($('p#loading'), function () {
                        _transitionFadeIn($('.popover'), function () {
                            /***
                            var player = $('#popoverPlayer').data('player');
                            if (player) {
                                ///player.play();
                            }
                            */
                        });
                    ///});
                }, 100);
            }
        }, 0.9);
    }
    
    function _hidePopover() {
        clearTimeout(_showPopoverTimer);
        _doShowPopover = false;
        
        var player = $('#popoverPlayer').data('player');
        if (player) {
            player.pause();
        }
        
        _transitionFadeOut($('.popover'), function () {
            _transitionFadeOut($('.popover_screen'), function () {
                $('.popover').css({
                    width: '',
                    height: ''
                });
            });
        });
    }
    
    function _initProjectLinks($links) {
        $links.each(function () {
            var $self = $(this);
            
            var projectView = new View($(this).attr('href'), 'project_details', _initProject);
            projectView.bindLink = function () {
                var self = this;
                this.$links.each(function () {
                    // The matching link in .projects_nav actually opens the drawer, so don't
                    // make it activate the view (which would cause an ajax load we don't want)
                    if (!$(this).parents('.projects_nav').length) {
                        $(this).click(function (e) {e.preventDefault(); e.stopPropagation(); self.activate();});
                    }
                });
            };
            projectView.needsReload = function () {
                // Blog posts need to be reloaded every time because you could load one blog post, then another, and then
                // hit back button...and the current blog post needs to be replaced with the contents of the previous one
                // ditto for 'project_details' and projects
                return !_skipReloadView;
            };
            projectView.beforeLoad = function () {
                _hideOverlay(true);
                _hideSearch();
                _hidePopover();
                _hideDrawer();
            };
            projectView.show = function () {
                this.beforeShow();
                
                _hideOverlay();
            };
            projectView.init();
        });
    }
    
    function _initBlogLinks($links) {
        $links.each(function () {
            var blogPostView = new View($(this).attr('href'), 'blog_post', _initBlogPost);
            blogPostView.needsReload = function () {
                // Blog posts need to be reloaded every time because you could load one blog post, then another, and then
                // hit back button...and the current blog post needs to be replaced with the contents of the previous one
                // ditto for 'project_details' and projects
                return !_skipReloadView;
            };
            blogPostView.init();
        });
    }
    
    function _initPopoverLinks($links) {
        $links.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            
            $self = $(this);
            ///_transitionFadeIn($('p#loading'), function () {
                _hideSearch();
                _loadPopover($self.attr('href'));
            ///});
        });
    }
    
    function _loadPopover(href) {
        $.ajax({
            url: href,
            cache: false,
            type: 'GET',
            error: function (jqXHR, textStatus, errorThrown) {
                alert(textStatus); // TODO... better error handling?
                _transitionFadeOut($('p#loading'));
            },
            success: function (data, textStatus, jqXHR) {
                var $data = $(data);
                
                if (_gaq && !_skipReloadView) {
    		        _gaq.push(['_trackPageview', _getURI(href)]);
    		    }
                
                // Image, Images, Video
                if ($data.find('.inner').length) {
                    $('body .popover').empty();
                    $('.popover').append($data.find('.inner'));
                    
                    $('.popover .inner').removeClass('initialized');
                    _initPopover($('.popover .inner'));
                    
                    _showPopover();
                    return;
                }
                
                // Unknown Failure
                _transitionFadeOut($('p#loading'));
            }
        });
    }
    
    function _initSocial($overlay) {
        if (typeof twttr !== 'undefined' && typeof twttr.widgets !== 'undefined' && typeof twttr.widgets.load !== 'undefined') {
            twttr.widgets.load();
        }

        if (typeof gapi !== 'undefined' && typeof gapi.plusone !== 'undefined' && typeof gapi.plusone.go !== 'undefined') {
            gapi.plusone.go();
        }
    }
    
    function _initProject($overlay) {
        if ($overlay.length && !$overlay.hasClass('initialized')) {
            // Full screen carousel setup
            _initHomeCarousel();
            
            // Start auto-stash timer
            $('#home_carousel').unbind('carouselReady.projects');
            $('#home_carousel').bind('carouselReady.projects', function () {
                _unstashDrawer($('.projects_nav'));
            });
            
            // If we click Projects in main nav when we are in projects view,
            // show the Browse Projects drawer
            $('#topnav li a[href="/"]').unbind('click.projects');
            $('#topnav a[href="/"]').bind('click.projects', function (e) {
                e.preventDefault();

                // When "/projects" view is shown, and drawer is then hidden, "/" does not
                // become the active view again... so check for either url
                if (View.active && (View.active.url == '/' || View.active.url == '/projects') && View.active.isLoaded) {
                    View.views['/projects'].activate();
                }
            });
            

            // Setup drawer opener / closer text link
            $('.projects_nav .drawer_toggle a').click(function (e) {
                e.preventDefault();
                e.stopPropagation();
                
                // TODO: put a check here to see if we're already animating a drawer, and if so, bail out?
                    
                // Open Project Details Drawer
                if (!$('.projects_nav').hasClass('project_drawer_open') && !$('.projects_nav').hasClass('browse_drawer_open')) {
                    // Important that this is cleared or fallback drawer animate() code gets screwed up
                    // and animate() finish callbacks do not fire correctly
                    clearTimeout(_stashTimer);

                    _showDrawer($('.project_details'));
                
                // Close any open drawer
                } else {
                    _hideDrawer();
                }
            });
            
            // Makes clicking outside of content area of drawer close the overlay
            $overlay.find('.inner').click(function (e) {e.stopPropagation();});
            $overlay.unbind('click.closeDrawer');
            $overlay.bind('click.closeDrawer', function () {
                _hideDrawer();
            });
            
            
            // Setup browse projects view
            var browseView = new View('/projects', 'browse_projects', _initBrowse);
            browseView.bindLink = function () {
                var self = this;
                this.$links.each(function () {
                    // The matching link in .browse_nav actually switches the browse projects subview,
                    // so don't make it activate the view (which would cause an ajax load we don't want)
                    if (!$(this).parents('.browse_nav').length) {
                        $(this).click(function (e) {e.preventDefault(); e.stopPropagation(); self.activate();});
                    }
                });
            };
            browseView.activate = function () {
                // Do not push a history state for browse projects
                this.whenActivated();
                
                // Important that this is cleared or fallback drawer animate() code gets screwed up
                // and animate() finish callbacks do not fire correctly
                clearTimeout(_stashTimer);
            };
            browseView.highlightLink = function () {};
            browseView.afterLoad = function () {
                _showDrawer(this.$view);
            };
            browseView.show = function () {
                this.initFunc(this.$view);

                this.beforeShow();

                _showDrawer(this.$view);
            };
            browseView.init();
            View.views['/awards'] = View.views['/projects'];
            
            
            // Setup browse nav between By Date and By Awards
            $('.browse_nav li a').click(function (e) {
                e.preventDefault();
                $('.browse_nav li a').removeClass('current');
                $(this).addClass('current');
                
                if (_gaq && !_skipReloadView) {
    		        _gaq.push(['_trackPageview', _getURI($(this).attr('href'))]);
    		    }
                
                _switchToInlay($('.inlay.browse_' + $(this).attr('rel')));
            });
            // Set initial nav state
            $('.browse_nav li a').removeClass('current');
            if ($('.inlay.browse_by_date').hasClass('show')) {
                $('.browse_nav li a').first().addClass('current');
            } else {
                $('.browse_nav li a').last().addClass('current');
            }
            
        
            // Setup stuff in details
            $overlay.find('.ribbons a').click(function (e) {e.preventDefault();});
            
            new Carouselstronaut($overlay.find('.details .carousel'), {$indicator: $overlay.find('.carousel_indicator'), marcopolo: true});
            
            _initProjectLinks($overlay.find('h2 a')); // make sure View is created for current project
            _initProjectLinks($overlay.find('.projects_list a'));
            
            _initSocial($overlay);
        
        
            $overlay.addClass('initialized');
        }
    }
    
    var _navAssistantsShownOnce = false;
    function _initHomeCarousel() {
        // Setup HTML5 video in carousel
        $('#home_carousel').find('video').each(function () {
            var $cover = $(this).parent('li').find('.videoCover');
            var $coverButton = $(this).parent('li').find('.videoCover .coverButton');
            
            // Set a fixed dimension based on load size for now to get MediaElementPlayer to be right size
            $(this).attr('width', $(this).width());
            $(this).attr('height', $(this).height());            
            var player = new MediaElementPlayer('#' + $(this).attr('id'), {features: []/*, videoWidth: $(this).width(), videoHeight: $(this).height()*/});
            $(this).data('player', player);
            
            var paused = true;
            
            // Intercept events to control video
            // Stop on touch
            if (TOUCHSUPPORT) {
                $cover.get(0).addEventListener('touchstart', function () {player.pause();}, false);
            } else {
                $cover.bind('mousedown', function () {player.pause();});
            }
            // Play/Pause on tap
            $coverButton.enableEventsTapFlick();
            $coverButton.bind('tap', function (data) {
                if (paused) {
                    player.play();
                    paused = false;

                } else {
                    player.pause();
                    paused = true;
                }
            });
        });
        
        // Firefox screws up Flash video in a translated container, so we have to use left CSS prop
        var forceLegacyAnimation = false;
        if ($('#home_carousel').getTransformProperty() == 'MozTransform') {
            forceLegacyAnimation = true;
        }
        
        // Setup JiantCarousel
        var jiantCarousel = new JiantCarousel($('#home_carousel'), {$prevnext: $('#home_carousel .prevnext'), forceLegacyAnimation: forceLegacyAnimation});

        jiantCarousel.showPrevnext = function () {
            if (!_navAssistantsShownOnce) {
                _navAssistantsShownOnce = true;
                
                _transitionFadeIn(this.$prevnext);
                setTimeout(function () {
                    jiantCarousel.hidePrevnext();
                }, 3000);
            }
        };
        
        jiantCarousel.hidePrevnext = function () {
            _transitionFadeOut(this.$prevnext);
        };
        
        jiantCarousel.parentGoPrev = jiantCarousel.goPrev;
        jiantCarousel.goPrev = function () {
            jiantCarousel.parentGoPrev();
            
            this.hidePrevnext();
        };
        
        jiantCarousel.parentGoNext = jiantCarousel.goNext;
        jiantCarousel.goNext = function () {
            jiantCarousel.parentGoNext();
            
            this.hidePrevnext();
        };
        
        if (TOUCHSUPPORT) {
            jiantCarousel.tapHandler = function (data) {
                // If the current carousel item is a video, cancel clicks in the middle
                // so they can control video instead of unstash drawer
                if (jiantCarousel.$moverLis.eq(jiantCarousel.index % jiantCarousel.$moverLis.length).hasClass('video')) {
                    if (data.pageX - this.$container.offset().left > this.$container.width() * 0.25 && data.pageX - this.$container.offset().left < this.$container.width() * 0.75) {
                        return; // do not pass go, do not collect $200
                    }
                }
                
                _unstashDrawer($('.projects_nav'));
            };
            
            $('#home_carousel').unbind('flick.home');
            $('#home_carousel').bind('flick.home', function (e, direction) {
                if (direction == 'up') {
                    _stashDrawer($('.projects_nav'));
                    
                } else if (direction == 'down') {
                    // Unstash or show details depending on stash state... feels more natural to me
                    if ($('.projects_nav .inner').hasClass('stash')) {
                        _unstashDrawer($('.projects_nav'));
                    } else {
                        _showDrawer($('.project_details'));
                    }
                }
            });
        
        } else {
            jiantCarousel.parentTapHandler = jiantCarousel.tapHandler;
            jiantCarousel.tapHandler = function (data) {
                // If the current carousel item is a video, cancel clicks in the middle
                // so they can control video instead of advance carousel
                if (jiantCarousel.$moverLis.eq(jiantCarousel.index % jiantCarousel.$moverLis.length).hasClass('video')) {
                    if (data.pageX - this.$container.offset().left > this.$container.width() * 0.25 && data.pageX - this.$container.offset().left < this.$container.width() * 0.75) {
                        return; // do not pass go, do not collect $200
                    }
                }
                
                jiantCarousel.parentTapHandler(data);
            }
        }
        
        if (jiantCarousel.count > 1) {
            $('#home_carousel').unbind('carouselReady.assistants');
            $('#home_carousel').bind('carouselReady.assistants', function () {
                jiantCarousel.showPrevnext();
            });
        }
        
        var _mouseInZone = false;
        $('body').unbind('mousemove.stash');
        $('body').bind('mousemove.stash', function (e) {
            if (e.pageY > 60 && e.pageY < 110) {
                // Don't unstash (thus causing the auto stash timer to start) if a drawer is open
                if (!_mouseInZone && $('.overlay.drawer.show').length == 0) {
                    _unstashDrawer($('.projects_nav'));
                }
                _mouseInZone = true;
                
            } else {
                _mouseInZone = false;
            }
        });
        
        
        setTimeout(function () {
            $('#home_carousel').trigger('carouselReady');
        }, 250);
    }
    
    function _initSearch() {
        var $search = $('.search');
        $('#search_input').keydown(function () {setTimeout(_loadSearch, 10); if (!$search.hasClass('show')) {_showSearch();}});
        $('#close_search, #search_screen').click(function (e) {
            e.preventDefault();

            if (!screenTapIgnore) {
                _hideSearch();
            }
        });
        var screenTapIgnore = false;
        if (TOUCHSUPPORT) {
            $('#search_input').blur(function () {
                // People will naturally tap outside of the keyboard not meaning to dismiss the search results
                screenTapIgnore = true;
                setTimeout(function () {
                    screenTapIgnore = false;
                }, 500);
            });
        }
        $('#search_form').submit(function (e) {e.preventDefault(); $('#search_input').blur();});
        _initSearchResults();
    }
    
    var _loadSearchTimer = null;
    var _loadSearchRequest = null;
    function _loadSearch() {
        var query = $('#search_input').val();
        if (query == '') {
            return;
        }
        
        clearTimeout(_loadSearchTimer);
        if (_loadSearchRequest) {
            _loadSearchRequest.abort();
        }
        
        _loadSearchTimer = setTimeout(function () {
            _loadSearchRequest = $.ajax({
                url: '/',
                data: {
                    s: query
                },
                cache: false,
                type: 'GET',
                error: function (jqXHR, textStatus, errorThrown) {
                    if (textStatus != 'abort') {
                        alert(textStatus); // TODO... better error handling?
                    }
                },
                success: function (data, textStatus, jqXHR) {
                    var $data = $(data);
                    
                    if ($data.find('.search_results .inner')) {
                        $('.search_results .inner').empty();
                        $('.search_results .inner').html($data.find('.search_results .inner').html());
                        
                        _initSearchResults();
                    }
                }
            });
        }, 300);
    }
    
    function _initSearchResults() {
        _initProjectLinks($('.search_results .projects_list a'));
        _initBlogLinks($('.search_results .posts_list a'));
    }
    
    function _initBrowse($overlay) {
        if (!$overlay.hasClass('initialized')) {
            // Makes clicking outside of content area of drawer close the overlay
            $overlay.find('.inner').click(function (e) {e.stopPropagation();});
            $overlay.unbind('click.closeDrawer');
            $overlay.bind('click.closeDrawer', function () {
                _hideDrawer();
            });
            
            // Set a width on nav links so they bold without affecting layout
            $('.browse_nav li a').each(function () {
                $(this).css('width', ($(this).width() + 10) + 'px');
            });

            /*** having to do this in _initProject() now instead /***
            // Setup browse nav between By Date and By Awards
            $('.browse_nav li a').click(function (e) {
                e.preventDefault();
                $('.browse_nav li a').removeClass('current');
                $(this).addClass('current');
                _switchToInlay($('.inlay.browse_' + $(this).attr('rel')));
            });
            */
            
            _initProjectLinks($overlay.find('.projects_list a'));
            
            $overlay.addClass('initialized');
        }
    }
    
    function _initBlog($overlay) {
        if ($overlay.length && !$overlay.hasClass('initialized')) {
            _initBlogBrowsePosts($overlay.find('.post'));
            
            _initInfiniteMasonry('blog', _initBlogBrowsePosts);
            
            $overlay.addClass('initialized');
        }
    }
    
    function _initBlogBrowsePosts($posts) {
        // Entire post is clickable
        $posts.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            $(this).find('a[href*="/blog"]').first().click();
        });
        
        $posts.hover(function () {$(this).toggleClass('hovered')});
        
        _initBlogLinks($posts.filter('.article').find('a[href*="/blog"]'));
        _initPopoverLinks($posts.filter('.images,.video').find('a[href*="/blog"]'));
    }
    
    function _initBlogPost($overlay) {
        if ($overlay.length && !$overlay.hasClass('initialized')) {        
            new Carouselstronaut($overlay.find('.carousel'), {$indicator: $overlay.find('.carousel_indicator'), marcopolo: true});
        
            if ($overlay.find('video').length) {
                var player = new MediaElementPlayer('#popoverPlayer');
                $('#popoverPlayer').data('player', player);
            }
        
            _initSocial($overlay);
        
            _initBlogLinks($overlay.find('h2 a')); // make sure View is setup for current blog post
            _initBlogLinks($overlay.find('.posts_list a'));
            
            $overlay.addClass('initialized');
        }
    }
    
    function _initPopover($inner) {
        if ($inner.length && !$inner.hasClass('initialized')) {
            new Carouselstronaut($inner.find('.carousel'), {$indicator: $inner.find('.carousel_indicator'), marcopolo: true});
            
            if ($inner.find('video').length) {
                $('#popoverPlayer').attr('width', $('#popoverPlayer').width());
                $('#popoverPlayer').attr('height', $('#popoverPlayer').height());
                
                var player = new MediaElementPlayer('#popoverPlayer');
                $('#popoverPlayer').data('player', player);
                
                $('#popoverPlayer').bind('loadedmetadata', function (e) {
                    $inner.find('.mejs-container').css('height', $('#popoverPlayer').height());
                    $inner.parent().css('height', $inner.outerHeight() + 'px');
                });
                
            } else {
                $inner.imagesLoaded(function () {
                    $inner.parent().css('height', $inner.outerHeight() + 'px');
                });
            }
                        
            $inner.addClass('initialized');
        }
    }
    
    function _initPress($overlay) {
        if ($overlay.length && !$overlay.hasClass('initialized')) {
            _initPressBrowsePosts($overlay.find('.post'));
            
            _initInfiniteMasonry('press', _initPressBrowsePosts);
            
            $overlay.addClass('initialized');
        }
    }
    
    function _initPressBrowsePosts($posts) {
        // Entire post is clickable
        $posts.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            $(this).find('a').first().click();
        });
        
        $posts.hover(function () {$(this).toggleClass('hovered')});
        
        $posts.find('a').click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            window.open($(this).attr('href'));
        });
    }
    
    function _initInfiniteMasonry(className, callback) {
        var classSelector = className;
        if (classSelector[0] != '.') {
            classSelector = '.' + classSelector;
        }
        
        $(classSelector + ' .inner').imagesLoaded(function () {
            $(classSelector + ' .inner').masonry({
                itemSelector: '.post',
                isAnimated: (!TOUCHSUPPORT && !TRANSITIONSUPPORT),
                columnWidth: 10,
                isFitWidth: true
            });
        });
        
        $(classSelector + ' .inner').infinitescroll({
                debug           : false,
                loading			: {
                	img			: '/wp-content/themes/ndd/js/lib/infinite-scroll/ajax-loader.gif',
                	msgText		: '<em>Loading...</em>',
                	finishedMsg	: ''
                },
                state			: {
                	currPage	: '1'
                },
                nextSelector    : classSelector + ' div.pagelinks a:first',
                navSelector     : classSelector + ' div.pagelinks',
                contentSelector : classSelector + ' .inner',
                itemSelector    : classSelector + ' .inner div.post',
                pathParse		: ['/' + className + '/page/', '']
            },
        	// Trigger Masonry as a callback
            function (newElements) {
                callback($(newElements));
                
                // Hide new items while they are loading
                var $newElems = $(newElements).css({opacity: 0});
                // Ensure that images load before adding to masonry layout
                $newElems.imagesLoaded(function () {
                    // Show elems now they're ready
                    $newElems.animate({opacity: 1});
                    $(classSelector + ' .inner').masonry('appended', $newElems, true); 
                });
            }
        );
    }
    
    function _initAbout($overlay) {
        if ($overlay.length && !$overlay.hasClass('initialized')) {
            var c = new AutoCarousel($overlay.find('.carousel'));
            
            _aboutTimer = setInterval(function () {
                if ($overlay.children('.inner').css('opacity') > 0.9) {
                    c.goNext();
                }
            }, 5000);
            
            ///_initSocial($overlay);
        
            $overlay.addClass('initialized');
        }
    }
    
    function _initContact($overlay) {
        if ($overlay.length && !$overlay.hasClass('initialized')) {
            $overlay.addClass('initialized');
        }
    }
    
    
    
    function _switchToInlay($inlay) {
        _transitionFadeOut(
            $inlay.siblings('.inlay.show'),
            function () {
                _transitionFadeIn($inlay);
            }
        );
    }
    
    function _transitionFadeIn($el, after, optionalOpacity) {
        var opacity = 0.99;
        if (typeof optionalOpacity !== 'undefined') {
            opacity = optionalOpacity;
        }
        
        if ($el.length && !$el.hasClass('show')) {
            $el.transition(
                function () {$el.addClass('show animating transitioned');},
                function () {$el.removeClass('animating transitioned'); if (after) {after();}},
                function () {
                    // Prep for browsers that do not transition opacity
                    $el.css('opacity', 0);
                    $el.addClass('show');
                    var duration = 700;
                    // Hack in shorter duration fade for loading message
                    if ($el.is('#loading')) {
                        duration = 300;
                    }
                    $el.stop().animate({opacity: opacity}, duration, function () {
                        if (after) {after();}
                    });
                }
            );
        } else {
            if (after) {after();}
        }
    }
    
    function _transitionFadeOut($el, after) {
        if ($el.length && $el.hasClass('show')) {
            $el.transition(
                function () {$el.addClass('animating transitioned').removeClass('show');},
                function () {$el.removeClass('animating transitioned'); if (after) {after();}},
                function () {
                    var duration = 700;
                    // Hack in shorter duration fade for loading message
                    if ($el.is('#loading')) {
                        duration = 300;
                    }
                    $el.stop().animate({opacity: 0.0}, duration, function () {
                        $el.removeClass('show');
                        if (after) {after();}
                    });
                }
            );
            
        } else {
            if (after) {after();}
        }
    }
});

