/**
*	@desc 		Collection of functions that support the form framework
*	@author		Tom Hogewind & Michael Clerx
*	@version	1.3
*/
var info = {};
var formInfo = {};
var fieldsetInfo = {};
var lang = 'nl';

var error = false;
var checked = false;

/**
 * Removes all errors from a field
 * @param	String	The id of the field
 */
function removeErrors(id)
{
	var dd = getContainer(id);
    //$('img.form-error',dd).remove();
    dd.removeClass('form-error');
    if(dd.attr('nodeName') == 'DD')
    {
    	dd.prev().removeClass('form-error');
    }

    var fieldsetId = getFieldsetId(id);
    var errorUL = $('#' + fieldsetId + '-errors');
    if(errorUL.size() == 0)
        return;

    $('li',errorUL).each(function()
    {
        if($(this).attr('id').substr(0,id.length) == id)
            $(this).addClass('solved');
    });
    var allSolved = true;
    $('li',errorUL).each(function()
    {
        if(!$(this).hasClass('solved'))
            allSolved = false;
    });
    if(allSolved)
    {
        errorUL.removeClass('negative');
        errorUL.addClass('positive');
    }

}

/**
 * Adds an error to a field
 * @param	String	The id of the field
 * @param   String  The id of the error (simply the number of the check that is performed)
 * @param   String  The error message (optional)
 */
function addError(id, errorId, msg)
{
    if(!msg)
        msg = '';
    error = true;
    var dd = getContainer(id);
    dd.addClass('form-error');

    /*
    if($('img.form-error',dd).size() == 0 || msg.length > 0)
    {
        $('img.form-error',dd).remove();
        dd.append('<img src="' + SITE_ROOT + 'img/icons/error.png" title="' + msg + '" alt="" class="form-error" />');
    }
    */
    if(dd.attr('nodeName') == 'DD')
    {
    	dd.prev().addClass('form-error');
    }

    // Add a notice to the fieldset
    if(msg != '')
    {
        var fieldsetId = getFieldsetId(id);
        var errorUL = $('#' + fieldsetId + '-errors');
        if(errorUL.size() == 0)
        {
            $('#' + fieldsetId).prepend('<ul id="' + fieldsetId + '-errors" class="notice negative"></ul>');
            errorUL = $('#' + fieldsetId + '-errors');
        }
        if($('#' + id + '__error-' + errorId,errorUL).size() > 0)
        {
            $('#' + id + '__error-' + errorId,errorUL).removeClass('solved');
        } else
        {
            // Check if there is an error with the same message
            var found = false;
            $('li',errorUL).each(function()
            {
                if($(this).attr('id').substr(0,id.length) == id && !found)
                {
                    if($(this).html() == msg)
                    {
                        $(this).removeClass('solved');
                        found = true;
                    }
                }
            });
            if(!found)
                errorUL.append('<li id="' + id + '__error-' + errorId +'" class="error">' + msg + '</li>');
        }
        //$('#' + id + '__error-' + errorId,errorUL).remove(); // Just to be sure that no duplicate errors appear

        errorUL.removeClass('positive');
        errorUL.addClass('negative');
    }


}

/**
 * Gets the id of the fieldset which contains the field with the given id
 * @param   String  The id of the field
 * @param   String  The id of the fieldset
 */
function getFieldsetId(fieldId)
{
    result = false;
    $.each(formInfo, function(index, value)
    {
        var sets = value.children;
        for(var x = 0; x < sets.length; x++)
        {
            var fields = fieldsetInfo[sets[x]].children;
            for(var y = 0; y < fields.length; y++)
            {
                //alert(fields[y] + '==' + fieldId + '=>' + sets[x]);
                if(fields[y] == fieldId)
                {
                    result = sets[x];
                    return;
                }
            }
        }
    });
    return result;
}

/**
 * Shows a field
 * @param	String	The id of the field
 */
