/**
 * field plugin
 *
 * different behaviors depending on the type of field
 */
(function($){
	$.fn.field = function(){
		return this.each( function(){

			// "this" is the html element
			// create a custom property of this element and attach info to it
			var self			= this;
			self.required		= $(self).is('.required');

			//------------------------------------------
			// internal functions
			//------------------------------------------

			// show/hide more
			self.more = function(evt){
				// hide other .more's inside fields of the same name
				var nm = $(evt.target).attr('name');
				var fieldset = $(evt.target).parents('fieldset:eq(0)');
				$('input[name=' + nm + ']',fieldset).each( function(){
					$(this).parents('li:eq(0)').find('> .more').slideUp();
				});
				// now determine if we have a .more to show
				if( $('> .more',self)[0] ){
					// determine whether to show or hide the .more -- don't use toggle
					var show = $(evt.target).is(':checked') ? true : false;
					// if we're inside a .more, don't hide the .more
					if( !show && $(this).parents('.more:eq(0)')[0] ){
						show = true;
					}
					if( show ){
						$('> .more',self).slideDown();
					}else{
						$('> .more',self).slideUp();
					}
				}
			}

			// handle sub values
			self.sub = function( index ){
				// default index
				index = index || 0;
				// save a reference to sub-values
				var sub = $('> .sub-values',self);
				// slide the sub-values up
				if( sub.is(':visible') ){
					sub.slideUp();
				}
				// hide all the .sub-values > div
				$('> div',sub).hide();
				// if there's nothing in the div of the correct index, hide everything again
				if( $('> div:eq(' + (index - 1) + ')',sub).text().length == 0 ){
					sub.slideUp();
					return false;
				}
				// show the div of the correct index
				$('> div:eq(' + (index - 1) + ')',sub).show();
				sub.slideDown();
			}

			// deal with status flags
			self.missing = function(){
				$(self)
					.addClass('missing')
					.removeClass('knockout')
					.removeClass('invalid')
					.removeClass('ok');
				$('.error',self).slideDown();
			}
			self.invalid = function(){
				// grab the pending element
				var pending = $('.server-pending',self);
				// done is a function that resets classes and hides pending
				var done = function(){
					$(self)
						.addClass('invalid')
						.removeClass('knockout')
						.removeClass('missing')
						.removeClass('ok');
					pending.hide();
					$('.error',self).slideDown();
				}
				// if we have a pending, set up a timeout
				if( pending[0] ){
					pending.show();
					setTimeout( done, 1000 );
				}else{
					// call done directly
					done();
				}
			}
			self.knockout = function(){
				// grab the pending element
				var pending = $('.server-pending',self);
				// done is a function that resets classes and hides pending
				var done = function(){
					$(self)
						.addClass('knockout')
						.removeClass('invalid')
						.removeClass('missing')
						.removeClass('ok');
					pending.hide();
					$('.error',self).slideDown();
					// set the page error
					$('form > .error').slideDown();
				}
				// if we have a pending, set up a timeout
				if( pending[0] ){
					pending.show();
					setTimeout( done, 1000 );
				}else{
					// call done directly
					done();
				}
			}
			self.ok = function(){
				// grab the pending element
				var pending = $('.server-pending',self);
				// done is a function that resets classes and hides pending
				var done = function(){
					$(self)
						.addClass('ok')
						.removeClass('knockout')
						.removeClass('missing')
						.removeClass('invalid');
					pending.hide();
					$('.error',self).slideUp();
					// set the page error
					$('form > .error').slideUp();
				}
				// if we have a pending, set up a timeout
				if( pending[0] ){
					pending.show();
					setTimeout( done, 1000 );
				}else{
					// call done directly
					done();
					// and remove "ok", since "ok" means server-side validation
					$(self).removeClass('ok');
				}
			}

			// if we've changed, deal with the various class names possible at the field level
			self.resetflags = function(){
				$(self)
					.removeClass('ok')
					.removeClass('invalid')
					.removeClass('missing')
					.removeClass('prefilled');
				$('.error',self).slideUp();
			}

			// if there's a checkbox or a radio button and a .more element ...
			if( $(self).is('.checkbox') || $(self).is('.radio') ){
				$(':checkbox,:radio',self).bind( 'click', [this], self.more );
			}

			// if we have sub values, handle the various trigger types
			// all we have to do is determine the index of the selection and call self.sub
			if( $('> .sub-values',self)[0] ){

				// pulldowns
				$('select',self).change( function(){
					self.sub( $(this).get(0).selectedIndex );
				});

				// radios
				$(':radio',self).click( function(){
					// get the index
					var index = $(':radio[name=' + $(this).attr('name') + ']').index( this );
					// call sub
					self.sub( (index + 1) );
				});
			}

			// the instant the value changes in a text field, reset flags
			$('input',self).focus( function(){
				$(this).keyup( function(e){
					var k = e.keyCode;
					var ignore=(k < 16 || (k > 16 && k < 32 ) || (k > 32 && k < 41));
					if( !ignore ){
						self.resetflags();
						$(this).unbind('keyup');
					}
				});
			});

			//------------------------------------------
			// run on load
			//------------------------------------------

			// add the help icon, and populate the @title with @alt from the main field
			if( $(self).attr('alt') && $('span.help',self).length == 0 ){
				$(self).append('<span class="help" title="' + $(self).attr('alt') + '"></span>');
			}

			// if we have a date field, run datepicker on it
			if( $(self).is('.date') && $.datepicker ){
				$('input',self).datepicker();
			}

			// if a checkbox or radio button is already checked and it has a .more, show the .more
			if( $(':checkbox,:radio',self).is(':checked') && $('.more',self)[0] ){
				$('.more',self).slideDown();
			}

			// expose status flag events
			$(self).bind( 'invalid', self.invalid );
			$(self).bind( 'missing', self.missing );
			$(self).bind( 'knockout', self.knockout );
			$(self).bind( 'ok', self.ok );

			// if the field is manually marked, run the appropriate function
			if( $(self).is('.missing') ){
				self.missing();
			}
			if( $(self).is('.invalid') ){
				self.invalid();
			}
			if( $(self).is('.knockout') ){
				self.knockout();
			}
			if( $(self).is('.ok') ){
				self.ok();
			}

		});
	};
})(jQuery);
