/********
 * Lifetype.Forms namespace
 *
 * Includes all functions related to forms, form validation, lists, etc.
 ***************/

Lifetype.Forms = function() {}

Lifetype.Forms.Events = function() {}

Lifetype.Forms.List = function() {}

Lifetype.Forms.Element = function() {}

/**
 * @static
 * Removes the selected items from the list
 * @param elem The id of an HTML object
 */
Lifetype.Forms.List.removeSelected = function( elem )
{
	list = document.getElementById( elem );

	for( i = 0; i < list.options.length; i++ ) {
		if( list.options[i].selected ) {
			// the element is selected, remove it
			list.remove( i );
		}
	}
}

/**
 * @static
 * Removes al elements from a list
 * @param elem The id of an HTML object
 */
Lifetype.Forms.List.removeAll = function( elem )
{
	list = document.getElementById( elem );

	for( i = 0; i < list.options.length; i++ ) {
		list.remove( i );
	}
}

/**
 * @static
 * Selects all elements from a list
 * @param elem The id of an HTML object
 */
Lifetype.Forms.List.selectAll = function( elem )
{
	list = document.getElementById( elem );

	for( i = 0; i < list.options.length; i++ ) {
		list.options[i].selected = true;
	}
}

/**
 * @static
 * Appends an item to a list
 * @param fieldName
 * @param value
 * @param ite
 */
Lifetype.Forms.List.appendToList = function( fieldName, value, item, selectOpt )
{
	if( selectOpt == undefined )
		selectOpt = false;

	return( Lifetype.Forms.List.appendToExternalList( document, fieldName, value, item, selectOpt ));
}

/**
 * @static
 * Appends an item to a list, which may not be inside the current document (hence the
 * 'dest' parameter)
 * @param dest
 * @param fieldName
 * @param value
 * @param ite
 */
Lifetype.Forms.List.appendToExternalList = function( dest, fieldName, value, item, selectOpt )
{
	if( selectOpt == undefined )
		selectOpt = false;

	dstList = dest.getElementById( fieldName );

	// check if the element is already there
	found = false;
	j = 0;
	while( j < dstList.options.length && !found ) {
		if( dstList.options[j].text == item && dstList.options[j].value == value ) {
			// element found!
			found = true;
		}
		j++;
	}

	// add the element only if not found
	if( !found ) {
		newOpt = new Option( item, value );
		//dstList.options[dstList.options.length] = newOpt;
		newOpt.selected = selectOpt;
		try {
			dstList.add( newOpt, null ); // standards compliant; doesn't work in IE
		}
		catch( ex ) {
			dstList.add( newOpt ); // IE only
		}
	}

	return true;
}

/**
 * automatically selects all the elements of a list
 *
 * @param listId
 */
Lifetype.Forms.List.selectAll = function( listId )
{
	list = document.getElementById( listId );
	for( i = 0; i < list.options.length; i++ ) {
		list.options[i].selected = true;
	}

	return true;
}

/**
 * empties a drop-down list
 *
 * @param box The form object representing the drop-down list
 * @return nothing
 */
Lifetype.Forms.List.emptyList = function( listId )
{
	box = Lifetype.Dom.$( listId );
	while ( box.options.length ) box.options[0] = null;
}

/**
 * Checks that there is at least one element selected
 * in a list
 *
 * @param box The drop-down list
 * @return True if there is at least one element selected
 * or false otherwise
 */
Lifetype.Forms.List.atLeastOneSelected = function( listId )
{
        list = Lifetype.Dom.$( listId );
        if( list == undefined )
            return( false );

        var found = false;
        for( var i = 0; i < list.options.length; i++ ) {
             if( list.options[i].selected == true ) {
                 found = true;
                 break;
             }
        }

        return( found );
}

/**
 * Toggles all checkboxes within a form
 */
Lifetype.Forms.toggleAllChecks = function(formName, prefix)
{
    n = "all";

    if (prefix)
    {
        n = prefix + n;
    }

    i = 0;
    e = document.getElementById(n);
    s = e.checked;
    f = document.getElementById(formName);

    while (e = f.elements[i])
    {
        if (e.type == "checkbox" && e.id != n)
        {
            if (!prefix || e.id.indexOf(prefix) != -1)
            {
                e.checked = s;
            }
        }

        i++;
    }
}

