jQuery.fn.customswitch = function(callback){
  return this.each(function(){
    var _hold = $(this);
    var _handle = $(this).find('.handle');
    var _body = $('body');
    var _currentValue = _hold.hasClass('true');
    var _dragging = false;
    var _dragX = 0;
    var _startLeft = 0;
    var _timeout = null;
    var _timer = true;
    
    var _toggle = function(newValue) {
      if(typeof(newValue) === 'undefined')
      {
        newValue = !_currentValue;
      }
      if(newValue)
      {
        _handle.animate(
          { left: _hold.outerWidth() - _handle.outerWidth() }, 
          100, 
          function(){ _hold.addClass('true'); }
        );
      }
      else
      {
        _handle.animate(
          { left: 0 }, 
          100, 
          function(){ _hold.removeClass('true'); }
        );
      }
      if(newValue != _currentValue && callback)
      {
        callback(newValue);
      }
      _currentValue = newValue;
    };
    
    _hold.bind('toggle', function(){ _toggle(); });
    
    _handle.click(function(e){
      if(_timer && Math.abs(_startLeft - _handle.position().left) < 10)
      {
        _dragging = false;
        _toggle(!_currentValue);
      }
    });
    
    _handle.mousedown(function(e){
      _timeout = setTimeout(function(){
        _timer = false;
      }, 150);
      _dragging = true;
      _dragX = e.pageX;
      _startLeft = _handle.position().left;
      return false;
    });
    
    _handle.mousemove(function(e){
      if(_dragging)
      {
        var dx = e.pageX - _dragX;
        _dragX = e.pageX;
        if(_handle.position().left + dx < 0)
        {
          _handle.css('left', 0);
        }
        else if (_handle.position().left + _handle.outerWidth() + dx > _hold.outerWidth())
        {
          _handle.css('left', _hold.outerWidth() - _handle.outerWidth());
        }
        else
        {
          _handle.css('left', _handle.position().left + dx);
        }
      }
    });
    _body.mouseup(function(e){
      if(_dragging)
      {
        _timer = true;
        var handleCenter = _handle.outerWidth() / 2;
        var holdCenter = _hold.outerWidth() / 2;
        var newValue = false;
        if(handleCenter + _handle.position().left > holdCenter)
        {
          newValue = true;
        }
        _toggle(newValue);
        // we need this to be false after mouseup event propogates
        setTimeout(function(){ _dragging = false; }, 5);
      }
    });
  });
}
