(function ($) {
   /*----------------------------------------------------------------------------------
   Class: FloatObject
   -------------------------------------------------------------------------------------*/
   function FloatObject(jqObj, params) {
      this.jqObj = jqObj;

      switch (params.speed) {
         case 'fast': this.steps = 5; break;
         case 'normal': this.steps = 10; break;
         case 'slow': this.steps = 20; break;
         default: this.steps = 10;
      };

      var offset = this.jqObj.offset();

      this.currentY = offset.top;
      this.width = this.jqObj.width();
      this.height = this.jqObj.height();
      this.alwaysVisible = params.alwaysVisible;
      this.alwaysTop = params.alwaysTop;
      this.scrollMax = this.jqObj.parent().height() - this.height - params.footerHeight;
      this.headerHeight = params.headerHeight;
      

      this.origY = this.currentY + params.headerHeight; 

      //inicializamos
      this.jqObj.css({ 'position': 'relative', 'top': params.headerHeight });
   }

   FloatObject.prototype.updateLocation = function () {

      if (this.alwaysTop == false) {
         this.updatedY = $(window).scrollTop() + this.origY;

         if (this.alwaysVisible) {
            if (this.origY + this.height > this.windowHeight()) {
               this.updatedY = $(window).scrollTop() + this.windowHeight() - this.height;
               if (this.updatedY < this.origY) this.updatedY = this.origY;
            }
         }
      }
      else {

         if ($(window).scrollTop() > this.origY) {
            this.updatedY = Math.min(Math.abs($(window).scrollTop() - this.origY + this.headerHeight) + 5, this.scrollMax);
         }
         else {

            this.updatedY = this.headerHeight; 
         }
      }
      this.dy = Math.abs(this.updatedY - this.currentY);

      return this.dy;
   }

   FloatObject.prototype.windowHeight = function () {
      var de = document.documentElement;

      return self.innerHeight ||
            (de && de.clientHeight) ||
            document.body.clientHeight;
   }

   FloatObject.prototype.windowWidth = function () {
      var de = document.documentElement;

      return self.innerWidth ||
            (de && de.clientWidth) ||
            document.body.clientWidth;
   }


   FloatObject.prototype.move = function () {
      if (this.jqObj.css("position") != "relative") return;
      var cy = 0;

      if (this.dy > 0) {
         if (this.dy < this.steps / 2)
            cy = (this.dy >= 1) ? 1 : 0;
         else
            cy = Math.round(this.dy / this.steps);

         if (this.currentY < this.updatedY)
            this.currentY += cy;
         else
            this.currentY -= cy;
      }

      this.jqObj.css({ 'top': this.currentY });
   }



   /*----------------------------------------------------------------------------------
   Object: floatMgr
   -------------------------------------------------------------------------------------*/
   $.floatMgr = {

      FOArray: new Array(),

      timer: null,

      initializeFO: function (jqObj, params) {
         var settings = $.extend({
            y: 0,
            speed: 'normal',
            alwaysVisible: false,
            alwaysTop: true,
            headerHeight: 0 /*Alto del header*/,
            footerHeight: 0 /*Alto del footer*/
         }, params || {});
         var newFO = new FloatObject(jqObj, settings);

         $.floatMgr.FOArray.push(newFO);

         if (!$.floatMgr.timer) $.floatMgr.adjustFO();

         //now making sure we are registered to all required window events
         if (!$.floatMgr.registeredEvents) {
            $(window).bind("resize", $.floatMgr.onChange);
            $(window).bind("scroll", $.floatMgr.onChange);
            $.floatMgr.registeredEvents = true;
         }
      },

      adjustFO: function () {
         $.floatMgr.timer = null;

         var moveFO = false;

         for (var i = 0; i < $.floatMgr.FOArray.length; i++) {
            FO = $.floatMgr.FOArray[i];
            if (FO.updateLocation()) moveFO = true;
         }

         if (moveFO) {
            for (var i = 0; i < $.floatMgr.FOArray.length; i++) {
               FO = $.floatMgr.FOArray[i];
               FO.move();
            }

            if (!$.floatMgr.timer) $.floatMgr.timer = setTimeout($.floatMgr.adjustFO, 50);
         }
      },

      stopFloatChk: false,

      onChange: function () {
         if (!$.floatMgr.timer && !$.floatMgr.stopFloatChk) $.floatMgr.adjustFO();
      }
   };

   /*----------------------------------------------------------------------------------
   Function: makeFloat
   -------------------------------------------------------------------------------------*/
   $.fn.makeFloat = function (params) {
      var obj = this.eq(0); //we only operate on the first selected object;
      $.floatMgr.initializeFO(obj, params);
      if ($.floatMgr.timer == null) $.floatMgr.adjustFO();
      return obj;
   };
   $.fn.stopFloat = function (params) {
      $.floatMgr.stopFloatChk = true;
   };

   $.fn.restartFloat = function (params) {
      $.floatMgr.stopFloatChk = false;
   };
})(jQuery);
