/**
 * -----------------------------------------------------------------------------
 * file: ui.inputDotArea.js
 * file version: 1.0.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/11/04 | first release
 * |         |            |
 * | 1.0.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 =
                    {
                      range:
                        {
                          x:[0,100],
                          y:[0,100]
                        },
                      width:0,
                      height:0,
                      disabled:false,
                      change: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,
                    values:
                      {
                        x:50,
                        y:50
                      },
                    isValid:true,
                    mouseIsDown:false
                  }
                );
                properties=$this.data('properties');
              }

              if(!objects)
              {
                objects =
                  {
                    container:$('<div/>',
                        {
                          'class':'ui-inputDotArea',
                          css:{
                            width:'100%',
                            height:'100%'
                          }
                        }
                    )
                    .bind('mousedown.inputDotArea',
                        function (event)
                        {
                          privateMethods.mouseDown($this, event);
                        }
                      )
                     .bind('mouseup.inputDotArea',
                       function (event)
                       {
                         privateMethods.mouseUp($this, event);
                       }
                     )
                     .bind('mousemove.inputDotArea',
                        function (event)
                        {
                          privateMethods.mouseMove($this, event);
                        }
                      ),
                    dot:$('<div/>',
                      {
                        'class':'ui-inputDotArea-dot'
                      }
                    )

                  };

                $this
                  .html('')
                  .append(objects.container.append(objects.dot));

                $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.dot.remove();
              objects.container.unbind().remove();
              $this
                .unbind('.inputDotArea')
                .removeData()
                .css(
                  {
                    width:'',
                    height:''
                  }
                );
              delete $this;
            }
          );
        }, // destroy

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

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

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

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

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

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

      values: function (value)
        {
          if(value!=null)
          {
            // set selected value
            return(
              this.each(
                function()
                {
                  privateMethods.setValues($(this), value, true);
                }
              )
            );
          }
          else
          {
            // return the selected tags
            var properties=this.data('properties');
            return(properties.values);
          }
        }, // 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

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

            if(options)
            {
              return(options.change);
            }
            else
            {
              return(null);
            }
          }
        } // change

    }; // 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.setWidth(object, (value.width!=null)?value.width:options.width);
          privateMethods.setHeight(object, (value.height!=null)?value.height:options.height);
          privateMethods.setRange(object, (value.range!=null)?value.range:options.range);
          privateMethods.setValues(object, (value.values!=null)?value.values:properties.values, true);

          privateMethods.setEventChange(object, (value.change!=null)?value.change:options.change);

          properties.initialized=true;
        },

      setIsValid : function (object, value)
        {
          var objects=object.data('objects'),
              properties=object.data('properties');
/*
          if(properties.isValid!=value && properties.initialized)
          {
            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);
        },


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

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

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

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

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

          if((!properties.initialized || options.disabled!=value) && (value==true || value==false))
          {
            options.disabled=value;
            objects.input.attr('disabled', options.disabled);
          }
          return(options.disabled);
        },


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

          if(value.x==false || ($.isArray(value.x) && value.x[0]<=value.x[1]))
          {
            options.range.x=value.x;
          }

          if(value.y==false || ($.isArray(value.y) && value.y[0]<=value.y[1]))
          {
            options.range.y=value.y;
          }

          return(options.range);
        }, //setValue


      setValues : function (object, value, apply)
        {
          var options=object.data('options'),
              properties=object.data('properties'),
              objects=object.data('objects'),
              tmp={x:'', y:''};

          if(!(
               (value.x==null || (value.x!=null && options.range.x[0]<=value.x && value.x<=options.range.x[1])) &&
               (value.y==null || (value.y!=null && options.range.y[0]<=value.y && value.y<=options.range.y[1])) &&
               !(value.x==null && value.y==null)
              )
            )
          {
            return(false);
          }

          if(value.x!=null) properties.values.x=value.x;
          if(value.y!=null) properties.values.y=value.y;

          if(apply)
          {
            if(options.range.x==false)
            {
              tmp.x=options.width/2;
            }
            else
            {
              tmp.x=properties.values.x*options.width/(options.range.x[1]-options.range.x[0])+options.range.x[0];
            }
            tmp.x-=6;

            if(options.range.y==false)
            {
              tmp.y=options.height/2;
            }
            else
            {
              tmp.y=properties.values.y*options.height/(options.range.y[1]-options.range.y[0])+options.range.y[0];
            }
            tmp.y-=6;

            objects.dot.css(
              {
                top:tmp.y+'px',
                left:tmp.x+'px'
              }
            );
          }

          if(options.change) object.trigger('inputDotAreaChange', properties.values);

          return(true);
        }, //setValue

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

          options.change=value;
          object.unbind('inputDotAreaChange');
          if(value) object.bind('inputDotAreaChange', options.change);
          return(options.change);
        },

      mouseDown : function (object, event)
        {
          var properties=object.data('properties');

          properties.mouseIsDown=true;
          privateMethods.mouseMove(object, event);
        },

      mouseUp : function (object, event)
        {
          var properties=object.data('properties');

          properties.mouseIsDown=false;
        },

      mouseMove : function (object, event)
        {
          var properties=object.data('properties'),
              objects=object.data('objects'),
              options=object.data('options'),
              values={};

          if(properties.mouseIsDown)
          {
            event.layerX=event.pageX-objects.container.offset().left;
            event.layerY=event.pageY-objects.container.offset().top;

            if(options.range.x!=false)
            {
              values.x=options.range.x[0]+event.layerX*(options.range.x[1]-options.range.x[0])/options.width;
            }
            if(options.range.y!=false)
            {
              values.y=options.range.y[0]+event.layerY*(options.range.y[1]-options.range.y[0])/options.height;
            }

            privateMethods.setValues(object, values, true);
          }
        }


    };


    $.fn.inputDotArea = 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.inputDotArea' );
      }
    } // $.fn.inputDotArea

  }
)(jQuery);


