Listing = Class.create();

new EventHandler(Listing);

Listing.Event = {
    CREATED : 'created',
    PAGE_CHANGING : 'page-changing',
    PAGE_CHANGED : 'page-changed',
    SORTING : 'sorting',
    SORTED : 'sorted',
    MASTER_TOGGLING : 'master-toggling',
    MASTER_TOGGLED : 'master-toggled'
};

Listing.prototype = {
    sortAction : null,    
    pageAction : null,    
    updateElement : null,
    /**
     * List of listing options used in the displaying
     * of the listing.
     */
    options: {},
    /**
     * Default constructor
     */
    initialize: function(id, itemIds) 
    {
        this.id = id;
        if (itemIds) {
            this.itemIds = itemIds;
        } else {
            this.itemIds = [];
        }
        new EventHandler(this);
        
        var masterCheckbox = $(this.id + '-master-checkbox');
        if (masterCheckbox) {
        	Event.observe(
				masterCheckbox,
				'click',
				function(e) {
					this.fire(Listing.Event.MASTER_TOGGLING);
					var checkbox = Event.element(e);                    
					if (checkbox.checked) {
						this.selectAll();
					} else {
						this.deselectAll();
					}
					this.fire(Listing.Event.MASTER_TOGGLED);
				}.bindAsEventListener(this)
			);
		}
        
        this.options = {
            /* Indicates whether the property checkbox-enabled is true. */
            checkboxEnabled: null,
            /* Indicates whether this is an alternative listing */
            alternatives: null,
            /* Indicates an action to take */
            action: null
        }
        Listing.fire(Listing.Event.CREATED, this);
    },

    
    actionTypes: {
        regular : function() {return true;},
        'refresh-listing' : function(e, url) {
            this.onRefresh(url);
            if (e) {
                Event.stop(e);
            }
        },
        'refresh-listing-confirm' : function() {return false;}
    },
    
    onRefresh : Prototype.emptyFunction,

    registerActions : function(actions) {    
        $A(this.itemIds).each(
            function(itemId) {
                $A(actions).each(
                    function(action) {        
                        var type = (action.type) ? action.type : 'regular';
                        var link = $(this.id + '-item-' + itemId + '-action-' + action.id + '-link');
                        Event.observe(
                            link,
                            'click',
                            this.actionTypes[type].bindAsEventListener(this, link.href)
                        );
                    }.bind(this)
                );
            }.bind(this)
        );
    },
    
    confirmAction : function(actionId, itemId) {
        var link = $(actionId + '-link');
        this.onRefresh(link.href);
    },
    
    getPageUrl : function(page) {                                           
        return this.appendParams(
            Paths.www
            + this.pageAction
            + '/'
            + page
        );
    },
    
    /**
    * Determines whether the listing is empty
    *
    * @return Boolean
    * @access public
    */
    isEmpty : function() {
        return this.itemIds.length == 0;
    },
    
    getSortUrl: function(column, direction, page) {
        return this.appendParams(
            Paths.www
            + this.sortAction
            + '/'
            + column
            + '/'
            + direction
            + '/'
            + (page ? page : '')
        );
    },
    
    /**
     * Appends parameters to the given URL
     * 
     * E.g.
     *  http://unisource.ca/uni_products/sort/format/asc
     *  // becomes ...
     *  http://unisource.ca/uni_products/sort/format/asc?listing[ch]=true&listing[sc]=true
     *
     * @access public
     * @return string 
     */
    appendParams: function (path) {
        var params = [];
        var append = function (list, name, param) {
            if (param != null) {
                var value = (typeof param == 'boolean') ? 
                      (param ? 'true' : 'false')
                    : (escape(param));
                list[list.length] = name + '=' + value;
            }
        }
        append(params, 'listing[checkbox_enabled]', this.options.checkboxEnabled);
        append(params, 'listing[alternatives]',     this.options.alternatives);
        append(params, 'listing[action]',           this.options.action);
        
        if (this.options.source) {
            append(params, 'source', this.options.source);
        }
        
        if (params.length > 0) {
            path += (path.indexOf('?') != -1) ? '&' : '?';
            path += params.join('&');
        }
        return path;
    },
        
    invokeAction : function(url, startEvent, endEvent) {
        if (startEvent) {
            this.fire(startEvent);
        }
        
        if (this.updateElement) {
            if (typeof this.updateRequest != 'undefined') {                  
                delete this.updateRequest;
            }
            this.updateRequest = new Ajax.Updater(
                $(this.updateElement),
                url, 
                {
                    evalScripts: true,
                    
                    onComplete : function() {
                        if (endEvent) {
                            this.fire(endEvent);
                        }
                        
                        this.clearEvents();                        
                    }.bind(this)
                }
            );
            
        } else {
            location.href = url;
        }
    },
    
    /**
    * For listings with checkboxes, checks off the checkboxes
    * for all items.
    */
    selectAll : function() {
        var checkboxes = this.getAllCheckboxes();
        
        $A(checkboxes).each(
            function(checkbox) {
                if (checkbox) {
            	    checkbox.checked = true;
                }
            }.bind(this)
        );
    },
    
    /**
    * For listings with checkboxes, unchecks the checkboxes
    * for all items.
    */
    deselectAll : function() {
        var checkboxes = this.getAllCheckboxes();
        
        $A(checkboxes).each(
            function(checkbox) {
                if (checkbox) {
            	    checkbox.checked = false;
                }
            }.bind(this)
        );
	},
	
		    
    
    
    /**
    * Returns the checkbox for the specified item, if
    * available. If there are no checkboxes, or the item
    * is not on the list, null is returned
    *
    * @param Integer itemId the ID of the item
    */
    getCheckbox : function(itemId) {
    	return $(this.id + '-checkbox-' + itemId);
	},
	
	/**
	* Determines if the checkbox for the specified item
	* has been checked
	*
    * @param Integer itemId the ID of the item	
	*/
	isSelected : function(itemId) {
		var result = false;
		var checkbox = this.getCheckbox(itemId);
		if (checkbox) {
			result = checkbox.checked;
		}
		return result;
	},
	
	/**
	* Returns all checkboxes present in this listing, if any
	*
	* @return Array
	*/
	getAllCheckboxes : function() {
		if (!this.checkboxes) {
			this.checkboxes = [];
			
			$A(this.itemIds).each(
				function(itemId) {
				    this.checkboxes.push(this.getCheckbox(itemId));
				}.bind(this)
			);
		}
		
		return this.checkboxes;
	},
	
    
        
    /**
    * Navigates to the specified page
    *
    * @param Integer page the page number
    */
    goToPage: function(page) {        
        this.invokeAction(
            this.getPageUrl(page),
            Listing.Event.PAGE_CHANGING,
            Listing.Event.PAGE_CHANGED
        );
    },
    
    /**
    * Sorts the listing according to the specified
    * sorting criteria
    *
    * @param String column 	the column to sort by
    * @param String direction the sort direction ('ASC' or 'DESC')
    * @param int 	page      the page number
    */
    sort : function (column, direction, page) {        
        this.invokeAction(
            this.getSortUrl(column, direction, page),
            Listing.Event.SORTING,
            Listing.Event.SORTED
        );
    }
}
