// smMarkerTool - a mousedriven marker tool
// Author - Igor Szyporyn
// Owner - System & Metode A/S
// Requires - jQuery

(function($) {

  var prefix = 'markerTool',
      _methods = {

        addPrefix: function(name) {
          return name + "." + prefix;
        },
        makeSelectable    : function(el) {
          if ($.browser.msie) {
            if (el.nodeType == 1) {
              el.unselectable = false;
            }
            var child = el.firstChild;
            while (child) {
              this.makeSelectable(child);
              child = child.nextSibling;
            }
          } else {
            $(el).css({
              '-webkit-user-select'   : '',
              '-khtml-user-select'    : '',
              '-moz-user-select'      : '',
              '-ms-user-select'       : ''
            });
          }
        },
        makeUnSelectable  : function(el) {
          if ( $.browser.msie) {
            if (el.nodeType == 1) {
              el.unselectable = true;
            }
            var child = el.firstChild;
            while (child) {
              this.makeUnSelectable(child);
              child = child.nextSibling;
            }
          }
          else {
            $(el).css({
              '-webkit-user-select'   : 'none',
              '-khtml-user-select'    : 'none',
              '-moz-user-select'      : 'none',
              '-ms-user-select'       : 'none'
            })
          }
        }
      }

  var methods = {

    init: function( options ) {

      var settings =  $.extend(true, {}, {
                        design        : {
                          borderColor   : '#369',
                          borderWidth   : '1px',
                          borderStyle   : 'solid', 
                          background    : '#def',
                          opacity       : 0.5
                        },
                        modifierKey   : 'altKey',
                        beforeDraw    : $.noop,
                        onDraw        : $.noop,
                        afterDraw     : $.noop
                      }, options);

      return this.each(function() {

        var $this = $(this),
            _noop = this,
            data = $this.data(prefix);

        if (!data) {

          var marker = {
            allowMarking    : false, 
            $element        : $('<div />').css({
                                'border-width'      : settings.design.borderWidth,
                                'border-color'      : settings.design.borderColor,
                                'border-style'      : settings.design.borderStyle,
                                'background-color'  : settings.design.background,
                                'opacity'           : settings.design.opacity,
                                'position'          : 'absolute'
                              }),
            dimensions      : {},
            clicked         : {},
            handler         : {
              element     : _noop,
              type        : $this.tagName,
              position    : [],
              getPosition : function() {

                var offset = $(this.element).offset();

                return [offset.left, offset.top];

              },
              update      : function() {

                var $el = $(this.element),
                    offset = $el.offset();

                this.position[0] = offset.left;
                this.position[1] = offset.top;

                return this;

              }
            },
            getDimensions : function() {

              var $el = this.$element, 
                  offset = $el.offset();

              return {
                width    : $el.outerWidth(),
                height   : $el.outerHeight(),
                x        : offset.left,
                y        : offset.top
              }

            }, 
            setDimensions : function() {
              this.dimensions = this.getDimensions();
              return this;
            }
          }

          

          $this.bind({

            mousedown : function( event ) {

              if ( event[settings.modifierKey] ) {

                event.stopPropagation();

                settings.beforeDraw.call( this, marker, event.target );

                // Manipulate how x and y are found when attaching to an absolutely
                // positioned DOM node!
                //var toAppendTo = $('body');
                var baseCmp = $(this);

                marker.clicked = {
                  x : event.pageX,
                  y : event.pageY
                }

                marker.$element.appendTo(baseCmp).css({
                  'width'   : '0px',
                  'height'  : '0px',
                  'top'     : marker.clicked.y - baseCmp.offset().top,
                  'left'    : marker.clicked.x - baseCmp.offset().left,
                  'z-index' : 99999999
                });
                

                marker.element = marker.$element.get(0);

                marker.handler.update();

                _methods.makeUnSelectable($this.get(0));

                marker.allowMarking = true;

              }

            },
            mousemove : function( event ) {

              if (marker.allowMarking) {

                var baseCmp = $(this),
                    baseOffset = baseCmp.offset();

                var xD = event.pageX - marker.clicked.x,
                    yD = event.pageY - marker.clicked.y;

                settings.onDraw.call( $(this), marker );

                marker.$element.css({
                  'left'    : event.pageX < marker.clicked.x ? event.pageX - baseOffset.left + 'px' : marker.clicked.x - baseOffset.left + 'px',
                  'top'     : event.pageY < marker.clicked.y ? event.pageY - baseOffset.top + 'px' : marker.clicked.y - baseOffset.top + 'px',
                  'width'   : event.pageX < marker.clicked.x ? (xD * -1) + 'px' : xD + 'px',
                  'height'  : event.pageY < marker.clicked.y ? (yD * -1) + 'px' : yD + 'px'
                });
                
                marker.setDimensions();

              }
              
            },
            mouseup   : function( event ) {

              if ( !marker.allowMarking ) return false;

              marker.$element.remove();

              marker.allowMarking = false;

              _methods.makeSelectable($this.get(0));

              settings.afterDraw.call( this, marker );

            }


          })

        }

      });

    },
    destroy   : function() {
      this.unbind('mousedown').unbind('mousemove').unbind('mouseup');
      return this;
    } 
  }

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