/*
 * This file contains all the application specific code for OAO/OMO.  It
 * mostly uses the jQuery library (http://jquery.com/).  jQuery is a
 * _relatively_ simple library, the main feature of which is the ability to
 * say $('some.css.selector').  Remember that all jQuery methods return the
 * jQuery object itself, so that you can call further methods on it.  What
 * that means in practise is that you have to say .get(0) or
 * .each(function(){}) if you want to run regular DOM methods.
 *
 * $Id: app.js 81220 2010-06-07 14:14:28Z steve $
 */

/*jslint browser: true */
/*global $, jQuery */

// Keep our stuff in a namespace for cleanliness.
var OAOOMO = {};

// A debugging tool for jQuery.
// http://dom.semantico.net/blog/archives/2007/09/26/jquery-logging/
jQuery.fn.log = function (msg) {
    console.log("%s: %o", msg, this);
    return this;
};

// NB: Returns a boolean, not a jQuery object!
jQuery.fn.exists = function () {
    return this.size() > 0;
};

// Write a mini-jQuery extension to pop up a new window on click.
jQuery.fn.popupClick = function (opts) {
    if (!opts) {
        // OMO-134: Default to something which resembles a default browser window.
        opts = 'menubar=yes,directories=yes,toolbar=yes,status=yes,resizable=yes,scrollbars=yes,location=yes';
    }
    if (!this.attr("href")) {
        // Do nothing if no href attr.
        return this;
    } else {
        return this.click(function (ev) {
            if (!this.popup || this.popup.closed) {
                this.popup = open(this.href, '_blank', opts);
            } else {
                this.popup.focus();
            }
            ev.preventDefault();
        });
    }
};

// Another mini jQuery extension to select the contents of an input field when
// it's set to the default value (so it can be overtyped).
jQuery.fn.selectClick = function () {
    var select_me = function (ev) {
        if (this.value === this.defaultValue) {
            this.select();
        }
    };
    // Handle both focus and click events to try and cover all cases..
    return this.focus(select_me).click(select_me);
};

// Allow selecting comments in the DOM.  Annoyingly, we can't do this as a
// selector, as they only handle elements.
jQuery.fn.comment = function () {
    var comments = [];
    this.each(function () {
        for (var i = 0; i < this.childNodes.length; i++) {
            // Node.COMMENT_NODE
            if (this.childNodes[i].nodeType === 8) {
                comments.push(this.childNodes[i]);
            }
        }
    });
    return $(comments);
};

OAOOMO.printToNewWindow = function () {
    var opts = 'toolbar=yes,status=yes,resizable=yes,scrollbars=yes';
    // XXX No need for two selectors, must fix HTML.
    $('#print_icon a, #iconPrint a').popupClick(opts);
};

OAOOMO.illusToNewWindow = function () {
    // Unfortunately, the width of the image isn't easily available.  This
    // value was determined by looking at grove image data and guessing.
    var opts = 'toolbar=yes,status=yes,resizable=yes,scrollbars=yes,width=550';
    $('#illus a').popupClick(opts);
};

OAOOMO.sibeliusToNewWindow = function () {
    // The sibelius plugin HTML is set up be 750px wide, so make the window
    // a little bit wider.
    var opts = 'toolbar=yes,status=yes,resizable=yes,scrollbars=yes,width=800';
    $('.sibelius a').popupClick(opts);
};


// OMO-94: Make the help popup.
OAOOMO.helpToNewWindow = function () {
    var opts = 'toolbar=yes,status=yes,resizable=yes,scrollbars=yes,width=800';
    $('a#help').popupClick(opts);
};