/**
 * CustomEvent object fired when the form has been successfully processed
 */
Lifetype.Forms.Events.formProcessorSuccessEvent = new YAHOO.util.CustomEvent('formProcessorSuccessEvent');

/**
 * CustomEvent object fired when the form was not successfully processed
 */
Lifetype.Forms.Events.formProcessorFailureEvent = new YAHOO.util.CustomEvent('formProcessorFailureEvent');

/**
 * @static
 * Processes responses for forms submitted via Ajax
 * @param formId
 * @param postUrl
 * @param options An options object:
 *   resetAfterSuccess:boolean = reset the form after success
 *   formSuccessCallback:function = callback, function to call if the form is successful
 *   formErrorCallback:function = callback, function to call if the form is not successful
 *   formInfo:string = dom id, place to show the form validate info
 *   formInfoMessage:string = dom id, place to show the form validate info message
 *   formError:string = dom id, place to show the form validate error
 *   formErrorMessage:string = dom id, place to show the form validate error message
 */
Lifetype.Forms.AjaxFormProcessor = function( formId, postUrl, options )
{
	var formObject = document.getElementById( formId );
	YAHOO.util.Connect.setForm(formObject);

	if( options )
	{
		options.formElement = formObject;
        if ( options.formInfo ) formInfoId = options.formInfo; else formInfoId = 'FormInfo';
        if ( options.formInfoMessage ) formInfoMessageId = options.formInfoMessage; else formInfoMessageId = 'FormInfoMessage';
        if ( options.formError ) formErrorId = options.formError; else formErrorId = 'FormError';
        if ( options.formErrorMessage ) formErrorMessageId = options.formErrorMessage; else formErrorMessageId = 'FormErrorMessage';
    } else {
        formInfoId = 'FormInfo';
        formInfoMessageId = 'FormInfoMessage';
        formErrorId = 'FormError';
        formErrorMessageId = 'FormErrorMessage';
    }
	Lifetype.Effects.Form.showPanel();

	var cObj = YAHOO.util.Connect.asyncRequest('POST', postUrl,
		callback = {
			argument: options,
			success: function( o ) {
				// decode the JSon response from the server
				response = Lifetype.JSon.decode( o.responseText );
				o.response = response;

				// shorter way to access the form object
				form = response.form;

				// 'deactivate' all field messages
				elements = YAHOO.util.Dom.getElementsByClassName('fieldValidationError','div');
				for( i = 0; i < elements.length; i++ ) {
					elements[i].style.display = 'none';
				}

				// and all other messages
				document.getElementById( formInfoId ).style.display = 'none';
				document.getElementById( formErrorId ).style.display = 'none';

				// was it successful?
				if( response.success == false ) {
					// process the information from the 'form' object
					if( form != undefined ) {
						for( i = 0; i < form.fields.length; i++ ) {
							fObject = form.fields[i];
							// is the field valid?
							if( fObject.valid == false ) {
								// We've also got the name of the field that caused the error and
								// the error message that should be displayed, so we can do it right away
								if(( elem = YAHOO.util.Dom.get( "field_" + fObject.field ))) {
									elem.style.display = 'block';
									elem.innerHTML = '<span style="background:red;color:white;font-weight:bold">&nbsp;!&nbsp;</span>&nbsp;' + fObject.message;
								}
							}
							else {
								// there was no error, so we can hide the error message if there was one previously displayed
								if(( elem = YAHOO.util.Dom.get( "field_" + fObject.field ))) {
									elem.style.display = 'none';
								}
							}
						}
					}

					// display the general error message by setting it into its container
					if(( elem = YAHOO.util.Dom.get( formErrorMessageId ))) {
						elem.innerHTML = response.message;
					}
					if(( elem = YAHOO.util.Dom.get( formErrorId ))) {
						elem.style.display = 'block';
					}

					// fire the error event
					Lifetype.Forms.Events.formProcessorFailureEvent.fire( o );

                    // invoke form error callback
                    if( options && options.formErrorCallback )
                        options.formErrorCallback();
				}
				else {
					// display the general success message by setting it into its container
					// and making the block visible
					if(( elem = YAHOO.util.Dom.get( formInfoMessageId )))
						elem.innerHTML = response.message;
					if(( elem = YAHOO.util.Dom.get( formInfoId )))
						elem.style.display = 'block';

					// check if there's any argument
					if( o.argument ) {
						// do we reset the form after success
						if( o.argument.resetAfterSuccess == true ) {
							o.argument.formElement.reset();
						}
					}

					// fire the success
					Lifetype.Forms.Events.formProcessorSuccessEvent.fire( o );

                    // invoke form success callback
                    if( options && options.formSuccessCallback )
                        options.formSuccessCallback();
				}

				Lifetype.Effects.Form.hidePanel();
			},
			failure: function() {
				// fire the error event
				Lifetype.Forms.Events.formProcessorFailureEvent.fire( o );

                // invoke form success callback
                if( options && options.formSuccessCallback )
                    options.formSuccessCallback();

				Lifetype.Effects.Form.hidePanel();
			}
		}
	);
}

