
var fx_slide_criteria_search = new Class({

    Extends: fx_slide_base,
    Implements: [Options, Events],
    
    // class of the pseudo-select areas
    str_select_class: null,
    
    // reference to the select area handler object
    obj_styled_select: null,
    
    // form id the options are within
    str_form_id: null,
    
    // overridable options
    options: {
        match_custom: 'Match: <strong><em>Custom</em></strong></strong>',
        match_any: 'Match: <strong>Any</strong>',
        cookie_name: 'postar_adv_search'
    },
    
    /**
     * Constructor.
     *
     * Calls parent and adds additional functionality specific to the criteria selections.
     *
     * @param str_block_selector  Criteria block CSS selector
     * @param str_select_class    Class of the contained styled select items
     * @param str_form_id         ID of the form used for criteria search
     * @param obj_options         Text strings used for the "Match custom/any" titlebars
     *                            In the format:
     *                                  { match_custom: "My string", match_any: "My string" }
     * @return void
     */                             
    initialize: function(str_block_selector, str_select_class, str_form_id, obj_options) {

        // parent
        this.parent(str_block_selector);
        
        // store select class and form id
        this.str_select_class = str_select_class;
        this.str_form_id = str_form_id;
    
        // add additional functionality to the blocks
        for(var i = 0, ilen = this.arr_blocks.length; i < ilen; i++) {
        
            var elm_block = this.arr_blocks[i];
            
            // store a reference to the parent criteria block in each select
            // element
            var elm_select = this.arr_blocks[i].getElements('.' + str_select_class);
            
            if(elm_select) {
                elm_select.store('criteria_id', elm_block.get('id'));
            }
            
            // bind event to the reset action for each block
            var elm_reset = elm_block.getElement('.criteria_reset');
            elm_reset.addEvent('click', this._event_reset.bind(this, i));
            
        }
        
        // listen to the forum submit event so we can automatically save the criteria
        $(this.str_form_id).addEvent('submit', this.save_criteria.bind(this, true));
        
        // reselect any saved criteria present
        this.restore_criteria();
        
        this.setOptions(obj_options);
    },
    
    /**
     * Required: pass select object handler here for internal use. Best to call
     * immediately after the constructor.
     *
     * Passed here, rather than the constructor, to allow for lazy loading (increased
     * perceived performance on the front end)
     */
    register_select_handler: function(obj_styled_select) {
    
        this.obj_styled_select = obj_styled_select;
    },
    
    /**
     * Saves the currently select criteria to a cookie (compressed - we can minimise storage
     * by only storing 1/0 (checked or unchecked) for each index in a select element list.
     * This effectively means we can store up to 4096 items in a standard cookie if necessary!
     *
     * @param boo_save   If true, saves the criteria to the cookie.
     *                   If false, removes the stored criteria
     */
    save_criteria: function(boo_save) {
    
        // create saved criteria
        if(boo_save == true) {
        
            var str_checkboxes = '';
            var str_selects = '';
            var str_blocks = '';
            
	        // retrieve checked input on/off values
	        var arr_checkboxes = $(this.str_form_id).getElements('input[type=checkbox]');
	        
	        for(var i = 0, ilen = arr_checkboxes.length; i < ilen; i++) {
	            str_checkboxes += arr_checkboxes[i].checked ? '1' : '0';
	        }
	        
	        // retrieve select area disabled states
	        var arr_selects = $(this.str_form_id).getElements('.styled-select');
            
            for(var i = 0, ilen = arr_selects.length; i < ilen; i++) {
                str_selects += arr_selects[i].hasClass('disabled') ? '0' : '1';
            }
            
            // retrieve block open/closed states
            var arr_blocks = this.arr_blocks;
            
            for(var i = 0, ilen = arr_blocks.length; i < ilen; i++) {
                str_blocks += arr_blocks[i].getElements('input[checked]').length ? '1' : '0';
            }
            
            var str_cookie = str_checkboxes + '|' + str_selects + '|' + str_blocks;
	        
	        Cookie.write(this.options.cookie_name, str_cookie);
	    }
	    
	    // destroy saved criteria
	    else {
	       
	       Cookie.write(this.options.cookie_name, '');
	       Cookie.dispose(this.options.cookie_name);
	    }
    }, 
    
    /**
     * Restores criteria from the cookie (if present)
     */
    restore_criteria: function() {
    
        // extract cookie contents from the cookie
        var str_cookie = Cookie.read(this.options.cookie_name);
        
        if(str_cookie) {
        
            // retrieve individual components
            var arr_components = str_cookie.split('|');
            
            var str_checkboxes = arr_components[0];
            var str_selects = arr_components[1];
            var str_blocks = arr_components[2];
        
            // set checkbox elements
            var arr_checkboxes = $(this.str_form_id).getElements('input[type=checkbox]');
            
            for(var i = 0, ilen = str_checkboxes.length; i < ilen; i++) {
            
                if(str_checkboxes.charAt(i).toInt() === 1) {
                    arr_checkboxes[i].set('checked', true);
                }
                else {
                    arr_checkboxes[i].set('checked', false);
                }
            }
            
            // set select disabled status
            var arr_selects = $(this.str_form_id).getElements('.styled-select');
            
            for(var i = 0, ilen = arr_selects.length; i < ilen; i++) {
            
                if(str_selects.charAt(i).toInt() === 1) {
                    arr_selects[i].removeClass('disabled');
                }
                else {
                    arr_selects[i].addClass('disabled');
                }
            }
            
            // open any blocks with criteria and change the title
            var arr_blocks = this.arr_blocks;
            
            for(var i = 0, ilen = arr_blocks.length; i < ilen; i++) {
                
                var arr_block = arr_blocks[i];
                
                if(str_blocks.charAt(i).toInt() === 1) {
                
                    // open - note delay is to ensure prior initialisations have taken place
                    this.obj_panel_slides[arr_block.get('id')].slideIn.delay(750, this.obj_panel_slides[arr_block.get('id')]);
                    
                    // update label
                    arr_block.addClass('custom').getElement('.title .type').set('html', this.options.match_custom);
                }
                else {
                    
                    arr_block.removeClass('custom');
                }
            }
        }
    },

    /**
     * Updates the criteria's visual state (match any/custom) depending on the state of the
     * select areas
     */
    _event_criteria_change: function(elm_select_parent, elm_select, elm_checkbox) {
        
        // retrieve criteria block reference from the parent select element
        var str_criteria_id = elm_select_parent.retrieve('criteria_id');
        var elm_criteria_block = $(str_criteria_id);
        var arr_checkboxes = elm_criteria_block.getElements('input[checked]');
        
        // if any are checked, this is a custom criteria, else this is match any
        if(arr_checkboxes.length > 0) {
            elm_criteria_block.addClass('custom').getElement('.title .type').set('html', this.options.match_custom);
        }
        else {
            elm_criteria_block.removeClass('custom').getElement('.title .type').set('html', this.options.match_any);
        }
        
        // now we need to see if any blocks need hiding or showing. Select blocks are
        // sequential; that is, if the first block has nothing selected then the second
        // shouldn't show. The same applies to the next block and so on.
        var arr_criteria = elm_criteria_block.getElements('.select_block');
        
        for(var i = 0, ilen = arr_criteria.length; i < ilen; i++) {
        
            var elm_criteria = arr_criteria[i];
            
            // retrieve selected count for this criteria
            if(elm_criteria.getElements('input[checked]').length == 0) {
            
                // nothing selected - hide the rest of the criteria
                for(var j = i + 1, jlen = arr_criteria.length; j < jlen; j++) {
                    this.obj_styled_select.disable(arr_criteria[j].getElements('.styled-select'));
                }
                
                break;
            }
            else {
            
                // next criteria is valid to show - ensure it is currently doing so
                if(arr_criteria[i + 1]) {
                    this.obj_styled_select.enable(arr_criteria[i + 1].getElements('.styled-select'));
                }
            }
        }
    },
    
    /**
     * Called when a user wishes to reset a criteria (that is, clear all options and change back to
     * a "match any")
     */
    _event_reset: function(int_block_idx) {
    
        var elm_block = this.arr_blocks[int_block_idx];
        var arr_selects = elm_block.getElements('.styled-select');
        
        // empty the select areas
        this.obj_styled_select.clear(elm_block.getElements('.styled-select'));
        
        // disable all but the first
        this.obj_styled_select.disable(new Elements(arr_selects.slice(1)));
        
        // restore 'match any' state
        elm_block.removeClass('custom').getElement('.title .type').set('html', this.options.match_any);
        
        // notify listeners
        this.fireEvent.delay(750, this, 'onChange');

	    // close the block
        var obj_slide = this.obj_panel_slides[elm_block.get('id')];
        
        // toggle the open/closed class for the title and the sliding of the data block
        obj_slide.toggle.delay(1000, obj_slide);
    }

});