jQuery( document ).ready( function( ){
 
 // For all the inputs that are text inputs
 jQuery( 'input:text' ).each( function( ){
  var $this = jQuery( this );
  
  // get the label
  var label = jQuery( 'label[for='+this.id+']' );
  
  // If no label, then return to avoid errors
  if( label.size( ) == 0 ){
   return;
  }
  
  // create wrapper element
  var wrapper = jQuery( '<div class="compactlabel-wrapper"></div>' );
  $this.wrap( wrapper );
  
  // move the label to before the the input
  $this.before( label );
  
  // create label backing
  var backing = jQuery( '<div class="compactlabel-label-backing"></div>' )
   .insertBefore( $this )
   .height( label.height( ) )
   .width( label.width( ) );
  
  // basic style information
  var labelOffset = label.position( ), inputOffset = $this.position( ), labelHeight = label.outerHeight( );
  
  // flag for if on or off
  var isHover = false, isFocus = false;
  
  // a jQuery object of the backing and label to animate both together
  var animatedElements = jQuery( backing.get( ) ).add( label.get( ) );
  
  
  // common functionality for hover on and focus on
  var on = function( event ){
   $this.parent( ).addClass( 'compactlabel-wrapper-on' );
   animatedElements.stop( ).animate( { "top": '-'+(labelHeight - inputOffset.top)+'px' } );
   
  };
  
  // common functionality for hover off and focus off
  var off = function( event ){
   if( isHover || isFocus ){
    return;
   }
   if( inputEmpty ){
    label.removeClass( 'compactlabel-hide' );
   } else {
    label.addClass( 'compactlabel-hide' );
   }
   
   if( !inputEmptyChange ){
    animatedElements.stop( );
   }
   
   animatedElements.animate( 
    { "top": labelOffset.top + 'px' }, 
    function( ){ 
     $this.parent( ).removeClass( 'compactlabel-wrapper-on' ) 
    } );
  };
  
  var onHover = function( event ){
   isHover = true;
   on( event );
  };
  
  var offHover = function( event ){
   isHover = false;
   off( event );
  };
  
  var onFocus = function( event ){
   isFocus = true;
   on( event );
  };
  
  var offFocus = function( event ){
   isFocus = false;
   off( event );
  };
  
  // The pieces for keeping track if the value of the input is empty
  var inputEmpty = false, inputEmptyStart = false, inputEmptyChange = false;
  var checkInputEmpty = function( ){
   inputEmpty = $this.val( ) == '';
  };
  checkInputEmpty( );
  // ID for setTimeout for checkInputEmpty
  var checkInputEmptyFnID = null;
  
  
  
  if( !inputEmpty ){
   label.addClass( 'compactlabel-hide' );
  }
  
  // add the events
  // events to track if the value changed empty state 
  $this.focus( function( ){
   inputEmptyStart = inputEmpty;
   inputEmptyChange = false;
   checkInputEmptyFnID = setInterval( checkInputEmpty, 50 );
  } );
  
  $this.blur( function( ){
   clearInterval( checkInputEmptyFnID );
   checkInputEmpty( );
   inputEmptyChange = inputEmptyStart != inputEmpty;
  } );
  
  // animation events
  $this.focus( onFocus );
  $this.blur( offFocus );
  $this.hover( onHover, offHover );
  label.hover( onHover, offHover );
  
 } );
} );