/**
 * CustomEvent object fired when the link has been successfully processed
 */
Lifetype.Forms.Events.performRequestSuccessEvent = new YAHOO.util.CustomEvent('performRequestSuccessEvent');

/**
 * CustomEvent object fired when the link was not successfully processed
 */
Lifetype.Forms.Events.performRequestFailureEvent = new YAHOO.util.CustomEvent('performRequestFailureEvent');

Lifetype.Forms.performUrl = function( url )
{
	var a = document.createElement( 'a' );
	a.href = url;
	a.style.display = 'none';
	document.body.appendChild( a );
	Lifetype.Forms.performRequest( a );
}

/**
 * This method can be used to execute a form or an anchor tag via XmlHttpRequest. Its output
 * is processed and placed in the page according to certain tags: ViewInfo and ViewInfoMessage for
 * successful cases and ViewError and ViewErrorMessage for error cases.
 *
 * The code is able to automatically detect whether we're dealing with an anchor tag or a
 * form tag.
 *
 * In case of successful request, the event performRequestSuccessEvent will be generated, while in case
 * of error requests, performRequestFailureEvent will be generated.
 */
Lifetype.Forms.performRequest = function( o )
{
	if( o.tagName.toLowerCase() == "form" ) {
		// it's a form
		YAHOO.util.Connect.setForm( o );
		url = '?output=json';
	}
	else {
		// it's an anchor tag
		var url = o.href + "&output=json";
	}

	Lifetype.Effects.Form.showPanel();

	YAHOO.util.Connect.asyncRequest('GET', url,
		callback = {
			success: function( o ) {

				Lifetype.Dom.$( 'ViewError' ).style.display = 'none';
				Lifetype.Dom.$( 'ViewInfo' ).style.display = 'none';

				var response = Lifetype.JSon.decode( o.responseText );

				/**
				 * Here is when easy things get annoyingly awkward...
				 * Some ajax views return their succes status in the 'success'
				 * field and the error message in the 'message' field of the json
				 * response. So far, so good.
				 *
				 * But there are other views that need to return both a success
				 * and an error message: think of an operation to delete more than
				 * one item at the same time, where some of the items may be successfully
				 * deleted but other may not be. In those cases, 'result' is always
				 * set to 'true' and the error message and the success message are
				 * packed into the 'message' variable as 'message.successMessage' and
				 * 'message.errorMessage' so we have to take these combinations into
				 * account.
				 */
				if( response.success == false ) {
					// this is used for validation errors, where we have a form object
					// containin the incorrect fields and a 'message' field containing
					// the validation error string
					Lifetype.Dom.$( 'ViewErrorMessage' ).innerHTML = response.message;
					Lifetype.Dom.$( 'ViewError' ).style.display = 'block';

					// fire the error event
					Lifetype.Forms.Events.performRequestFailureEvent.fire( o );
				}
				else {
					if( response.message["successMessage"] || response.message["errorMessage"] ) {
						if( response.message.successMessage ) {
							Lifetype.Dom.$( 'ViewInfoMessage' ).innerHTML = response.message.successMessage;
							Lifetype.Dom.$( 'ViewInfo' ).style.display = 'block';

							// fire the success event
							Lifetype.Forms.Events.performRequestSuccessEvent.fire( o );
						}
						if( response.message.errorMessage ) {
							Lifetype.Dom.$( 'ViewErrorMessage' ).innerHTML = response.message.errorMessage;
							Lifetype.Dom.$( 'ViewError' ).style.display = 'block';

							// fire the error event
							Lifetype.Forms.Events.performRequestFailureEvent.fire( o );
						}
					}
					else {
						Lifetype.Dom.$( 'ViewInfoMessage' ).innerHTML = response.message;
						Lifetype.Dom.$( 'ViewInfo' ).style.display = 'block';

						// fire the success event
						Lifetype.Forms.Events.performRequestSuccessEvent.fire( o );
					}
				}
				Lifetype.Effects.Form.hidePanel();
			},
			failure: function( o ) {
				Lifetype.Dom.$( 'ViewErrorMessage' ).innerHTML = 'Error performing request';
				Lifetype.Dom.$( 'ViewError' ).style.display = 'block';

				// fire the error event
				Lifetype.Forms.Events.performRequestFailureEvent.fire( o );
				Lifetype.Effects.Form.hidePanel();
			}
		}
	);
}