OAOOMO.externalLinksToNewWindow = function () {
    $('a[href]').each(function () {
        // Curse the infernal variations of DOM0. Sometimes hostname
        // has a port number on it, sometimes it doesn't. Ditto for
        // "host" (which should always have a port number). Instead,
        // just strip off anything after a colon and hope for the best.
        var link_hostname = this.hostname.replace(/:[0-9]+$/, "");

        // Ignore internal links.
        if (link_hostname === document.location.hostname) {
            return;
        }
        // We explicitly don't want this one to popup.
        else if ($(this).hasClass('samewindow')) {
            return;
        }

        $(this).popupClick().attr("title", "Opens in a new window").addClass("external");
    });
};

// This can vary depending upon where we are deployed.  Pick out the root from
// a known link instead.
//
// @see http://peter.michaux.ca/article/3556 for the reason behind the double
// function.
OAOOMO.getRootUrl = function () {
    var url = $('#logolink').attr('href').replace(/(public|subscriber)\/$/, "");
    OAOOMO.getRootUrl = function () {
        return url;
    };
    return url;
};

// Create a new scope.  Functions declared in here will be private.
(function () {

    // Return a new button which can manage the visibility of *node*.
    function newTocButton(node) {
        var toggler = document.createElement('span');
        $(toggler).html("&nbsp;");
        // A miniature API.
        toggler.open = function () {
            $(node).show();
            $(this).removeClass('open');
            this.isOpen = true;
        };
        toggler.close = function () {
            $(node).hide();
            $(this).addClass('open');
            this.isOpen = false;
        };
        $(toggler).addClass("toggle").click(function (ev) {
            if (this.isOpen) {
                this.close();
            } else {
                this.open();
            }
        });

        // What should the default state be?
        if ($(node).hasClass("open-node")) {
            toggler.open();
        } else {
            toggler.close();
        }
        return toggler;
    }

    function getIDFromURL() {
        return location.hash;
    }

    function getArticleFromURL() {
        var components = location.pathname.split("/");
        return components[components.length - 1];
    }

    // OMA-56 extract current node functionality to use on 'Works pages'
    
    function setCurrentNode(toc_id) {
        // Mark the current node with a special class:
        // NB: This won't always be accurate.  e.g. #firsthit.
        var current_href = getArticleFromURL() + getIDFromURL();       
        // Check for an URL which _ends_ in this href.
        var current_node = $("#" + toc_id + " a[href$=" + current_href + "]");
        // OAO-94 When matching links we are matching the links as they
        // were written by the application and not how the browser 
        // rewrites them. So for some links that have an anchor we should
        // just look for the anchor.
        var split_href;

        if (current_href.indexOf("#") !== -1) {
            split_href = current_href.split("#");
            current_node = $("#" + toc_id + " a[href$=" + split_href[1] + "]");
        }
        if (current_node.exists()) {
            current_node.addClass('current-node');

            // mark each parent ul node with a special class:
            current_node.parents("ul").addClass('open-node');

            // and also each sibling ul node:
            current_node.siblings("ul").addClass('open-node');
        }

    }
    
    OAOOMO.setupToc = function (toc_id) {
        // Mark the first generation toc entries with a special class,
        // so that they are *always* opened.
        $("#" + toc_id + " > ul > li > ul").addClass('open-node');

        setCurrentNode(toc_id);
        
        $("#" + toc_id + " a").each(function () {
            // If the link contains a sibling "ul", then add a selector
            // and open/close it depending on relationship with current node

            var contents = $(this).next('ul');
            if (contents.exists()) {
                // Stick in a new button to do the toggling.
                $(this).before(newTocButton(contents[0]));
            }
        });
    };
    
    OAOOMO.setCurrentNode = function (toc_id) {

        setCurrentNode(toc_id);
        
    };

    // OMA-105 function added highlight correct link when moving
    // within a page
    OAOOMO.setCurrentNodeOnCurrentPage = function (anchor) {

        // remove any existing current nodes
        $('a.current-node').removeClass('current-node');

        anchor.addClass('current-node');
        // mark each parent ul node with a special class:
        anchor.parents("ul").addClass('open-node');
        // and also each sibling ul node:
        anchor.siblings("ul").addClass('open-node');

    };

})();

