// TAGR Advanced Search Behavior Injector

/* 
*  Expectations:
*   A form named searchBoxAdvanced
*   Hidden input searchString
*   Text input anyString
*   Text input allString
*   Text input noneString
*   button btnSearch

*   gradeLimit radio
*   grade checkbox (Array)
*   langLimit radio
*   lang checkbox (Array)
*


*/


// Namespace object
var AS = new Object;

// subject and standard aren't basic
AS.basicFacets = ['grade', 'audience', 'language', 'media_type', 'resource_type', 'source'];

// Handle a basic facet changing -- enforce coherence
AS.handleFacetChange = function(evt) {
    var sel = Event.element(evt);
    var count = AS.getSelectedCount(sel);
    
    // If nothing is selected, select All.
    if (count == 0) {
        AS.setSelectExclusive(sel,'all');
    } else {
        // If anything else is selected, 'all' must not be
        if (count > 1 && AS.getSelectOption(sel,'all')) {
            AS.setSelectOption(sel,'all', false);
        }
    }
}


// Attach any event handlers to their elements
AS.injectBehavior = function() {

    // add onsubmit to the form
    document.forms["searchBoxAdvanced"].onsubmit = AS.handleAdvSearchFormSubmit;

    // Add onchange handler for each basicFacet
    // use Prototype events - may have more than one for some of these
    $(AS.basicFacets).each(function (elem) {
        Event.observe(elem, 'change', AS.handleFacetChange);
    });

    // Install extra behavior for standard selection
    Event.observe($('grade'), 'change', AS.handleGradeChange);
    Event.observe($('subject'), 'change', AS.handleSubjectChange);
    Event.observe($('standard'), 'change', AS.handleFacetChange); // same as basicFacet - prevents selection of all when others selected
}

// Add the behavior inject to the page onload handler
if (onloadHooks) {
    onloadHooks.addHook(AS.injectBehavior);
}

// If exactly one grade is selected, display the Subject Facet.
AS.handleGradeChange = function(evt) {
    var sel = $('grade');
    var count = AS.getSelectedCount(sel);
    
    // If 'all' or multiple grade chosen, hide the subject & standards box.
    if (count != 1 || AS.getSelectOption(sel,'all')) {
        // Reset to 'all'
        AS.setSelectExclusive('subject','all');
        AS.setSelectExclusive('standard','all');
        $('stdSubject').hide();
        $('stdNeedGrade').show();
    } else {
        $('stdSubject').show();
        $('stdNeedGrade').hide();
        $('stdStandard').hide();
        $('stdNeedSubject').show();
        $('stdLoading').hide();
        $('stdNoIndicator').hide();
        AS.setSelectExclusive('standard','all');
    }    
}

// Fetch Standards listing if possible
AS.handleSubjectChange = function(evt) {
    var sel = $('subject');

    // If Please choose (which has the value all) is chosen, disable standard
    if (AS.getSelectOption(sel,'all')) {
        // Reset to 'all'
        AS.setSelectExclusive('standard','all');
        $('stdStandard').hide();
        $('stdNeedSubject').show();
        $('stdLoading').hide();
        $('stdNoIndicator').hide();
    } else {
        $('stdStandard').hide();
        $('stdLoading').show();
        $('stdNeedSubject').hide();
        $('stdNoIndicator').hide();
        // Fire a AJAX request to load the standards.
        var url = '/ILRN/Dispatcher.do/SearchAjaxStandards?';
        url += 'grade=' + AS.getSelectFirstSelected('grade');
        url += '&subject=' + AS.getSelectFirstSelected('subject');
        new Ajax.Request(url, { method: 'GET', onSuccess: AS.handleStandardsArrived });
    }
}

AS.handleStandardsArrived = function(transport) {

    // expects JSON list of hashes with value, label keys
    var list = eval(transport.responseText);

    if (list.length != 0 ) {
        var sel = $('standard');
        sel.options.length = 0;
        var idx = 0;

        // Add Choose...
        var opt = new Option('Choose...', 'all', true, true);
        opt.className = 'searchOption searchOptionDefault';
        sel.options[idx++] = opt;

        // Add all indicators
        list.each(function(indicator) {
            opt = new Option(indicator.label, indicator.value, false, false);
            opt.className = 'searchOption';
            sel.options[idx++] = opt;
        });

        $('stdStandard').show();

    } else {
        // No indicators for this subject.
        $('stdNoIndicator').show();
    }

    $('stdLoading').hide();
    $('stdNeedSubject').hide();

    
}

