(function($) {

  function LOG(obj) {
    if (window.console && window.console.log) {
      window.console.log(obj);
    }
    else {
      var console = $('#console');
      if (console) {
        console.append(obj);
        console.append('<br/>\n');
      }
    }
  }

  // resizable textbox

  $.fn.resizableTextbox = function(el, options) {
    var $opts = $.extend({
        min:    5,
        max:    500,
        step:   7
      }, options);
      
    var $width = el.attr('offsetWidth');
      
    el
      .bind('keydown', function(e) {
        $(this).data('rt-value', this.value.length);
      })
      .bind('keyup', function(e) {
        var $this = $(this);
        var newsize = $opts.step * $this.val().length;
        if (newsize <= $opts.min) {
          newsize = $width;
        }
        if (!($this.val().length == $this.data('rt-value') ||
              newsize <= $opts.min ||
              newsize >= $opts.max)) {
          $this.width(newsize);
        }
      });
  };


  $.fn.autobox = function(options) {

    return this.each(function() {

      // member vars
      var $auto_hide;
      var $count = 0;
      var $current = undefined; // currently focused element
      var $bits = { };
      var $opts = {
        className : 'bit'
      };
      var $maininput = undefined;
      var $element = undefined; // this element
      // auto
      var $autoholder = undefined;
      var $autoresults = undefined;
      var $resultsshown = undefined;
      var $data = [];
      var $dosearch = false;
      var $autocurrent = undefined;
      var $autoenter = false;
      var $isCity = false;
      var $lastinput = undefined;
      var $holder = undefined;


      // member methods

      function setEvents() {
        $(document)
          .bind($.browser.msie ? 'keydown' : 'keypress', function(e) {
            if (e.keyCode == 8) { // 8=BACKSPACE
                e.stopPropagation();
            }
          });

        $(document)
          .bind('keyup', function(e) {
            e.stopPropagation();
            if (!$current) {
              return;
            }
            switch(e.keyCode) {
              case 37: return move('left'); // left arrow
              case 39: return move('right');// right arrow
              case 46: case 8:
                if ($current.data('type') == 'box') {
                  dispose($current);
                  return false;
                }
                break;
            }
          });

        $(document)
          .bind('click', function(e) {
            $(document).trigger('blur');
          });
      }

      function update() {
        var buf = '';
        for (var key in $bits) {
          if (buf.length > 0) {
            buf += $opts.separator;
          }
          buf += $bits[key].value;
        }
        $element.val(buf);
        return $element;
      }

      function add(obj, html) {
        if ($opts.isCity) {
          dispose($holder.find('li.bit-box:last'));
        }
        var id = $opts.className + '-' + $count++;
        var el =
          createBox(obj ? obj.caption : html, $maininput)
            .attr('id', id)
            .bind('click', function(e) {
              e.stopPropagation();
              focus(el);
              autoHide();
            }).data('obj', obj)
            .insertBefore($maininput);
        $bits[id] = obj;
        update();
        autoHide();
      }

      function dispose(el) {
        autoFeed(el.data('obj'));
        delete $bits[el.attr('id')];
        update();
        if ($current == el) {
          focus(el.next());
        }
        if (el.data('type') == 'box') {
          el.trigger('boxDispose');
        }
        el.remove();
        return this;
      }

      /**
       * Add focus class to current.
       * If the current is input, then focus it.
       * Set current to the element.
       */
      function focus(el) {
        if ($current && $current == el) {
          return el;
        }

        blur();

        el.addClass($opts.className + '-' + el.data('type') + '-focus');

        if (el.data('type') == 'input') {
          var input = el.data('input');
          input.trigger('inputFocus');
          setTimeout(function() { input[0].focus(); }, 200);
        }
        else {
          el.trigger('boxFocus');
        }

        $current = el;
        return el;
      }

      /**
       * If current is input, then blur the control.
       * Remove focus class from current and set current to undefined..
       */
      function blur() {
        if (!$current)
          return this;

        if ($current.data('type') == 'input') {
          var input = $current.data('input');
          setTimeout(function() { input[0].blur(); }, 200);//causes recursive call on blur() on some browsers
          input.trigger('inputBlur');
        }
        else {
          $current.trigger('boxBlur');
        }

        $current.removeClass($opts.className + '-' + $current.data('type') + '-focus');
        if ($current) { // if called recursively (see above), then $current==null
        }
        $current = undefined;
        return this;
      }

	function actOnRadio(elm)
	{
		if ($(elm).parents(".row").hasClass("show-alert")){
			$(elm).parents(".row").removeClass("show-alert");
		}

		$(elm).parents(".radio-list:visible").hide();

		//adding the box
		var atadd = {};
		atadd.caption = $(elm).attr("rel");
		atadd.value = $(elm).val();
		add(atadd);


		autoHide();
		$maininput.data('input').val('');
	}

      function createBox(text, focusElementOnRemove) {
        var li = $('<li><div><span><em>'+text+'</em></span></div></li>')
                 .addClass($opts.className + '-box')
                 .data('type', 'box');
        if (!$opts.noRemove) {
          li
            .bind('mouseenter', function(e) {
              li.addClass('bit-hover');
            })
            .bind('mouseleave', function(e) {
              li.removeClass('bit-hover');
            });
            $(li).find('span:first').append($('<a href="javascript:;" class="close"></a>')
                  .bind('click', function(e) {
                    e.stopPropagation();
                    if (!$current) {
                      focus(focusElementOnRemove);
                    }
                    dispose(li);
                  }))
            .data('text', text);
        }
        bindCustomEvents(li);
        return li;
      }

      function createInput() {
        var li = $('<li class="' + $opts.className + '-input"></li>');

        var input = $('<input type="text"></input>');
        input
          .bind('click', function(e) {
            e.stopPropagation();
          })
          .bind('focus', function(e) {
              //focus(li);
          })
          .bind('blur', function(e) {
	
		/*
			if ($opts.isCity && input.val().length >= 3){
				alert('blur');
			}
		*/	
			
			/*
            if ($current == li) {
              //$current = undefined;
              blur();
            }
			*/
			
			//else if($opts.isCity && input.val().length >= 3){
			if($opts.isCity && input.val().length >= 3){
				//alert("here");
				var $typed = input.val();
				var $hidn = $element.val();
				var $thisrow = $maininput.parents(".row");
				var $radiolist = $thisrow.find(".radio-list");
				
				//-- looking for the submit button
				var $sbutton = $thisrow.parents(".tags").find("a.btn-save img:first");
				$sbutton.addClass("giveopacity");
				$sbutton.parents("a:first").addClass("dizabled");
				
				
				var $flag = $thisrow.find(".flag-img img:first:visible");
				var $flagsrc = $flag.attr("src");
				var dirs = $flagsrc.split("/");
				$filename = dirs[dirs.length - 1];
				$cntry = $filename.substr(0, 2);
				$call = $radiolist.attr("rel");
				
				
				// 10 - 07 - 2009 -- loading management (add rolling ico and disable save button)
				$targetico = '/images/loading.gif';
				$flag.attr("src", $targetico);
				$flag.attr("width", 16);
				$flag.attr("height", 16);
				
				
				$.getJSON($call, {"city": $typed, "country": $cntry}, function(json) {
					
					$flag.attr("src", $flagsrc);
					$flag.attr("height", 11);
					$sbutton.removeClass("giveopacity");
					$sbutton.parents("a:first").removeClass("dizabled");
					
					if (json.length > 1){
						
						$radiolist.html("");
						
						$.each(json, function(idx,str){
							
							var $rd = $('<input type="radio" name="ouaich"></input>');
							var $lbl = $('<label></label>');
							var $li = $('<li></li>');
							
							
							$rd.bind("click", function(e){
								//alert("id");
								actOnRadio(this);
							});
							
							$rd.attr("id", "rdo-"+str.value);
							$rd.attr("rel", str.caption);
							$rd.val(str.value);
							$lbl.text(str.caption);
							$lbl.attr("for", $rd.attr("id"));
							
							var $htm = $li.append($rd).append($lbl);
							$radiolist.append($htm);
							
							
						});
						
						$thisrow.addClass("show-alert");
						$thisrow.find(".input-alert p").text("Choose a city below");
						$radiolist.fadeIn("slow");
					}
					else if (json.length == 1){
						var $toAdd = {};
						$toAdd.caption = json[0].caption;
						$toAdd.value = json[0].value;
						add($toAdd);
						autoHide();
						$maininput.data('input').val('');
					}
					else{
						$thisrow.find(".input-alert p").text("Please enter a valid city");
						$thisrow.addClass("show-alert");
					}
				}); 
			}
          })
          .bind('keydown', function(e) {
            $(this)
              .data('lastValue', this.value)
              .data('lastCaret', getCaretPosition(input));
            if ($autoholder) {
              $dosearch = false;
              switch (e.keyCode) {
                case 38 : return autoMove('up');
                case 40 : return autoMove('down');
                case 8 : {
                    if ($holder.find('input').attr('value') == '')
                      if ($holder.find('li.bit-box:last').length) {
                        dispose($holder.find('li.bit-box:last')); break;
                        autoHide();
                      }
                      autoHide();
                  }
                case 13 : // enter
                  if ($resultsshown && $autocurrent && $autocurrent.data('result')) {
                    autoAdd($autocurrent);
                    $autocurrent = false;
                    $autoenter = true;
                    autoHide();
                  }
                 /* else if (this.value) {
                    add(this.value);
                    this.value = '';
                  }*/
                  break;
                case 27 : // esc
                  if (!$resultsshown && $current && $current.data('input')) {
                    setTimeout(function() { $current.data('input').val('') }, 0);
                  }
                  else {
                    e.stopPropagation();
                    autoHide();
                    return false;//skip IE default behavior (clear field)
                  }
                  break;
                default:
                  $dosearch = true;
              }

              if ($autoenter && $.browser.msie) {
                e.stopPropagation();
                $autoenter = false;
              }

              return e.keyCode != 13; // skip IE default behavior (beeps)
            } else autoHide();
          })
          .bind('keypress', function(e) {
            if ($autoenter && !$.browser.msie) {
              e.stopPropagation();
              $autoenter = false;
            }
            //autoHide();
          })
          .bind('keyup', function(e) {
            if ($autoholder) {
              if ($dosearch) {
                autoShow(input.val());
              }
            }
          });
        bindCustomEvents(input);

        return li.data('type', 'input')
                 .data('input', input)
                 .append(input);
      }

      function makeResizable(li) {
        var el = li.data('input');
        el.data('resizable', $.fn.resizableTextbox(el, $.extend($opts.resizable, { min: el.attr('offsetWidth'), max: $element.width() })));
        return this;
      }

      function checkInput() {
        var input = $current.data('input');
        return !input.data('lastValue') ||
               (getCaretPosition(input) === 0 && input.data('lastCaret') === 0);
      }

      function move(direction) {
        var el = direction == 'left' ? $current.prev() : $current.next();
        if (el.length > 0 && (!$current.data('input') || checkInput() || direction == 'right')) {
          focus(el);
        }
        return this;
      }

      function isObjEmpty(obj) {
        for (var i in obj) {
          return false;
        }
        return true;
      }

      function getCaretPosition(input) {
        if (input.createTextRange) {
          var r = document.selection.createRange().duplicate();
          r.moveEnd('character', input.val().length);
          if (r.text === '') {
            return input.val().length;
          }
          return input.val().lastIndexOf(r.text);
        }
        else {
          return input.attr('selectionStart');
        }
      }

      var specials = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\' ];
      var specialsRE = new RegExp('(\\' + specials.join('|\\') + ')', 'g');

      function escRE(text) {
        return text.replace(specialsRE, '\\$1');
      }

      function autoShow(search) {
        $maininput.parents('.row').find('.drop-countries').hide();
        $autoholder.show();
        $autoholder.children('ul').hide();
        $maininput.parents('.row').css('position', 'relative');
        if (!search || !$.trim(search) ||
            (!search.length || search.length < $opts.autocomplete.minchars)) {
          $autoholder.find('.default').show();
          $resultsshown = false;
        }
        else {
          $resultsshown = true;
          $autoresults.show().empty();
          var j = 0;
          
          search = escRE(search);
          var _result_count = $opts.autocomplete.maxresults;
          $.each(
              $.grep($data, function(obj, idx) {
               // return idx < $opts.autocomplete.maxresults ?
                //  (obj ? (new RegExp(search, 'i')).test(obj.caption) : false) : false;
                if (obj && _result_count > 0){
                  if ((new RegExp(search, 'i')).test(obj.caption)) _result_count--;
                  return (new RegExp(search, 'i')).test(obj.caption)
                }
                else{
                  return false;
                }
              }),
              function(item) {
                var el =
                  $('<li></li>')
                  .bind('mouseenter', function(e) {
                    autoFocus($(this));
                  })
                  .bind('click', function(e) {
                    e.stopPropagation();
                    autoAdd($(this));
                    autoHide();
                  })
                  .html('<a href="javascript:;">'+autoHighlight(this.caption, search)+'</a>')
                  .data('result', this);
                $autoresults.append(el);
                $autoholder.css('bottom', -1*$autoresults.attr('offsetHeight'));
                if (j == 0) {
                  ++j;
                  autoFocus(el);
                }
              }
          );
        }
        return this;
      }

      function autoHighlight(html, highlight) {
        return html.replace(new RegExp(highlight, 'gi'), function(match) {
          return '<em>' + match + '</em>';
        });
      }

      function autoHide() {
        //alert(1);
        $maininput.parents('.row').find('.drop-countries').hide();
        $maininput.parents('.row').css('position', 'static');
		$current = undefined;//trick - for radio list
        $resultsshown = false;
        $autoholder.hide();
      }
      function autoFocus(el) {
        if (el) {
          if ($autocurrent) {
            $autocurrent.removeClass('auto-focus');
          }
          $autocurrent = el.addClass('auto-focus');
        }
      }

      function autoMove(direction) {
        if ($resultsshown && $autocurrent) {
          if (direction == 'up') {
            if ($autocurrent.prev().length > 0)
              autoFocus($autocurrent.prev());
          }
          else {
            if ($autocurrent.next().length > 0)
              autoFocus($autocurrent.next());
          }
        }
        return this;
      }

      function autoFeed(text) {
        for (var i = 0; i < $data.length; ++i) {
          if ($data[i] == text)
            return this;
        }
        $data.push(text);
        return this;
      }

      function autoAdd(el) {
        if (el && el.data('result')) {
          add(el.data('result'));
          for (var i = 0; i < $data.length; ++i) {
            if ($data[i] == el.data('result')) {
              delete $data[i];
              break;
            }
          }

          autoHide();

          $maininput.data('input').val('');
          focus($maininput);
        }
      }

      function bindCustomEvents(el) {
        // bind custom events, events are in options with ^on[A-Z]\w* : function
        for (var k in $opts) {
          if (k.search(/^on[A-Z]/) == 0 && typeof $opts[k] == 'function') {
            var ev = k.substr(2,1).toLowerCase() + k.substr(3);
            el.bind(ev, $opts[k]);
          }
        }
      }

      // body
      //$(this).parent('li').addClass('autobox-input-text');

      $opts = $.extend({
          // auto
          onBoxDispose : function(item) {
            if ($autoholder) {
              autoFeed($(this).data('text'));
            }
          },
          onInputFocus : function() {
            if ($autoholder) {
              autoShow();
            }
          },
          onInputBlur : function(e) {
            if ($autoholder) {
              $lastinput = $(this);
              // we need to call autoHide _after_ the click is called, clever hack?
              //if ($($maininput).parents('.row').find('.drop-countries').css('display') == 'none') setTimeout(function() { autoHide(); }, 200);
            }
          }
        },
        $.fn.autobox.defaults,
        options);

      // support metadata plugin (element specific options)
      var o = $.meta ? $.extend({ }, $opts, $(this).data()) : $opts;

      $element = $(this);
      $(this).hide();

      $maininput = createInput();
      $maininput
        .find('input')
        .addClass('maininput');

      $holder =
        $('<ul class="input-area"></ul>')
          .addClass('autobox-holder')
            .bind('click', function(e) {
              e.stopPropagation();
              if ($current != $maininput) {
                focus($maininput);
              }
              return false;
            })
            .append($maininput)
            .insertBefore($(this));

      $autoholder = $('#' + this.id + '-auto');//.wrapInner('<div class="stretch-bg"></div>');
      if ($autoholder) {
        $autoholder
          .addClass('drop-select-countries')
          //.css('opacity', $opts.autocomplete.opacity)
          .hide();
        $autoresults = $autoholder.children('ul');
        $autoresults.wrap('<div class="stretch-bg"></div>')
        $autoresults.children('li').each(function() {
          var obj = {};
          obj.caption = $(this).html();
          obj.value = $(this).attr('class').replace('id-', '');
          add(obj);
        });
      }
	$(".row .input-alert").bind("click", function(e){

		if ($opts.isCity){
			$(this).parents(".row").find(".radio-list:visible").hide();
			$(this).parents(".row").find("input:text:first:visible").val("");
			$(this).parents(".row").find("input:text:first:visible").focus();
		}

		$(this).parents(".row").removeClass("show-alert");
		return false;

	})
      makeResizable($maininput);
      setEvents();

      // public methods are added to this
      this.add = add;
      this.autoFeed = autoFeed;
      this.isCity = $isCity;
    });

  };

  $.fn.autobox.defaults = {
    resizable :   { },
    className :   'bit',
    separator :   ',',
    startInput :  true,
    isCity :  false,
    hideEmpty :   true,
    noRemove :    false,        // set to true if no remove boxes
    // auto
    autocomplete : {
      opacity :         1,
      maxresults :      10,
      minchars :        1
    }
  };


})(jQuery);