OAOOMO.setupQuickSearch = function () {
    // First, install the query from the cookie if there is one.
    var results = $.cookie('q');
    if (results) {
        $('#q').val(results);
    }

    // Next, set up the form to save its contents back into the cookie when
    // it's submitted.
    $('#q').parents('form').submit(function(ev) {
        var q = $('#q').get(0);
        if (q.value !== q.defaultValue) {
            $.cookie('q', q.value, {path: OAOOMO.getRootUrl()});
        }	
    });
};

// Stores the users preference for results per page (does this separately for
// browse and search results).
// XXX This should be handled server-side.
OAOOMO.setupResultsPerPage = function () {
    $('#results_per_page').submit(function (ev) {
        var rpp = $('#size', this).val();
        $.cookie('RPP', rpp, {path: OAOOMO.getRootUrl()});
    });
};

OAOOMO.setupImageThumbnails = function() {
	
	// reset to default if starting a new search
    if (!location.href.match(/[&?]_start=/)) {
    	$.cookie('show_image_thumbs', null, {path: OAOOMO.getRootUrl()});
    }
	
    // show thumbnails or not, depending on cookie value
    var cookieVal = $.cookie('show_image_thumbs') || 'On';
    $('img.thumb').each(function () {
        if (cookieVal === 'On') {
            $(this).removeClass('hidden');
        } else {
            $(this).addClass('hidden');
        }
    });
    
    // show the toggle icon
	$('#thumbnails_icon').removeClass('hidden');
	
	if (cookieVal === 'Off') {
		$('#thumbnails_icon').removeClass('on');
        $('#thumbnails_icon a').text('Thumbnails Off');
	}
	
	// set up handler for toggle icon
	$('#thumbnails_icon a:first').click(function (ev) {
        
        $('img.thumb').each(function () {
            $(this).toggleClass('hidden');
        });
                
        $('#thumbnails_icon').toggleClass('on');
        
        if ($('#thumbnails_icon').hasClass('on')) {
        	$('#thumbnails_icon a').text('Thumbnails On');
        	$.cookie('show_image_thumbs', 'On', {path: OAOOMO.getRootUrl()});
        } else {
        	$('#thumbnails_icon a').text('Thumbnails Off');
        	$.cookie('show_image_thumbs', 'Off', {path: OAOOMO.getRootUrl()});
        }
        
        ev.preventDefault();
    });
	
};