function show(id)
{
    var dd = $('#' + id);
    while(dd.attr('nodeName') != 'DD' && dd.length != 0)
        dd = dd.parent();
    var dt = dd.prev();

    //dd.slideDown(300);
    //dt.slideDown(300);
    dd.removeClass('hide');
    dt.removeClass('hide');
	dd.show();
	dt.show();

    var i = info[id];
    i.active = true;

    // TODO: update for other fields as well
    $('#' + id + ' input[type=radio]:checked, #' + id + ' select').trigger('click');
    $('#' + id + ' input[type=text], #' + id + ' textarea').trigger('keyup');
}

/**
 * Hides a field
 * @param	String	The id of the field
 */
function hide(id)
{
    var dd = $('#' + id);
    while(dd.attr('nodeName') != 'DD' && dd.length != 0)
        dd = dd.parent();
    var dt = dd.prev();

    //dt.slideUp(300);
    //dd.slideUp(300);
    dt.hide();
    dd.hide();

    var i = info[id];
    i.active = false;
    for(var x = 0; x < i.children.length; x++)
    {
        hide(i.children[x]);
    }
}

/**
 * Tests if an array contains a given object
 * @param	array	The array
 * @param	object	The object that will be tested
 * @returns	boolean
 */
function contains(a, obj)
{
    var i = a.length;
    while (i--) if (a[i] === obj) return true;
    return false;
}

// Takes an array a of HtmlInputElements and checks if there value
//  equals obj
function containsWithValue(a, obj)
{
    var i = a.length;
    while (i--) if (a[i].value === obj) return true;
    return false;
}

/**
 * Very simple email check, coded to be permissive
 * @param	String	The string that will be checked
 * @returns	boolean
 */
function isEmail(str)
{
    str = jQuery.trim(str);
    parts = str.split('@');
    if (parts.length != 2) return false;
    if (parts[0].length < 1) return false;
    parts = parts[1].split('.');
    i = parts.length;
    if (i < 2) return false;
    while(i--) if (parts[i].length < 1) return false;
    return true;
}

// Takes an array of checkboxes and returns the name of each value
//  that's been checked. Id must include hash mark.
function checkToString(id)
{
    boxes = $(id+' input:checked');
    values = new Array();
    boxes.each(function(i) { values.push(this.value); });
    return values.join(", ");
}

/**
 * Toggles a field or fieldset
 * @param	String	The id of the field or fieldset
 */
function toggle(id)
{
    var e = $('#' +id);
    if(e.attr('nodeName') == 'FORM')
    {
    	var children = formInfo[id].children;
    	for(var i = 0; i < children.length; i++)
    	{
    		toggle(children[i]);
    	}
    	$('.edit-button', e).toggleClass('hide');
    	$('.submit-button', e).toggleClass('hide');
    } else if(e.attr('nodeName') == 'FIELDSET')
    {
    	$('dd',e).each(function()
    	{
    		$('.current-value',$(this)).toggleClass('hide');
    		$('.edit-value',$(this)).toggleClass('hide');
    	});
    } else
    {
    /*
    	var dd = e;
        while(dd.attr('nodeName') != 'DD' && dd.length != 0)
            dd = dd.parent(); */
        var dd = getContainer(id);
        $('.current-value',dd).toggleClass('hide');
        $('.edit-value',dd).toggleClass('hide');
    }
}

/**
 * Posts the value of a field to the server with an ajax-request
 * @param	String		The id of the field
 * @param	String		The name of the module that will process the request
 * @param	String		The function that will process the request
 */
