/**
 * -----------------------------------------------------------------------------
 * file: ui.inputTag.js
 * file version: 1.1.1
 * date: 2012-06-18
 *
 * A jQuery plugin provided by the piwigo's plugin "GrumPluginClasses"
 *
 * -----------------------------------------------------------------------------
 * Author     : Grum
 *   email    : grum@piwigo.com
 *   website  : http://photos.grum.fr
 *
 *   << May the Little SpaceFrog be with you ! >>
 * -----------------------------------------------------------------------------
 *
 *
 *
 *
 * :: HISTORY ::
 *
 * | release | date       |
 * | 1.0.0   | 2010/10/10 | * first release
 * |         |            |
 * | 1.1.0   | 2010/11/03 | * add 'isValid' method
 * |         |            |
 * | 1.1.1   | 2012/06/18 | * improve memory managment
 * |         |            |
 * |         |            |
 * |         |            |
 *
 */



(
  function($)
  {
    /*
     * plugin 'public' functions
     */
    var publicMethods =
    {
      init : function (opt)
        {
          return this.each(function()
            {
              // default values for the plugin
              var $this=$(this),
                  data = $this.data('options'),
                  objects = $this.data('objects'),
                  properties = $this.data('properties'),
                  options =
                    {
                      ignoreCase:true,
                      //allowCreate:false,
                      serverUrl:'',
                      serverCallDelay:250,
                      postData:{},  // additional free data sent to the server

                      listMaxWidth:0,
                      listMaxHeight:0,
                      maximumTagLoaded:0,  //0 = no limits

                      textStart:'Start to type text...',
                      textFound:'%s tags found',
                      textDisplay:'display only %s tags',

                      mode:'public',
                      filter:'affected',

                      inputNumCar:5,

                      add:null,
                      remove:null,
                      popup:null,
                      load:null
                    };

              // if options given, merge it
              // if(opt) $.extend(options, opt); ==> options are set by setters

              $this.data('options', options);


              if(!properties)
              {
                $this.data('properties',
                  {
                    initialized:false,
                    selectorVisible:false,
                    totalTags:0,
                    tags:[], // a tag = {id:0, name:''}
                    cache:[],
                    timerHandle:null,
                    isValid:true
                  }
                );
                properties=$this.data('properties');
              }

              if(!objects)
              {
                objects =
                  {
                    container:$('<div/>',
                        {
                          'class':'ui-tag-selector-input',
                          css:{
                            width:'100%'
                          }
                        }
                    ).bind('click.inputTag',
                        function ()
                        {
                          objects.input.focus();
                        }
                      ),
                    selectedTagList:$('<ul/>',
                      {
                        html: '',
                        'class':'ui-tag-selector-selected-tag-list'
                      }
                    ),
                    input:$('<input>',
                      {
                        type:"text",
                        value:''
                      }
                    ).bind('focusout.inputTag',
                        function ()
                        {
                          privateMethods.lostFocus($this);
                        }
                      )
                      .bind('focus.inputTag',
                          function ()
                          {
                            privateMethods.getFocus($this);
                          }
                        )
                      .bind('keypress.inputTag',
                          function ()
                          {
                            privateMethods.setTimerHandle($this);
                          }
                        ),
                    selectorList:$('<div/>',
                        {
                          html: "",
                          'class':'ui-tag-selector-list',
                          css: {
                            display:'none',
                            position:'absolute',
                            zIndex:9999
                          }
                        }
                    ).bind('mouseleave.inputTag',
                        function ()
                        {
                          privateMethods.displaySelector($this, false);
                        }
                      ),
                    tagList:$('<ul/>',
                      {
                        css: {
                          listStyle:'none',
                          padding:'0px',
                          margin:'0px',
                          overflow:"auto"
                        }
                      }
                    ),
                    textArea:$('<div/>',
                      {
                        html:'',
                        'class':'ui-tag-selector-text'
                      }
                    )
                  };

                $this
                  .html('')
                  .append(objects.container.append(objects.selectedTagList.append($('<li/>').append(objects.input) ) ) )
                  .append(objects.selectorList.append(objects.tagList).append(objects.textArea));

                $this.data('objects', objects);
              }

              privateMethods.setOptions($this, opt);
            }
          );
        }, // init
      destroy : function ()
        {
          return this.each(
            function()
            {
              // default values for the plugin
              var $this=$(this),
                  objects = $this.data('objects');
              objects.selectedTagList.children().unbind();
              objects.input.unbind().remove();
              objects.container.unbind().remove();
              objects.selectorList.unbind().remove();
              objects.tagList.remove();
              $this
                .unbind('.categorySelector')
                .removeData()
                .css(
                  {
                    width:'',
                    height:''
                  }
                );
              delete $this;
            }
          );
        }, // destroy

      options: function (value)
        {
          return this.each(function()
            {
              privateMethods.setOptions($(this), value);
            }
          );
        }, // autoLoad


      ignoreCase: function (value)
        {
          if(value!=null)
          {
            return this.each(function()
              {
                privateMethods.setIgnoreCase($(this), value);
              }
            );
          }
          else
          {
            var options = this.data('options');

            if(options)
            {
              return(options.ignoreCase);
            }
            else
            {
              return(true);
            }
          }
        }, // ignoreCase

      inputNumCar: function (value)
        {
          if(value!=null)
          {
            return this.each(function()
              {
                privateMethods.setInputNumCar($(this), value);
              }
            );
          }
          else
          {
            var options = this.data('options');

            if(options)
            {
              return(options.inputNumCar);
            }
            else
            {
              return(true);
            }
          }
        }, // ignoreCase

/*
      allowCreate: function (value)
        {
          if(value)
          {
            this.each(function()
              {
                var $this=$(this);
                privateMethods.setAllowCreate($this, value);
                return($this);
              }
            );
          }
          else
          {
            var options = this.data('options');

            if(options)
            {
              return(options.allowCreate);
            }
            else
            {
              return(false);
            }
          }
        }, // allowCreate
*/
      maximumTagLoaded: function (value)
        {
          if(value!=null)
          {
            return this.each(function()
              {
                privateMethods.setMaximumTagLoaded($(this), value);
              }
            );
          }
          else
          {
            var options = this.data('options');

            if(options)
            {
              return(options.maximumTagLoaded);
            }
            else
            {
              return(0);
            }
          }
        }, // maximumTagLoaded

      listMaxWidth: function (value)
        {
          if(value!=null)
          {
            return this.each(function()
              {
                privateMethods.setListMaxWidth($(this), value);
              }
            );
          }
          else
          {
            var options = this.data('options');

            if(options)
            {
              return(options.listMaxWidth);
            }
            else
            {
              return(0);
            }
          }
        }, // listMaxWidth

      listMaxHeight: function (value)
        {
          if(value!=null)
          {
            return this.each(function()
              {
                privateMethods.setListMaxHeight($(this), value);
              }
            );
          }
          else
          {
            var options = this.data('options');

            if(options)
            {
              return(options.listMaxHeight);
            }
            else
            {
              return(0);
            }
          }
        }, // listMaxHeight


      serverCallDelay: function (value)
        {
          if(value!=null)
          {
            return this.each(function()
              {
                privateMethods.setServerCallDelay($(this), value);
              }
            );
          }
          else
          {
            var options = this.data('options');

            if(options)
            {
              return(options.serverCallDelay);
            }
            else
            {
              return(0);
            }
          }
        }, // serverCallDelay


      serverUrl: function (value)
        {
          if(value!=null)
          {
            return this.each(function()
              {
                privateMethods.setServerUrl($(this), value);
              }
            );
          }
          else
          {
            var options = this.data('options');

            if(options)
            {
              return(options.serverUrl);
            }
            else
            {
              return('');
            }
          }
        }, // serverUrl

      postData: function (value)
        {
          if(value!=null)
          {
            // set selected value
            return(
              this.each(
                function()
                {
                  privateMethods.setPostData($(this), value, true);
                }
              )
            );
          }
          else
          {
            var options=this.data('options');
            return(options.postData);
          }
        }, // postData

      textStart: function (value)
        {
          if(value!=null)
          {
            return this.each(function()
              {
                privateMethods.setTextStart($(this), value);
              }
            );
          }
          else
          {
            var options = this.data('options');

            if(options)
            {
              return(options.textStart);
            }
            else
            {
              return('');
            }
          }
        }, // textStart

      textFound: function (value)
        {
          if(value!=null)
          {
            return this.each(function()
              {
                privateMethods.setTextFound($(this), value);
              }
            );
          }
          else
          {
            var options = this.data('options');

            if(options)
            {
              return(options.textFound);
            }
            else
            {
              return('');
            }
          }
        }, // textFound

      textDisplay: function (value)
        {
          if(value!=null)
          {
            return this.each(function()
              {
                privateMethods.setTextDisplay($(this), value);
              }
            );
          }
          else
          {
            var options = this.data('options');

            if(options)
            {
              return(options.textDisplay);
            }
            else
            {
              return('');
            }
          }
        }, // textDisplay

      filter: function (value)
        {
          if(value!=null)
          {
            return this.each(function()
              {
                privateMethods.setFilter($(this), value);
              }
            );
          }
          else
          {
            var options = this.data('options');

            if(options)
            {
              return(options.filter);
            }
            else
            {
              return(true);
            }
          }
        }, // filter

      mode: function (value)
        {
          if(value!=null)
          {
            return this.each(function()
              {
                privateMethods.setMode($(this), value);
              }
            );
          }
          else
          {
            var options = this.data('options');

            if(options)
            {
              return(options.mode);
            }
            else
            {
              return(true);
            }
          }
        }, // mode

      value: function (value)
        {
          if(value!=null)
          {
            // set selected value
            return this.each(function()
              {
                privateMethods.setValue($(this), value);
              }
            );
          }
          else
          {
            // return the selected tags
            var properties=this.data('properties');

            return(properties.tags);
          }
        }, // value

      isValid: function (value)
        {
          if(value!=null)
          {
            // set selected value
            return this.each(function()
              {
                privateMethods.setIsValid($(this), value);
              }
            );
          }
          else
          {
            // return the selected tags
            var properties=this.data('properties');

            return(properties.isValid);
          }
        }, // isValid

      load: function (value)
        {
          /*
           * two functionnalities :
           *  - if value is set, use it to set the load event function
           *  - if no value, loads data from server
           */
          if(value && $.isFunction(value))
          {
            // set selected value
            return this.each(function()
              {
                privateMethods.setEventLoad($(this), value);
              }
            );
          }
          else
          {
            // loads data from server
            privateMethods.load(this);
          }
        },

      popup: function (value)
        {
          if(value && $.isFunction(value))
          {
            // set selected value
            return this.each(function()
              {
                privateMethods.setEventPopup($(this), value);
              }
            );
          }
          else
          {
            // return the selected value
            var options=this.data('options');

            if(options)
            {
              return(options.popup);
            }
            else
            {
              return(null);
            }
          }
        }, // popup
      add: function (value)
        {
          if(value && $.isFunction(value))
          {
            // set selected value
            return this.each(function()
              {
                privateMethods.setEventAdd($(this), value);
              }
            );
          }
          else
          {
            // return the selected value
            var options=this.data('options');

            if(options)
            {
              return(options.add);
            }
            else
            {
              return(null);
            }
          }
        }, // add
      remove: function (value)
        {
          if(value && $.isFunction(value))
          {
            // set selected value
            return this.each(function()
              {
                privateMethods.setEventRemove($(this), value);
              }
            );
          }
          else
          {
            // return the selected value
            var options=this.data('options');

            if(options)
            {
              return(options.remove);
            }
            else
            {
              return(null);
            }
          }
        }, // remove
      numberOfTags: function ()
        {
          var properties=this.data('properties');

          if(properties)
          {
            return(properties.tags.length);
          }
          else
          {
            return(null);
          }
        } // numberOfTags

    }; // methods


    /*
     * plugin 'private' methods
     */
    var privateMethods =
    {
      setOptions : function (object, value)
        {
          var properties=object.data('properties'),
              options=object.data('options');

          if(!$.isPlainObject(value)) return(false);

          properties.initialized=false;

          privateMethods.setIgnoreCase(object, (value.ignoreCase!=null)?value.ignoreCase:options.ignoreCase);
          privateMethods.setInputNumCar(object, (value.inputNumCar!=null)?value.inputNumCar:options.inputNumCar);
          //privateMethods.setAllowCreate(object, (value.allowCreate!=null)?value.allowCreate:options.allowCreate);
          privateMethods.setValue(object, (value.value!=null)?value.value:[]);
          privateMethods.setMaximumTagLoaded(object, (value.maximumTagLoaded!=null)?value.maximumTagLoaded:options.maximumTagLoaded);
          privateMethods.setTextStart(object, (value.textStart!=null)?value.textStart:options.textStart);
          privateMethods.setTextFound(object, (value.textFound!=null)?value.textFound:options.textFound);
          privateMethods.setTextDisplay(object, (value.textDisplay!=null)?value.textDisplay:options.textDisplay);
          privateMethods.setListMaxWidth(object, (value.listMaxWidth!=null)?value.listMaxWidth:options.listMaxWidth);
          privateMethods.setListMaxHeight(object, (value.listMaxHeight!=null)?value.listMaxHeight:options.listMaxHeight);
          privateMethods.setPostData(object, (value.postData!=null)?value.postData:options.postData);
          privateMethods.setServerCallDelay(object, (value.serverCallDelay!=null)?value.serverCallDelay:options.serverCallDelay);
          privateMethods.setServerUrl(object, (value.serverUrl!=null)?value.serverUrl:options.serverUrl);
          privateMethods.setMode(object, (value.mode!=null)?value.mode:options.mode);
          privateMethods.setFilter(object, (value.filter!=null)?value.filter:options.filter);
          privateMethods.setEventPopup(object, (value.popup!=null)?value.popup:options.popup);
          privateMethods.setEventAdd(object, (value.add!=null)?value.add:options.add);
          privateMethods.setEventRemove(object, (value.remove!=null)?value.remove:options.remove);
          privateMethods.setEventLoad(object, (value.load!=null)?value.load:options.load);

          if(options.autoLoad) privateMethods.load(object);

          properties.initialized=true;
        },

      setIsValid : function (object, value)
        {
          var objects=object.data('objects'),
              properties=object.data('properties');

          if(properties.isValid!=value)
          {
            properties.isValid=value;
            if(properties.isValid)
            {
              objects.container.removeClass('ui-error');
              objects.input.removeClass('ui-error');
            }
            else
            {
              objects.container.addClass('ui-error');
              objects.input.addClass('ui-error');
            }
          }
          return(properties.isValid);
        },

      setIgnoreCase : function (object, value)
        {
          var options=object.data('options'),
              properties=object.data('properties');

          if((!properties.initialized || options.ignoreCase!=value) && (value==true || value==false))
          {
            options.ignoreCase=value;
          }
          return(options.ignoreCase);
        },

      setInputNumCar : function (object, value)
        {
          var options=object.data('options'),
              objects=object.data('objects'),
              properties=object.data('properties');

          if((!properties.initialized || options.inputNumCar!=value) && value>0)
          {
            options.inputNumCar=value;
            objects.input.attr('size', options.inputNumCar);
          }
          return(options.inputNumCar);
        },

/*
      setAllowCreate : function (object, value)
        {
          var options=object.data('options'),
              properties=object.data('properties');
          if((!properties.initialized || options.allowCreate!=value) && (value==true || value==false))
          {
            options.allowCreate=value;
          }
          return(options.allowCreate);
        },
*/

      setMaximumTagLoaded : function (object, value)
        {
          var options=object.data('options'),
              properties=object.data('properties');

          if((!properties.initialized || options.setMaximumTagLoaded!=value) && value>=0)
          {
            options.maximumTagLoaded=value;
          }
          return(options.maximumTagLoaded);
        },


      setTextStart : function (object, value)
        {
          var options=object.data('options'),
              properties=object.data('properties');

          if(!properties.initialized || options.textStart!=value)
          {
            options.textStart=value;
          }
          return(options.textStart);
        },

      setTextFound : function (object, value)
        {
          var options=object.data('options'),
              properties=object.data('properties');

          if(!properties.initialized || options.textFound!=value)
          {
            options.textFound=value;
          }
          return(options.textFound);
        },

      setTextDisplay : function (object, value)
        {
          var options=object.data('options'),
              properties=object.data('properties');

          if(!properties.initialized || options.textDisplay!=value)
          {
            options.textDisplay=value;
          }
          return(options.textDisplay);
        },

      setListMaxWidth : function (object, value)
        {
          var options=object.data('options'),
              properties=object.data('properties'),
              objects=object.data('objects');

          if((!properties.initialized || options.listMaxWidth!=value) && value>=0)
          {
            options.listMaxWidth=value;
            if(options.listMaxWidth>0)
            {
              objects.selectorList.css('max-width', options.listMaxWidth+'px');
            }
            else
            {
              objects.selectorList.css('max-width', '');
            }
          }
          return(options.listMaxWidth);
        },

      setListMaxHeight : function (object, value)
        {
          var options=object.data('options'),
              properties=object.data('properties'),
              objects=object.data('objects');

          if((!properties.initialized || options.listMaxHeight!=value) && value>=0)
          {
            options.listMaxHeight=value;
            if(options.listMaxHeight>0)
            {
              objects.tagList.css('max-height', options.listMaxHeight+'px');
            }
            else
            {
              objects.tagList.css('max-height', '');
            }
          }
          return(options.listMaxHeight);
        },

      setServerCallDelay : function (object, value)
        {
          var options=object.data('options'),
              properties=object.data('properties');

          if((!properties.initialized || options.serverCallDelay!=value) && value>0 )
          {
            options.serverCallDelay=value;
          }
          return(options.serverCallDelay);
        },

      setServerUrl : function (object, value)
        {
          var options=object.data('options'),
              properties=object.data('properties');

          if(!properties.initialized || options.serverUrl!=value)
          {
            options.serverUrl=value;
            if(options.autoLoad && properties.initialized) privateMethods.load(object);
          }
          return(options.serverUrl);
        },

      setPostData : function (object, value)
        {
          var properties=object.data('properties'),
              options=object.data('options');

          if(!properties.initialized || value!=options.postData)
          {
            options.postData=value;
          }

          return(options.postData);
        }, // setPostData

      setMode : function (object, value)
        {
          var options=object.data('options'),
              properties=object.data('properties');

          if((!properties.initialized || options.mode!=value) && (value=='admin' || value=='public'))
          {
            options.mode=value;
          }
          return(options.mode);
        },

      setFilter : function (object, value)
        {
          var options=object.data('options'),
              properties=object.data('properties');

          if((!properties.initialized || options.filter!=value) && (value=='all' || value=='affected'))
          {
            options.filter=value;
          }
          return(options.filter);
        },


      setValue : function (object, value)
        {
          var properties=object.data('properties'),
              objects=object.data('objects');

          if(value=='clear')
          {
            properties.tags=[];
            objects.selectedTagList.children('.ui-tag-selector-selected-tag').remove();
            privateMethods.cacheClear(object);
            objects.input.val('');
          }
          else
          {
            if(!$.isArray(value))
            {
              value=[value]; //works with array only
            }

            for(var i=0;i<value.length;i++)
            {
              if(value[i].id!=null && value[i].name!=null)
              {
                // remove tag if present, otherwise add it
                if(privateMethods.removeTag(object, value[i].id)==-1) privateMethods.addTag(object, value[i].id, value[i].name);
              }
              else
              {
                //not an object, consider it's a tag id to be removed
                privateMethods.removeTag(object, value[i]);
              }
            }
          }

          return(null);
        }, //setValue


      displaySelector : function (object, value)
        {
          var options=object.data('options'),
              properties=object.data('properties'),
              objects=object.data('objects'),
              popup=false;

          if(properties.selectorVisible!=value) popup=true;;

          properties.selectorVisible=value;

          if(properties.selectorVisible)
          {
            if(properties.cache.length>0)
            {
              objects.tagList.css('display', 'block');
              if(properties.cache.length<properties.totalTags)
              {
                objects.textArea.html(
                  options.textFound.replace('%s', properties.totalTags)+', '+
                  options.textDisplay.replace('%s', properties.cache.length)
                ).css('display', 'block');
              }
              else
              {
                objects.textArea.html(options.textFound.replace('%s', properties.cache.length)).css('display', 'block');
              }
            }
            else if(options.textStart!='')
            {
              objects.tagList.css('display', 'none');
              objects.textArea.html(options.textStart).css('display', 'block');
            }
            else
            {
              objects.textArea.html('').css('display', 'none');
            }

            objects.selectorList
              .css(
                {
                  display:'block',
                  'min-width':objects.selectorList.parent().css('width')
                }
              );
          }
          else
          {
            objects.selectorList.css('display', 'none');
          }

          if(options.popup && popup) object.trigger('inputTagPopup', [properties.selectorVisible]);

          return(properties.selectorVisible);
        }, //displaySelector

      load : function (object)
        {
          // load datas from server through an asynchronous ajax call
          var options=object.data('options'),
              properties=object.data('properties'),
              objects=object.data('objects');

          privateMethods.clearTimerHandle(object);

          if(objects.input.val()=='')
          {
            privateMethods.cacheClear(object);
            privateMethods.displaySelector(object, true);
            return(false);
          }


          $.ajax(
            {
              type: "POST",
              url: options.serverUrl,
              data: {
                ajaxfct:options.mode+'.inputTag.get',
                filter:options.filter,
                maxTags:options.maximumTagLoaded,
                ignoreCase:options.ignoreCase,
                letters:objects.input.val(),
                data:options.postData
              },
              async: true,
              success: function(msg)
                {
                  list=$.parseJSON(msg);

                  properties.totalTags=list.totalNbTags;
                  privateMethods.cacheClear(object);
                  privateMethods.cacheAddItems(object, list.tags);
                  if(options.load) object.trigger('inputTagLoad');

                  privateMethods.displaySelector(object, true);
                },
              error: function(msg)
                {
                  objects.selectorList.html('Error ! '+msg);
                }
            }
         );
        },

      cacheClear : function (object)
        {
          // clear the cache tag list
          var objects=object.data('objects'),
              properties=object.data('properties');

          objects.tagList.children().unbind().remove();
          properties.cache=[];
        },

      cacheAddItems : function (object, listItems)
        {
          // add the items to the cache list
          var options=object.data('options'),
              properties=object.data('properties'),
              objects=object.data('objects');

          for(var i=0;i<listItems.length;i++)
          {
            properties.cache.push(
              {
                id:listItems[i].id,
                name:listItems[i].name
              }
            );

            if(options.ignoreCase)
            {
              var re=new RegExp('(.*)('+objects.input.val()+')(.*)', 'i');
            }
            else
            {
              var re=new RegExp('(.*)('+objects.input.val()+')(.*)');
            }
            tmpResult=re.exec(listItems[i].name);
            if(tmpResult!=null)
            {
              tmpResult=tmpResult[1]+'<span class="ui-tag-selector-highlight">'+tmpResult[2]+'</span>'+tmpResult[3];
            }
            else
            {
              tmpResult=listItems[i].name;
            }

            var li=$('<li/>',
                      {
                        html:tmpResult,
                        value:listItems[i].id,
                        'class':'ui-tag-selector-list-item'
                      }
                    ).bind('mousedown.inputTag',
                          {object:object},
                          function (event)
                          {
                            privateMethods.addTag(event.data.object, $(this).attr('value'), $(this).text());
                          }
                      );
            objects.tagList.append(li);
          }
        },

      addTag : function (object, id, name)
        {
          var options=object.data('options'),
              properties=object.data('properties'),
              objects=object.data('objects');

          if(privateMethods.findTagById(object, id)==-1)
          {
            //add only if not already selected..
            properties.tags.push({id:id, name:name});

            var li=$('<li/>',
                      {
                        value:id,
                        html:name,
                        'class':'ui-tag-selector-selected-tag'
                      }
                    ).prepend(
                      $('<span/>',
                        {
                          html:'x'
                        }
                       ).bind('click.inputTag',
                          {object:object},
                          function (event)
                          {
                            privateMethods.removeTag(event.data.object, $(this).parent().attr('value'));
                          }
                        )
                      );
            objects.input.val('').parent().before(li);
            if(options.add) object.trigger('inputTagAdd', id);
          }
        },

      removeTag : function (object, id)
        {
          var options=object.data('options'),
              properties=object.data('properties'),
              objects=object.data('objects');

          var index=privateMethods.findTagById(object, id);
          if(index>-1)
          {
            properties.tags.splice(index,1);
            objects.selectedTagList.children('[value='+id+']').remove();

            if(options.remove) object.trigger('inputTagRemove', id);
          }
          return(index);
        },

      findTagById : function (object, value)
        {
          var properties=object.data('properties');

          for(var i=0;i<properties.tags.length;i++)
          {
            if(properties.tags[i].id==value) return(i);
          }
          return(-1);
        },

      getFocus : function (object)
        {
          privateMethods.displaySelector(object, true);
        },

      lostFocus : function (object)
        {
          privateMethods.displaySelector(object, false);
        },

      setEventPopup : function (object, value)
        {
          var options=object.data('options');

          options.popup=value;
          object.unbind('inputTagPopup');
          if(value) object.bind('inputTagPopup', options.popup);
          return(options.popup);
        },

      setEventAdd : function (object, value)
        {
          var options=object.data('options');

          options.add=value;
          object.unbind('inputTagAdd');
          if(value) object.bind('inputTagAdd', options.add);
          return(options.add);
        },

      setEventRemove : function (object, value)
        {
          var options=object.data('options');

          options.remove=value;
          object.unbind('inputTagRemove');
          if(value) object.bind('inputTagRemove', options.remove);
          return(options.remove);
        },

      setEventLoad : function (object, value)
        {
          var options=object.data('options');
          options.load=value;
          object.unbind('categorySelectorLoad');
          if(value) object.bind('inputTagLoad', options.load);
          return(options.load);
        },

      clearTimerHandle : function(object)
        {
          var properties=object.data('properties');

          if(properties.timerHandle!=null)
          {
            window.clearInterval(properties.timerHandle);
            properties.timerHandle=null;
          }
        },

      setTimerHandle : function(object)
        {
          var properties=object.data('properties'),
              options=object.data('options');

          privateMethods.clearTimerHandle(object);
          properties.timerHandle=window.setInterval(function () { privateMethods.load(object); }, options.serverCallDelay);
        },
    };


    $.fn.inputTag = function(method)
    {
      if(publicMethods[method])
      {
        return publicMethods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
      }
      else if(typeof method === 'object' || ! method)
      {
        return publicMethods.init.apply(this, arguments);
      }
      else
      {
        $.error( 'Method ' +  method + ' does not exist on jQuery.inputTag' );
      }
    } // $.fn.inputTag

  }
)(jQuery);