//
// :TODO:
// Move the functions above to the Lifetype.Forms.List namespace
//

//
// counter to keep track of how many elements we have!
//
var numFields = 2;
var debug = false;

function hideElement(elem)
{
 elem.type = 'hidden';
}

function showElement(elem)
{
 elem.type = 'file';
}
function toggleElement(elem)
{
 if( elem.type == 'hidden')
   showElement(elem);
 else
   hideElement(elem);
}

function addElementToForm (containerName, fieldType, fieldName, fieldValue)
{
var separator = document.getElementById('marker');
var container = document.getElementById(containerName);
if (navigator.userAgent.indexOf("MSIE") != -1){//isie
var fileTag ="<input type='"+fieldType+"' value='' name='"+fieldName+"_"+numFields+"'>";
var fileObj = document.createElement(fileTag);
var newLine = document.createElement('BR');
container.insertBefore(fileObj,separator);
container.insertBefore(newLine,separator);
numFields++;
}//endie
  else
	{//notie
	  if (document.getElementById) {
    var input = document.createElement('INPUT');
    var newLine = document.createElement('BR');
    var newFieldName = fieldName + '_' + numFields;
    if( debug) window.alert('adding field ' + newFieldName);
      if (document.all) {
        input.type = fieldType;
        input.name = newFieldName;
        input.value = fieldValue;
      }
      else if (document.getElementById) {
        input.setAttribute('type', fieldType);
        input.setAttribute('name', newFieldName);
        input.setAttribute('value', fieldValue);
      }

    container.insertBefore(input,separator);
    container.insertBefore(newLine,separator);
    numFields++;
  }
	}//endnotie
}

function getField (form, fieldName) {
  if (!document.all)
    return form[fieldName];
  else  // IE has a bug not adding dynamically created field
        // as named properties so we loop through the elements array
    for (var e = 0; e < form.elements.length; e++)
      if (form.elements[e].name == fieldName)
        return form.elements[e];
  return null;
}

function removeField (form, fieldName) {
  var field = getField (form, fieldName);
  if (field && !field.length)
    field.parentNode.removeChild(field);
}

function toggleField (form, fieldName, value) {
  var field = getField (form, fieldName);
  if (field)
    removeField (form, fieldName);
  else
    addField (form, 'hidden', fieldName, value);
}

/**
 * sets a field in the given document (like 'document' or 'parent.opener.document')
 * This function is useful to set a field regardless of in which form it is located
 */
function setDocumentField(dest, fieldName, value )
{
	element = dest.getElementById( fieldName );
	element.value = value;
}