// Event handler
AS.handleAdvSearchFormSubmit = function() {
    var formElem = document.forms["searchBoxAdvanced"];

    var elem; 
    var parts = new Array();
    var query = "";

    // Collapse each group of controls into a query string
    parts[parts.length] = AS.collapseTextField('anyString', 'OR');
    parts[parts.length] = AS.collapseTextField('allString', 'AND');
    parts[parts.length] = AS.collapseTextField('noneString', 'NOT');

    AS.basicFacets.each(function (facet) {
        parts[parts.length] = AS.collapseFacet(facet);
    });

    parts[parts.length] = AS.collapseStandard();

    // Remove empty parts 
    parts = parts.compact();

    // Join parts with AND
    query = parts.join(" AND ");
    formElem.elements["searchString"].value = query;

    //alert("Parsed query as: " + query);
    formElem.submit();
    //return false;
}


AS.collapseTextField = function(element, operator) {
    var elem = document.forms["searchBoxAdvanced"].elements[element];
    var query = "";
    var tokens = elem.value.split(/\s+/);
    query = tokens.join(" " + operator + " ");
    if (operator == 'NOT' && query) {
	query = "NOT " + query;
    }
    if (query) {
	query = "(" + query + ")";
        return query;
    } else {
        return undefined;
    }

}

AS.collapseStandard = function() {
    var stdElem = $('standard');
    var subj = AS.getSelectFirstSelected('subject');

    if (subj == 'all') { return undefined; }
    if (AS.getSelectOption(stdElem, 'all')) { return undefined; }

    var parts = new Array();
    var opts = stdElem.options;

    for (var i = 0; i < opts.length;  i++) {
	if (opts[i].selected) {
            parts[parts.length] =  'standard:"' + subj + ' ' + opts[i].value + '"';
	}
    }

    var query = parts.join(' OR ');
    query = query ? '(' + query + ')' : '';
    return query;

}

// Collapse a Select control into a query string, with labels.
AS.collapseFacet = function(facet) {
    var sel = $(facet);
    if (AS.getSelectOption(sel, 'all')) { return undefined; }  
    
    var parts = new Array();
    var opts = sel.options;

    for (var i = 0; i < opts.length;  i++) {
	if (opts[i].selected) {
            parts[parts.length] = facet + ':"' + opts[i].value + '"';
	}
    }

    var query = parts.join(' OR ');
    query = query ? '(' + query + ')' : '';
    return query;

}


// Sets a select field to have exactly the value given
//  (deselects everything else)
AS.setSelectExclusive = function(id, value) {
    var sel = $(id);
    var opts = sel.options;

    // Unselect everything 
    for (var i = 0; i < opts.length;  i++) {
	opts[i].selected = false;
     }

    // Find and select the desired option
    for (var i = 0; i < opts.length;  i++) {
	if (opts[i].value == value) {
	    opts[i].selected = true;
	    return true;
	}
    }

    // Not found...
    return false;
}

// Sets a Select to have the given value selected (or unselected, use 3rd param)
// (does not affect other selections)
AS.setSelectOption = function(id, value, selected) {
    selected == undefined ? true : selected; // default to true if not provided
    var sel = $(id);
    var opts = sel.options;

    // Find and select the desired option
    for (var i = 0; i < opts.length;  i++) {
	if (opts[i].value == value) {
	    opts[i].selected = selected;
	    return true;
	}
    }
    
    // Not found...
    return false;
    
}

// Returns the selected state of the option with the 
// specified value in the given select.
AS.getSelectOption = function(id, value) {
    var sel = $(id);
    var opts = sel.options;

    // Find and select the desired option
    for (var i = 0; i < opts.length;  i++) {
	if (opts[i].value == value) {
            return opts[i].selected;
	}
    }

    return undefined;
}

// Returns the value of the first selected option in the given select.
AS.getSelectFirstSelected = function(id) {
    var sel = $(id);
    var opts = sel.options;

    // Find and select the desired option
    for (var i = 0; i < opts.length;  i++) {
	if (opts[i].selected) {
            return opts[i].value
	}
    }

    return undefined;
}


// Returns the number of options selected in the given select.
AS.getSelectedCount = function(id) {
    var sel = $(id);
    var opts = sel.options;
    var count = 0;
    
    // Find and select the desired option
    for (var i = 0; i < opts.length;  i++) {
        count += opts[i].selected ? 1 : 0;
    }

    return count;
}
