/* ******************************************************************************** */
/*                             PLEASE LEAVE THIS INTACT                             */
/* ******************************************************************************** */
/* Date: 20/09/2007                                                                 */
/* Title: mSuggest                                                               */
/* Description: Brings auto-suggest functionality to standard input text boxes      */
/* Author: Tom Glenn (http://www.tomglenn.co.uk)                                    */
/* Contact: tom@tomglenn.co.uk OR hazviz@gmail.com                                  */
/* Credits: MooTools dev team (http://www.mootools.net) for the MooTools Framework  */
/* ******************************************************************************** */
/*                             PLEASE LEAVE THIS INTACT                             */
/* ******************************************************************************** */

var mSuggest = new Class({

  options: {
    InputBox      : false,
    SuggestArray  : [],
    MaxDisplay    : 10,
    EffectDuration: 500,
    SuggestItem   : 0,
	AsyncLoadFunc : function(sugget,completed){ //if you want to use ajax load data,you need rewrite this function 
						completed(); 
					  }
  },
  
  initialize: function(options){
    // Initialize variables
    this.setOptions(options);
    this.InputBox = this.options.InputBox;
    this.preInputLength = 0;
    this.InputBoxProperties = [];
    this.SuggestionBox = null;
    this.RelativeArray = [];
    this.RelativeArray.length = 0;
    this.SuggestArray = [];
    this.MaxDisplay = 10;
    this.EffectDuration = this.options.EffectDuration;
    this.SuggestItem = this.options.SuggestItem;
    this.ToggleFX = null;
    this.IsOpen = false;
    this.HasEntered = false;
    this.ListPos = null;
    this.ChosenItem = null;
    this.IndexBase = 0;
    this.MyPos = 1;
	this.AsyncLoadFunc = this.options.AsyncLoadFunc;
    
    // Perform key initialization functions
    this.AddSuggestions(this.options.SuggestArray);
    this.GetInputBoxProperties(this.InputBox);
    this.CreateSuggestionBox();
    this.AddInputEvents();
  },
  
  AddSuggestions: function(suggestions){
    suggestions.each(function(suggestion){
      this.SuggestArray.extend([suggestion]);
    }, this);
  },
  
  GetInputBoxProperties: function(){
    this.InputBoxProperties = this.InputBox.getCoordinates();
  },
  
  CreateSuggestionBox: function(){
    // Create new element
    this.SuggestionBox = new Element('div', {
      'class': 'suggestions',
      'events': {
        'mouseenter': function(){
          this.HasEntered = true;
        }.bind(this),
        'mouseleave': function(){
          this.HasEntered = false;
          this.BeginFade();
        }.bind(this)
      }
    });
    
    // Set its properties
    this.SuggestionBox.setStyle('display', 'block');
    this.SuggestionBox.setStyle('width', (this.InputBoxProperties['width']-2));
    this.SuggestionBox.setStyle('top', (this.InputBoxProperties['top']+this.InputBoxProperties['height']+12));
    this.SuggestionBox.setStyle('left', (this.InputBoxProperties['left']+2));

    this.SuggestionBox.injectInside(document.body);
    this.ToggleFX = new Fx.Style(this.SuggestionBox, 'opacity', {duration: this.EffectDuration});
  },
  
  AddInputEvents: function(){

    this.InputBox.addEvents({
      'keyup': function(event){
        event = new Event(event);
        if(event.key == "up") {          
		  if(this.RelativeArray.length > 0) 
			  this.UpList(this.RelativeArray);
        } else if (event.key == "down") {
		  if(this.RelativeArray.length > 0)
			  this.DownList(this.RelativeArray);
        } else if ( event.key == "enter"){          
		  if(this.RelativeArray.length > 0 && this.ChosenItem != null && this.IsOpen == true) {
            this.InputBox.value = this.ChosenItem;
            this.SelectItem(this.InputBox.value);
            this.HideSuggestions();
          }
		 } else {
          this.ListPos = null;
          this.MyPos = 1;
          this.Indexbase = 0;		  
          this.PerformSuggest();
        }
      }.bind(this),

      'mouseleave': function(){        
		this.HasEntered = false;
        this.BeginFade();

      }.bind(this)

    });
  },
  
  HighlightItem: function(){
    $('s' + this.SuggestItem + this.ListPos).addClass('mouseenter');
    this.ChosenItem = this.RelativeArray[this.ListPos];

    if(this.IsOpen == false && this.RelativeArray.length > 0) {
      this.EmptySuggestions();
      this.InjectSuggestions(this.RelativeArray, this.IndexBase);
      this.ShowCount(this.RelativeArray, this.ListPos);
      this.ShowSuggestions();
    }
  },
  
  DownList: function(){
    // Am i null? If so, make me 0. If not, add to me.
    if(this.ListPos == null) {
      this.ListPos = 0;
    } else {
      this.ListPos++;
      this.MyPos++;
    }

    // Am i greater than allowed and myPos equal to max display? If so, reset me and my base and my pos.
    if (  this.ListPos > (this.RelativeArray.length-1) 
		&& this.MyPos > this.MaxDisplay || this.ListPos > (this.RelativeArray.length-1) 
		&& this.MyPos > (this.RelativeArray.length-1)) {
	  this.ListPos = 0;
      this.IndexBase = 0;
      this.MyPos = 1;
    } else if(this.MyPos > this.MaxDisplay && this.ListPos <= (this.RelativeArray.length-1)){
      this.IndexBase++;
      this.MyPos = this.MaxDisplay
    }

    // Show the results and highlight
    if(this.IsOpen == true && this.RelativeArray.length > 0) {
      this.EmptySuggestions();
      this.InjectSuggestions(this.RelativeArray, this.IndexBase);
      this.ShowCount(this.RelativeArray, this.ListPos);
    }

      this.HighlightItem(this.RelativeArray, this.ListPos);
  },

  UpList: function(){
    // Am i null? If so, make me equal to biggest. If not, take from me.
    if(this.ListPos == null) {
      this.ListPos = (this.RelativeArray.length-1);
    } else {
      this.ListPos--;
      this.MyPos--;
    }

    // Am i smaller than allowed? If so, reset me and my base.
    if(this.ListPos < 0 && this.MyPos < 1 || this.ListPos < 0) {
      this.ListPos = (this.RelativeArray.length-1);
      this.IndexBase = (this.RelativeArray.length-1)-(this.MaxDisplay-1);
      this.MyPos = this.MaxDisplay;
      if(this.MaxDisplay > (this.RelativeArray.length-1)) this.MyPos = (this.MaxDisplay - (this.RelativeArray.length-1));
    }else if(this.MyPos < 1 && this.ListPos <= (this.RelativeArray.length-1)){
      this.IndexBase--;
      this.MyPos = 1;
    }

    // Show the results and highlight
    if(this.IsOpen == true && this.RelativeArray.length > 0) {
      this.EmptySuggestions();
      this.InjectSuggestions(this.RelativeArray, this.IndexBase);
      this.ShowCount(this.RelativeArray, this.ListPos);
    }

    this.HighlightItem(this.RelativeArray, this.ListPos);
  },

  InjectItem: function(item, index){
    // Create a new element
    var newElement = new Element('div', {
      'id': 's' + this.SuggestItem + index,
      'class': 'suggestionentry',
      'events': {
        'click': function(){
          // Select item and close suggestion box
          this.SelectItem(item);
          this.HideSuggestions()
        }.bind(this),
        'mouseenter': function(){
          newElement.removeClass('mouseleave');
          newElement.addClass('mouseenter');
        }.bind(this),
        'mouseleave': function(){
          newElement.removeClass('mouseenter');
          newElement.addClass('mouseleave');
        }.bind(this)
      }
    }).setHTML(item);

    // Inject new element into the suggestions box
    newElement.injectInside(this.SuggestionBox);
  },

  InjectSuggestions: function(){
    var iCount = 0;
    var txtC = this.InputBox.value;
    this.RelativeArray.each(function(item, index){
    	//alert(item);
    	//alert(index);
      if(iCount < this.MaxDisplay && index >= this.IndexBase) {
      	item = item.replace(new RegExp('('+txtC+ ')','ig'),'<b>$1</b>');
        this.InjectItem(item, index);
        iCount++;
      }
    }, this);
  },

  SelectItem: function(item){
  	item = item.replace(/<b>/gi,'').replace(/<\/b>/gi,'');
    this.InputBox.value = item;
    redirect(item);
  },


  DoFade: function(){
    if(this.IsOpen == true && this.HasEntered == false) {
      this.HideSuggestions();
    }
  },

  BeginFade: function(){
    if(this.IsOpen == true)
    {
      this.DoFade.bind(this).delay(500);
    }
  },

  ShowCount: function(){
    var newElement = new Element('div', {
      'class': 'suggestioncount'
    }).setHTML((this.ListPos+1) + '/' + this.RelativeArray.length + ' suggestions');
    // Inject new element into the suggestions box
    newElement.injectInside(this.SuggestionBox);
  },

  CloseSuggestions: function(){
    this.IsOpen = false;
    this.ToggleFX.set(0);
  },

  HideSuggestions: function(){
    this.ListPos = null;
    this.MyPos = 1;
    this.Indexbase = 0;
    this.IsOpen = false;
    this.ToggleFX.start(1, 0);
  },

  ShowSuggestions: function(){
    this.IsOpen = true;
    this.ToggleFX.start(0, 1);
  },

  EmptySuggestions: function(){
    this.SuggestionBox.setHTML('');
  },

  
  PerformSuggest: function(){
  	
    // Empty relative suggestions
    this.RelativeArray.length = 0;
  
    // Has the user typed anything?!
    if(this.InputBox.value.length > 2) {
  	  
	  this.fireEvent('perform',this);
	  
      // Reset ListPos, MyPos and IndexBase
      this.ListPos = null;
      this.MyPos = 1;
      this.Indexbase = 0;
  
      // Fill relative suggestions array
      this.SuggestArray.each(function(item, index){
  
        if(item.test("^"+this.InputBox.value, "i")) {
          // Extend matched array if item isn't exact
          if(item != this.InputBox.value) this.RelativeArray.extend([item]);
        }
  
      }, this);
	  
	  this.AsyncLoadFunc(this,
	    function() { //on ajax load completed,do flow
			// Did anything match? Then show it!
			//alert(this.IsOpen);
			//alert(this.RelativeArray.length);
	      if(this.IsOpen == false && this.RelativeArray.length > 0) {
	      	this.preInputLength = this.InputBox.value.length;
	        this.EmptySuggestions();
	        this.InjectSuggestions(this.RelativeArray, this.IndexBase);
	        this.ShowCount(this.RelativeArray, this.ListPos);
	        this.ShowSuggestions();
	      }else if(this.IsOpen == true && this.RelativeArray.length > 0 && 
	      		  this.preInputLength != this.InputBox.value.length) {
	      	this.preInputLength = this.InputBox.value.length;
	        this.EmptySuggestions();
	        this.InjectSuggestions(this.RelativeArray, this.IndexBase);
	        this.ShowCount(this.RelativeArray, this.ListPos);
	        this.ShowSuggestions();
	      	
	      }else if(this.IsOpen == true && this.RelativeArray.length == 0){
	        this.HideSuggestions();
	      }
		}.bind(this)
	  );
	    
    } else {
      this.CloseSuggestions();
    }
  }
});

/* ******************************************************************************** */

mSuggest.implement(new Options, new Events);

/* ******************************************************************************** */


window.addEvent('domready', function(){
  var suggestArray = [];
  var iCount = 0;
  suggestionobjects = $$('input[rel=suggest]');
  suggestionobjects.each(function(txt){
    suggestArray.extend([
      new mSuggest({
        InputBox: txt,
        SuggestArray: txt.getProperty('data').split(','),
        MaxDisplay: 10,
        EffectDuration: 500,
        SuggestItem: iCount,
		AsyncLoadFunc : function(suggest,callback) {
			var url = txt.getProperty('url');
			if($chk(url) && url.length > 5) {
			var key = txt.value.substring(0,3); //cache using first two letter
		 	$load(url,function(res){
				var data  = Json.evaluate(res);
				if ($type(data) == 'array') {
				      data.each(function(item){
				        if(item.test(txt.value.replace('/','').replace('\\',''), "i")) {
				          suggest.RelativeArray.extend([item]);
				        }
				      });
				}
				callback();
			},{'prefix':key});
			}
		}
      })
    ]);
    iCount++;
  });
});