function post(id, module, func)
{
    if(!module)
        module = CURRENT_MODULE;
    if(!func)
        func = CURRENT_FUNCTION;
    var vars = new Object();
    vars.__dynamic = 'true';
    var e = $('#' +id);
    var children, fields, i;

    if(e.attr('nodeName') == 'FORM')
    {
    	// TODO: FIX AJAX POST REQUEST FOR FILES -> then make it a ajax call
    	e.submit();

    	/*
    	children = formInfo[id].children;
    	for(var i = 0; i < children.length; i++)
    	{
    		fields = fieldsetInfo[children[i]];
    		for(var j = 0; j < fields.length; j++)
    		{
    			i = info[id];
    			for(var x = 0; x < i.keys.length; x++)
    			{
    				eval('vars.' + i.keys[x] + ' = ' + i.values[x]);
    			}
    		}
		}*/
    }
    if(e.attr('nodeName') == 'FIELDSET')
    {
    	$('dd',e).each(function()
    	{

		});
    } else
    {
    	var i = info[id];
    	var keys = i.keys;
    	var values = i.values;
    	for(var x = 0; x < keys.length; x++)
    	{
    		eval('vars.' + keys[x] + ' = ' + values[x]);
    	}
    }
    ajaxModule(module,func,vars);
}

/**
 * Checks a field, fieldset or form for input errors
 * @param	String		The id of the field, fieldset or form
 * @returns	boolean
 */
function check(id)
{
    var result = true;
    if($('#' + id).attr('nodeName') == 'FORM')
    {
    	var children = formInfo[id].children;
    	for(var i = 0; i < children.length; i++)
    	{
    		if(!check(children[i]))
    			result = false;
    	}
    } else if($('#' + id).attr('nodeName') == 'FIELDSET')
    {
    	var children = fieldsetInfo[id].children;
    	for(var i = 0; i < children.length; i++)
    	{
    		if(!check(children[i]))
    			result = false;
    	}
    } else
    {
		var i = info[id];
		if(i.optional)
			return true;
		if(!i.checked)
		    bindErrorListeners(id);
		if(!i.active)
			return true;
		var checks = i.checks;
		var errors = i.errors;

		var result = true;
        removeErrors(id);
		for(var x = 0; x < checks.length; x++)
		{
    		eval('if(' + checks[x] + '){addError(\'' + id + '\',' + x + ',\'' + errors[x] + '\');result = false;}');
		}
        return result;
    }
    return result;
}

/**
 * Binds listeners to fields that will check for input errors on the fly
 * @param	String		The id of the field
 */
function bindErrorListeners(id)
{
    if(formInfo[id])
    {
        var sets = formInfo[id].children;
        for(var x = 0; x < sets.length; x++)
        {
            var fields = fieldsetInfo[sets[x]].children;
            for(var y = 0; y < fields.length; y++)
            {
                bindErrorListeners(fields[y]);
            }
        }
        return;
    }
	var i = info[id];
	var selectors = i.updateSelectors;
	var events = i.updateEvents;

	for(var x = 0; x < selectors.length; x++)
	{
		$(selectors[x]).bind(events[x], function(){check(id)});
	}
	i.checked = true;
}

/**
 * Bind listeners to fields that have follow-up fields
 * @param	String		The id of the field or form
 */
function bindFollowUpListeners(id)
{
	// If the given id belongs to a form -> iterate through the fieldsets and fields
	if(formInfo[id])
	{
		var sets = formInfo[id].children;
		for(var x = 0; x < sets.length; x++)
		{
			var fields = fieldsetInfo[sets[x]].children;
			for(var y = 0; y < fields.length; y++)
			{
				bindFollowUpListeners(fields[y]);
			}
		}
		return;
	}

	var i = info[id];
	var children = i.children;
	var selectors = i.updateSelectors;
	var events = i.updateEvents;
	var child;

	// For each selector... (some fields have more than one input field)
	for(var y = 0; y < selectors.length; y++)
	{
		// For each event... (some fields have multiple events such as onchange and onclick)
		$(selectors[y]).bind(events[y], function()
		{
			// For each child...
			for(var x = 0; x < children.length; x++)
			{
				// Show if the conditions are met
				child = children[x];
				if((child.v && check(id)) || contains(child.values, getValue(id)))
				{
						show(child.key);
				}
				else
				{
						hide(child.key);
				}
			}

		});
	}

}

/**
 * Returns the value of a field
 * @param	String		The id of the field
 * @returns	String		The value of the field
 */
