/*  -----------------------------------------------------------------
 *  Author: Korobov Sergey 
 *  e-mail: mag@korobov.info
 *  icq: 305615
 *  jabber: jabber@mag.tc
 *
 *  magTags: Class for add autocomplete feature for tags
 *
 *  Usage: 
 *    1. Initialize tags defaults:
 *       var def_tags = ['tag1', 'tag2', 'tag3']// (or get it from server througth ajax)
 *
 *    2. You need <input type=text id="some_id"> and start class works:
 *
 *		var mt = new magTags('some_id', {
 *		  tags: def_tags
 *		});
 *
 *
 *--------------------------------------------------------------------------*/


		var magTags = Class.create();
		magTags.prototype = {
		  initialize: function(id){
		    this.el = $(id);

		    this.options = Object.extend({
		      tags:[],
		      remote: null,
		      separator: ','
		    },arguments[1]||{});
		    

		    this.el.autocomplete = 'off';

		    if ( this.options.remote != null ){
		      var obj = this;
		      new Ajax.Request(this.options.remote, {
		        onSuccess: function(transport) {
		        
		          if ( transport.status == 200 ) {
		            obj.options.tags = eval(transport.responseText);
  		          }
		          else
		            alert('Error while loading data!');
		        }

		      });
		    }

		    Event.observe(this.el, "keyup", this.keyUp.bindAsEventListener(this));
		    Event.observe(this.el, "keydown", this.keyDown.bindAsEventListener(this));
		    
		    this.firstClickEvent = this.firstClick.bindAsEventListener(this);
		    Event.observe(this.el, "click", this.firstClickEvent);

		    Event.observe(document.body, "click", this.click.bindAsEventListener(this));


		  },

		  getCaretPosition: function(){
		    var o = this.el;

		    if (o.createTextRange) {
		      var r = document.selection.createRange().duplicate()
		      r.moveEnd('character', o.value.length)
		      if (r.text == '') return o.value.length
			return o.value.lastIndexOf(r.text)
		    } 
		    else return o.selectionStart

		  },

		  setCaretPosition: function(pos){
		    if ( this.el.setSelectionRange ){
		      this.el.focus();
		      this.el.setSelectionRange(pos, pos);
		    }
		    else if ( this.el.createTextRange ){
		      var range = this.el.createTextRange();
		      range.collapse(true);
		      range.moveEnd('character', pos);
		      range.moveStart('character', pos);
		      range.select();
		    }
		  },

		  keyDown: function(e){
		    var code = e.keyCode;

		    //if up and down cursor buttons
		    if ( code == 38 || code == 40 ){
		      Event.stop(e);
		      return this.navigate(code);
		    }
		    
		    //if enter
		    if ( code == Event.KEY_RETURN ){
		      Event.stop(e);

		      this.typeSelectedTag();		      
		      return;
		    }

		    
		  },

		  keyUp: function(e){
		    var code = e.keyCode;

		    // ignore tab, backspace, left, right, and delete
		    if (code == 9 /*|| code == 8 */|| code == 37 || code == 39 || code == 46 || code == 38 || code == 40)
		       return false;


		    this.caretPosition = this.getCaretPosition();


		    var word = this.getWord(this.caretPosition);

		    var similarTags = this.findSimilar(word);

		    this.drawResultsDiv(similarTags);



		  },

		  firstClick: function(e){
		    
		    var value = this.el.value.strip();
		    if (value.length > 0) {
		      if (value[value.length-1] != this.options.separator) {
		        this.el.value = value + this.options.separator + ' ';
		      }

		      this.setCaretPosition(this.el.value.length);
		    }
		    Event.stopObserving(this.el, 'click', this.firstClickEvent);
		    
		  },


		  //get current typed word, dependend on cursor position
		  //
		  getWord: function(pos){
		    var value = this.el.value;

		    //if we on the end of tags field
		    if ( pos == value.length ) {
		      value = value.strip();
		      var tmp = value.split(this.options.separator);
		      this.leftBorder = value.lastIndexOf(this.options.separator);
		      return tmp[tmp.length-1].replace(/(^\s+)|(\s+$)/g, '');
		    }
		    else {		      
		      value = value.strip();
		      //if we have more that one tag
		      var sepPos = value.substring(0, pos).lastIndexOf(this.options.separator)
		      var leftBorder = sepPos != -1 ? sepPos : 0;

		      var sepPosLast = value.indexOf(this.options.separator, pos)
		      var rightBorder = sepPosLast != -1 ? sepPosLast : 0;

		      if ( leftBorder == rightBorder )
		        leftBorder = 0;

		      this.leftBorder = leftBorder;


		      return value.substring(leftBorder, rightBorder).replace(this.options.separator, '').strip().toLowerCase();

		    }

		  },

		  //search similar tags in array
		  //may be need todo AJAX call
		  //
		  findSimilar: function(word){
		     var tags = this.options.tags;
		     var founded = [];

		     var enteredTags = this.el.value.split(this.options.separator);

		     if ( word.length == 0 )
		       return [];

		     word = word.toLowerCase();

		     for ( i = 0; i < tags.length; i++ ){
		       if (tags[i].toLowerCase().indexOf(word) == 0){
		         var found = false;
		         enteredTags.each(function(t){
		           if ( t.strip() == tags[i] )
		             found = true;
		         })

		         if ( !found )
		           founded.push(tags[i]);
		       }
		     }

		     return founded;

		  },

		  //draw div with results
		  //
		  drawResultsDiv: function(words){

		    var fieldPos = Position.cumulativeOffset(this.el);


		    //if calls first time - create new div
		    if (!this.unique){
		      var date = new Date();
		      this.unique = date.getTime();
		      
		      var div = document.body.appendChild(document.createElement('DIV'));
		      div.id = 'magTagsResults_' + this.unique;
		      div = $(div.id);
		      div.addClassName('magTagResultDiv');

		    }
		    //else we can use existings
		    else {
		      var div = $('magTagsResults_' + this.unique);
		      div.innerHTML = '';
		    }

		    div.setStyle({
		      top: (fieldPos[1] + 25) + 'px',
		      left: (fieldPos[0] + 30) + 'px'
		    });


		    this.resultsDiv = div;

		    if ( words.length == 0 ) {
		      div.hide();
		      return;
		    }


		    //add all finded tags to the div
		    //
		    for ( var i = 0; i < words.length; i++ ){
		      var w = div.appendChild(document.createElement('DIV'));
		      w.id = 'magTag_' + i;
		      w.nextId = i >= words.length-1 ? 0 : i+1;
		      w.prevId = i > 0 ? i-1 : words.length-1;

		      w = $(w.id);
		      w.innerHTML = words[i];

		      var obj = this;
		      w.onclick = function(){
		        obj.setActiveTag(this.id);
		        obj.typeSelectedTag();
		      }

		      //mark first tag as active
		      if ( i == 0 ){
		        this.activeTag = w.id;
		        this.toggleActive(w.id);
		      }
		      
		    }

		    div.show();
		      

		  },

		  //toggle method for active tag
		  //
		  toggleActive: function(id) {
		    var w = $(id);
		    var className = 'magTagActiveTag';
		    w[w.hasClassName(className) ? 'removeClassName' : 'addClassName'](className);
		  },


		  //set another tag as active and deactivate current (old active)
		  //
		  setActiveTag: function(id){

		    if ( this.activeTag ){
		      var w = $(this.activeTag);
		      this.toggleActive(this.activeTag);


		      this.activeTag = id;
		      var w = $(id);
		      this.toggleActive(id);

		    }

		  },

		  //make navigation with cursor keys
		  //
		  navigate: function(code){

		    if ( !this.activeTag )
		      return;

		    var w = $(this.activeTag);

		    // go up
		    if ( code == 38 ) {
		      this.setActiveTag('magTag_' + w.prevId);
		    }

		    // go down
		    else {
		      this.setActiveTag('magTag_' + w.nextId);
		    }


		  },


		  //type selected tag to input field and add separator to the end
		  //
		  typeSelectedTag: function (){
		    value = this.el.value;

		    if ( this.activeTag ) {
		      var w = $(this.activeTag);
		      var tag = w.innerHTML;

		      var endText = value.substr(this.caretPosition);
		      if ( this.leftBorder > 0 )
		        var startText = value.slice(0, this.leftBorder) + this.options.separator + ' ';
		      else 
		        var startText = '';
		      

		      if ( !endText || endText[0] != this.options.separator ){
		        tag = tag + this.options.separator + ' ';
		      }


		      this.el.value = startText + tag + endText;
		      this.el.focus();

		    }

		    this.hide();
		  },


		  //close current opened div with tags results
		  //
		  hide: function(){
		    if (this.resultsDiv) {
		      this.resultsDiv.hide();
		      this.activeTag = null;
		    }
		  },

		  click: function(e){
		    var elt = Event.findElement(e, 'DIV');
		    if ( !elt || (elt && !elt.hasClassName('magTagResultDiv')) )
		      this.hide();
		  }


		}
		  
 