var Lists = {}
var ActiveSearches = Array();

var List = function( options ) {
    this.name = '';
	this.SelectedItem = null;
	this.pos = 0;
	this.searchNum = 0;
	this.lastSearchNum = 0;
    this.page = 0;
    this.limit = 10;
	this.listState = null;	// The can (optionally) be a URLAnchor object that can preserve/re-create the state of
							// any filters applied to the list
	
	jQuery.extend( this, options );
	Lists[this.listId] = this;
	ActiveList = this;
	
	this.select = function( Element ) {
		// if clicking on the already selected item, unselect it and return
		if ( this.SelectedItem && Element.id == this.SelectedItem.id ) {
			this.unselect();
			return;
		}
		
		// if nothing selected or clicking on something other than
		// the currently selected item, do some selecting
		if ( !this.SelectedItem || Element.id != this.SelectedItem.id ) {
			this.unselect();

			Element.className += ' selected';
			this.SelectedItem = Element;

			matches = this.SelectedItem.className.match( 'pos[0-9]+' );
			pos = Number( matches[0].substr( 3 ) );

			if ( this.searchInputId ) {
				QueryInput = $( this.searchInputId );
			
				jQuery( '#' + this.SelectedItem.id + ' .name' ).each( function() {
					QueryInput.value = this.innerHTML;
				} );
			}

			if ( this.onSelect ) {
				this.onSelect( Element );
			}
		}
	}
	
	this.unselect = function() {
		if ( this.SelectedItem ) {
			this.SelectedItem.className
				= this.SelectedItem.className.replace( ' selected', '' );
			this.SelectedItem = null;
			pos = 0;
		}
	}
	
	this.nextPrev = function( direction ) {	
		switch( direction ) {
		case 'next':
			var tmpPos = pos + 1;
			match = $$( '.pos' + tmpPos )[0];
			if ( match ) {
				pos = tmpPos;
			}
			break;
		case 'prev':
			if ( pos > 1 ) {
				var tmpPos = pos - 1;
			} else {
				var tmpPos = 1;
			}
			match = $$( '.pos' + tmpPos )[0];
			if ( match ) {
				pos = tmpPos;
			}
			break;
		}
		if ( match ) {
			this.select( $$( '.pos' + pos )[0] );
		}
	}

	this.update = function( html ) {
		jQuery( '#' + this.listId ).html( html );
		this.huntForSelected();
	}

    this.search = function( page, token, extras ) {
        var minChars = 3;
        var frequency = 1.5; // min secs between search queries
        var Now = new Date;
        ActiveSearches[this.name] = this;
		
        // don't do searches with too few chars
        // but still do searches for zero chars
        // (ie to remove the search filter)
        if ( token.length < minChars && token.length != 0 ) {
            return;
        }
		
		if ( undefined === extras || !extras.searchNum ) {
		    var searchNum = ++this.searchNum;
    	} else if ( searchNum < this.searchNum ) {
	    	return;
    	}
		
        // don't search now if too soon after last search
        // and isn't an out of date search number
	    if ( token.length > 0 && Now.getTime() < this.lastSearchTime + frequency * 1000 ) {
	    	setTimeout( 
		    	function( DelayedList ) {
			    	DelayedList.search( page, token, { searchNum: searchNum } )
    			}, frequency * 1000, this
	    	);
		    return;
    	} else {
	    	this.lastSearchTime = Now.getTime();
	    }
		
		// If specified, store the list filters in the URL anchor
		if( this.listState ){
			this.listState.reset();
			this.listState.setParams( extras, [ "searchNum" ] );
			this.listState.set( "page", page );
			this.listState.set( "token", token );
		}
		
    	post = { 
            name: this.name, 
            limit: this.limit,
            page: page,
            order: searchNum,
            token: token
        }
        jQuery.extend( post, extras );
       
	    if ( this.changePage ) {
		    post.onclick = this.changePage;
    	}

    	jQuery( '#' + this.name + '_indicator' ).css( 'display', 'block' );

    	jQuery.post(
            this.searchURL, post,
            function( responseText ) {
                Result = eval( responseText );
		    	if ( Result[0] != 'success' ) {
			    	alert( Result[0] );
				    return;
    			}
                // make sure we're not updating with an older search result 
                // than we already have
	    		if ( Result[1] > ActiveSearches[Result[4]].lastSearchNum ) {
		    		ActiveSearches[Result[4]].update( Result[2] );
			    	jQuery( '#' + Result[4] + '_pagination' ).html( Result[3] );
                    ActiveSearches[Result[4]].page = page;
    			}
                ActiveSearches[Result[4]].lastSearchNum = Result[1];

                // only turn indicator off if we're not expecting any more 
                // results
	    		if ( Result[1] == ActiveSearches[Result[4]].searchNum ) {
		    		jQuery( '#' + Result[4] + '_indicator' ).css( 'display', 'none' );
                }
            }
        );
    }

	this.empty = function() {
		var ListElm = $( this.listId );
		ListElm.innerHTML = '';
		ListElm.style.display = 'none';
	}
	
	this.huntForSelected = function() {
        Context = this;
		jQuery( '#' + this.listId + ' .item' ).each( function() {
			if ( this.className.indexOf( 'selected' ) > 0 ) {
				Context.SelectedItem = this;

				matches = Context.SelectedItem.className.match( 'pos[0-9]+' );
				Context.pos = Number( matches[0].substr( 3 ) );
			}
		} );
	}
	
	this.hideAllButSelected = function() {
		$$( '#' + this.listId + ' .item' ).each( function( Item ) {
			if ( Item.className.indexOf( 'selected' ) < 0 ) {
				new Effect.BlindUp( Item.id, { duration: 0.1 } );
			}
		} );
	}
	
	this.searchFromURLAnchor = function(){
		if( this.listState.hasParams ){
			page = ( this.listState.get( "page" ) ? this.listState.get( "page" ) : 1 );
			token = ( this.listState.get( "token" ) ? this.listState.get( "token" ) : "" );
			this.search( page, token, this.listState.get() );
		}
	}
}