// Introduce a private scope.
(function () {
    function setHHCookie(value) {
        $.cookie('HH', value, {path: OAOOMO.getRootUrl()});
    }

    function getHHCookie() {
        return $.cookie('HH') || 'On';
    }

    // OMO-98: need to reset the hit highlighting on new searches.
    // We test to see if we're on a new search by looking for the absence
    // of a "_start" parameter in the URL.
    OAOOMO.maybeResetHighlighting = function () {
        if (!location.href.match(/[&?]_start=/)) {
            setHHCookie(null);
        }
    };
    
    

    OAOOMO.setupHitHighlighting = function () {
        // Initialize the page according to the status of the Cookie.
        var cookieVal = getHHCookie();
        $('span.hit').each(function () {
            if (cookieVal === 'On') {
                $(this).addClass('highlight');
            } else {
                $(this).removeClass('highlight');
            }
        });

        $('#iconHighlighting').removeClass('hidden');
        $('#iconHighlighting a:first').click(function (ev) {
            // First, go through and toggle all the highlights.
            $('span.hit').each(function () {
                $(this).toggleClass('highlight');
            });
            // Now, do we have any highlights?
            setHHCookie($('span.highlight:first').size() > 0 ? 'On' : 'Off');
            // Don't follow the link.
            ev.preventDefault();
        });
    };
    
    OAOOMO.setupInArticleHitHighlighting = function () {
        $('#articleHighlight').removeClass('hidden');
        $('#iconInArticleHighlighting').click(function (ev) {
            // First, go through and toggle all the highlights.
            $('span.hit_in_article').each(function () {
                $(this).toggleClass('hh_in_article');
            });
            // Don't follow the link.
            ev.preventDefault();
        });
    };
    
    OAOOMO.setupInArticleHighlightingToggle = function () {
        $('#toggleArticleSearchFormAndResults').click(function (ev) {
            $('#articleSearchFormAndResults').toggleClass('noDisplay');
            $('#toggleArticleSearchFormAndResults').toggleClass('open');
            if ($('#articleSearchFormAndResults').hasClass('noDisplay')) {
                $('span.hit_in_article').each(function () {
                    $(this).removeClass('hh_in_article');
                });
            }
            // OMA-150.  Don't focus unless the user actually clicked, as
            // opposed to the code calling click().   This is preventing the
            // browser from jumping to the anchor point.
            else if (typeof ev.button !== 'undefined') {
                $('#qa').focus();
            }
            // Don't follow the link.
            ev.preventDefault();
        });
        $('#articleSearchForm label').addClass('hidden');
        // Show expand button
        $('#toggleArticleSearchFormAndResults').removeClass('hidden');
        $('#articleSearchFormAndResults').addClass('noDisplay');
        // If a search has been done then open results
        if ($('#articleSearchFormAndResults .results').length > 0) {
            $('#toggleArticleSearchFormAndResults').click();
        }
    };
    
    
    OAOOMO.setupMarkSelectedHit = function () {
        $('#articleSearchFormAndResults li a').each(function () {
            $(this).click(function () {
                $('#articleSearchFormAndResults li a').each(function () {
                    $(this).removeClass('selected');
                });
                $(this).addClass('selected');
            });
        });
    };
    
})();

// This is a fairly nasty hack, but the SGK needs POST to logout.  So, create
// a hidden form and POST that instead.
OAOOMO.setupLogoutLink = function (link) {
    $('a#logout').click(function (ev) {
        OAOOMO.clearAllCookies();
        var form = $("<form action='" + link + "' method='post' />").hide();
        $(this).parent().append(form);
        form.submit();
        ev.preventDefault();
    });
};

OAOOMO.appendAnchorTo = function (sel) {
    if (document.location.hash) {
        $(sel).each(function () {
            this.value = this.value + document.location.hash;
        });
    }
};