function getValue(id)
{
	var i = info[id];
	var type = i.type;
	switch(type)
	{
		case "textarea":
		case "text":
			return $('#' + id).val();
		case "radio":
			return  $('#' + id +' input:checked').val();
		case "select":
			return $('#' + id +' option:selected').val();
		case "check":
			return $('#' + id + ':checked').size() == 1? 'on':'off';
        case "datetime":
            var parent = $('#date').parent();
            var year = $('select.form-date-year').val();
            var date = new Date($('select.form-date-year').val(), $('select.form-date-month').val() - 1, $('select.form-date-day').val(), $('select.form-date-hour').val(), $('select.form-date-minute').val(), 0,0);
            return Math.round(date.getTime() / 1000);
	}
	alert('todo: implement!');
}

/**
 * Resets a dynamicField (hides the input fields and resets their value)
 * @param	String 		The id of the field
 */

function resetDynamicField(id)
{
	if($('#' + id).attr('tagName') == 'FORM')
	{
		var children = formInfo[id].children;
    	for(var i = 0; i < children.length; i++)
    	{
    		resetDynamicField(children[i]);
    	}
    	return;
	}
	if($('#' + id).attr('tagName') == 'FIELDSET')
	{
		var children = fieldsetInfo[id].children;
		for(var i = 0; i < children.length; i++)
		{
			resetDynamicField(children[i]);
		}
		return;
	}
    var i = info[id];
    if(!i.dynamic)
    	return;
    var type = i.type;
    switch(type)
    {
    	case "textarea":
    	case "text":
    		$('#' + id).val(i.currentValue);
    	break;
    	case "radio":
	  		$('#' + id +' input:checked').removeAttr('checked');
	  		$('#' + id +' input[value=' + i.currentValue +']').attr('checked','checked');

    	break;
    	case "select":
    		$('#' + id +' option:selected').removeAttr('selected');
	  		$('#' + id +' option[value=' + i.currentValue +']').attr('selected','selected');
	  		$('#' + id).trigger('change');
    	break;
        case "tinymce":
            tinyMCE.execInstanceCommand(id,'mceSetContent',false,i.currentValue);
        break;
        case "datetime":
        	var container = getContainer(id);
        	var value = i.currentValue;
        	$('select',container).removeAttr('selected');
        	$('.form-date-day option[value=' + date('j',i.currentValue) + ']', container).attr('selected','selected');
        	$('.form-date-month option[value=' + date('n',i.currentValue) + ']', container).attr('selected','selected');
        	$('.form-date-year option[value=' + date('Y',i.currentValue) + ']', container).attr('selected','selected');
        	$('.form-date-hour option[value=' + date('H',i.currentValue) + ']', container).attr('selected','selected');
        	$('.form-date-minute option[value=' + date('i',i.currentValue) + ']', container).attr('selected','selected');
        break;
    }

}

/**
 * Updates a dynamic field (set the current-value)
 * @param	String		The id of the field
 */
function updateDynamicField(id)
{
    var i = info[id];
    var dd = getContainer(id);
    switch(i.type)
    {
    	case "textarea":
    	case "text":
    		var value = $('#' + id).val();
    		i.currentValue = value;
    		$('.current-value',dd).html(htmlEntities(value));
    	break;
    	case "radio":
    		i.currentValue = $('#' + id +' input:checked').val();
    		$('.current-value',dd).html($('#' + id +' input:checked').next().html());
    	break;
    	case "select":
    		i.currentValue = $('#' + id + ' option:selected').val();
    		$('.current-value',dd).html($('#' + id + ' option:selected').html());
    	break;
        case "tinymce":
            i.currentValue = $("#" + id + "_parent iframe").contents().find("#tinymce").html();
            $('.current-value',dd).html(i.currentValue);
        break;
        case "datetime":
        	i.currentValue = getValue(id);
            $('.current-value',dd).html(date(i.additional.format, i.currentValue));
        break;
        case "check":
        	alert('todo: implement');
        break;
    }
}

/**
 * Replaces all special characters in the given string to html-entities and returns it
 * @param	String		The initial text
 * @returns	String
 */
function htmlEntities(text)
{
    var c;
    var r = '';


    for(var i=0; i < text.length; i++)
    {
        c = text.charCodeAt(i);
        if((c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 121))
        {
            r += text[i];
        }else
        {
            r += "&#" + c + ";";
        }
    }
    return r;
}

/**
 * Returns the container element that contains the field with the given id. This is usually a dd element
 * @param	String		The id of the field
 * @returns	JQueryObject
 */
function getContainer(id)
{
	var c = $('#' + id);
	while(c.attr('nodeName') != 'DD' && !c.hasClass('field-container') && c.length != 0)
		c = c.parent();

	if(c.length == false)
		return false;
	return c;
}
/**
 * A multilangue javascript equivalent of the php date function
 * @param	String	The format of the date (see www.php.net/date)
 * @param	int		Timestamp
 * @returns String	The formatted string
 */
function date(format, timestamp)
{
	var daysShort = {'nl':['Zo','Ma','Di','Wo','Do','Vr','Za'], 'en':['Sun','Mon','Tue','Wed','Thu','Fri','Sat']};
	var daysLong = {'nl':['Zondag','Maandag','Dinsdag','Woensdag','Donderdag','Vrijdag','Zaterdag'], 'en':['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']};
	var monthsShort = {'nl':['Jan','Feb','Mrt','Apr','Mei','Jun','Jul','Aug','Sep','Okt','Nov','Dec'], 'en':['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']};
	var monthsLong = {'nl':['Januari','Februari','Maart','April','Mei','Juni','Juli','Augustus','September','Oktober','November','December'], 'en':['January','Febuary','March','April','May','June','July','August','Sep','October','November','December']};

	if(!lang)
		var lang = 'en';

	for(var i = format.length; i > 0; i--)
	{
		format = format.substr(0,i - 1) + '_' + format.substr(i - 1);
	}

	var d;
	if(timestamp)
    {
        timezone = 1; // one extra hour (Amsterdam)
        d = new Date((timestamp + (timezone * 3600)) * 1000);
    }
	
	else
		d = new Date();
	var output = format;

	output = output.replace('_d',d.getUTCDate() < 10? '0'+d.getUTCDate():d.getUTCDate());
	output = output.replace('_D',daysShort[lang][d.getUTCDay()]);
	output = output.replace('_j',d.getUTCDate());
	output = output.replace('_l',daysLong[lang][d.getUTCDay()]);
	output = output.replace('_N',d.getUTCDay() == 0? 7:d.getUTCDay());
	output = output.replace('_w',d.getUTCDay());

	output = output.replace('_F', monthsLong[lang][d.getUTCMonth()]);
	output = output.replace('_m',d.getUTCMonth() < 9? '0'+(d.getUTCMonth()+1):d.getUTCMonth()+1);
	output = output.replace('_M', monthsShort[lang][d.getUTCMonth()]);
	output = output.replace('_n', d.getUTCMonth()+1);

	output = output.replace('_Y', d.getUTCFullYear());
	output = output.replace('_y', d.getUTCFullYear().toString().substr(2));

	output = output.replace('_a', d.getUTCHours() < 12? 'am':'pm');
	output = output.replace('_A', d.getUTCHours() < 12? 'AM':'PM');
	output = output.replace('_g', d.getUTCHours()%12 == 0? 12:d.getUTCHours()%12);
	output = output.replace('_G', d.getUTCHours());
	output = output.replace('_h', d.getUTCHours()%12 == 0? 12:(d.getUTCHours()%12 < 10? '0'+d.getUTCHours()%12:d.getUTCHours()%12));
	output = output.replace('_H', d.getUTCHours() < 10? '0'+d.getUTCHours():d.getUTCHours());
	output = output.replace('_i', d.getUTCMinutes() < 10? '0' + d.getUTCMinutes():d.getUTCMinutes());
	output = output.replace('_s', d.getUTCSeconds() < 10? '0' + d.getUTCSeconds():d.getUTCSeconds());
	output = output.replace('_u', d.getTime());

	return output.split('_').join('');


}