OAOOMO.highlightFragments = function () {
    $('div.fragment').each(function () {
        var file = this.id.replace(/_/g, "/").replace(/\/\//g, "_");
        this.title = file;
        $(this).css('border', '1px solid red');
    });
};

// Uncomment the stacktrace on an error page.
OAOOMO.showError = function () {
    $('#error #errmsg').each(function () {
        var error = $(this).comment()[0].data;
        var pre = $("<pre></pre>").text(error);
        $(this).append($('<h3>Error</h3>')).append(pre);
    });
};

OAOOMO.showScores = function () {
    $('ul.search_result_list li.result').each(function () {
        var score = this.className.match(/s-(\d+)/)[1];
        var quality = this.className.match(/q-(\d+)/)[1];
        var html = $("<b>score=" + score + ", quality=" + quality + "</b>");
        $(this).find('br:first').before(html);
    });
};

// Create function for storing a cookie with the 'source' values
OAOOMO.setSourceCookie = function () {
    var ele =  $('#' + this.id);
    var shouldCheck = false;
    if (this.id === 'grove_limiter') {
        if (ele.is(':checked')) {
            $.cookie('source', 'true', {path: OAOOMO.getRootUrl()});
            return;
        } else {
            $.cookie('source', null, {path: OAOOMO.getRootUrl()});
            return;
        }
    }
    var count = 0;
    var groveChecked = false;
    var quickSourceCheckbox = $('.quickSourceCheckbox');
    for (i=0;i<quickSourceCheckbox.length;i++) {
        var srcCheck = $('#' + quickSourceCheckbox[i].id);
        if (srcCheck.is(':checked')) {
            count++;
            if (quickSourceCheckbox[i].id === 'omo_gmo' || quickSourceCheckbox[i].id === 'oao_gao') {
                groveChecked = true;
            } 
        }
    }
    
    if (count === 1 && groveChecked) {
        $.cookie('source', 'true', {path: OAOOMO.getRootUrl()});
    } else {
        $.cookie('source', null, {path: OAOOMO.getRootUrl()});
    }
};

// If the user searches for Grove only, keep the checkboxes in unison (not the union)
OAOOMO.setSourceCheckbox = function () {
    var value = OAOOMO.getSourceCookie();
    var shouldCheck = false;
    
    if (value !== null && value) {
        if (value === 'true') {
            shouldCheck = true;
        }
        if ($('#' + value)) {
            shouldCheck = true;
        }
    }

    $('#grove_limiter').attr('checked', shouldCheck);
    OAOOMO.checkForHomePageQuickSource(value, shouldCheck);
};

// Also, check the value on the home page if a search has been performed for Grove only
OAOOMO.checkForHomePageQuickSource = function (groveName, shouldCheck) {
    if (!shouldCheck) { 
        return; 
    }
    
    if ($('#omo_gmo').length !== 0) {
        groveName = 'omo_gmo'; 
    } else {
        groveName = 'oao_gao';
    }
    
    if ($('.quickSourceCheckbox') !== null) {
        $('.quickSourceCheckbox').attr('checked', false);
        $('#' + groveName).attr('checked', shouldCheck);
    }
    
};

OAOOMO.setupGroveSource = function () {
    if ($('#grove_limiter')) {
        $('#grove_limiter').click(OAOOMO.setSourceCookie);
    }
    
    if ($('.quickSourceCheckbox') !== null) {
        $('.quickSourceCheckbox').click(OAOOMO.setSourceCookie);
    }
    
};

OAOOMO.setupWorksLists = function () {
	// find all enlarge table links and set the href correctly
	$('a.thickbox').each(function(i) {
			var link = '#TB_inline?height=450&amp;width=S&amp;inlineId=';
			var treeid = $(this).siblings('div.hidden-table').filter(":first").attr('id');
			$(this).attr('href', link + treeid);
	});
	if ($('div.hidden-table')) {
		$('div.hidden-table').click(function() {
			var element = $(this);
			var t = element.siblings('h3').text();
			var a = '#TB_inline?height=550&amp;width=S&amp;inlineId=' + this.id;
			var g = this.rel || false;
			tb_show(t,a,g);
			this.blur();
			return false;
			}
		);
	}
};

OAOOMO.getSourceCookie = function () {
    return $.cookie('source') || false;
};

OAOOMO.clearAllCookies = function () {
    var allCookies = document.cookie;
    var cookies = allCookies.split(';');
    for (i=0;i<cookies.length;i++) {
        var keyVal = cookies[i].split('=');
        $.cookie(keyVal[0], null);
    }
};

// Run all this as soon as the page is ready, before onload().
$(document).ready(function () {
    OAOOMO.externalLinksToNewWindow();
    OAOOMO.printToNewWindow();
    OAOOMO.setupHitHighlighting();
    OAOOMO.setupInArticleHitHighlighting();
    OAOOMO.setupInArticleHighlightingToggle();
    OAOOMO.setupMarkSelectedHit();
    // Make these fields select value when clicked.
    $("#user, #lib_card").selectClick();
    OAOOMO.setupQuickSearch();
    OAOOMO.setupResultsPerPage();
    OAOOMO.setupGroveSource();
    OAOOMO.setSourceCheckbox();
    OAOOMO.setupLogoutLink(OAOOMO.getRootUrl() + "LOGOUT");
    // OMO-94: Make the music help into a nasty popup.
    // OAO-72: Do the same for art.
    OAOOMO.helpToNewWindow();
    OAOOMO.setupImageThumbnails();
    OAOOMO.setupWorksLists();
});


