var async = true;

function callFunctions(input)
{
    if(typeof(input) == "object")
    {
        for(var function_to_call in input)
        {
            try
            {
                var params = input[function_to_call];
                if(typeof(params) == "object")
                {
                    switch(function_to_call)
                    {
                        case "defaultEventHandler":
                            defaultEventHandler(params);
                        break;

                        case "setSelected":
                            for(var i = 0 ; i < params.length ; i++)
                            {
                                setSelected(params[i]);
                            }
                        break;

                        case "hideHierarchyArrows":
                            hideHierarchyArrows(params);
                        break;


                        default:
                           throw function_to_call+" wurde nicht in loadFunctions definiert";
                        break;
                    }
                }
                else
                {
                    throw "Der Parameter von "+function_to_call+" ist kein Objekt.";
                }
            }
            catch(error)
            {
                alert(error.toString());
            }
        }
    }
};

/**
 * Wandelt eine ID in eine fuer jquery lesbare Form um ([ in \\[, ] in \\])
 * Achtung, der ID-identifier # wird noch vor den ouput gesetzt
 */
function jqid(myid)
{
    return '#'+myid.replace(/\[/g,"\\[").replace(/\]/g,"\\]");
};

function jqclass(myid)
{
    return '.'+myid.replace(/\[/g,"\\[").replace(/\]/g,"\\]");
};

var NOT_SELECTED  = -2;
var NOT_SPECIFIED = -1;
/**
 * Funktionen für Ajax
 */
/**
 * uebermittelt ajax die selektierten items der selectbox
 * @param String el_id, [ID der Selectbox]
 * @params String function_name [abweichende Funktion]
 * @params Int return_type [Datentyp der zurückgeliefert werden soll]
 */
function setSelected(el_id, function_name, return_type, change)
{
    var el = document.getElementById(el_id);
    if(!el)
    {
        //console.log('Das Element '+el_id+' ist nicht vorhanden');
        return;
    }
    var cnt = el.options.length;

    var ids = "";
    if(!function_name)
    {
        function_name = 'setValues';
    }

    if(!change)
    {
        change = false;
    }

    for(i = 0; i < cnt; i++)
    {
        if(el.options[i].selected)
        {
            ids += (ids.length == 0 ? el.options[i].value:","+el.options[i].value);
        }
    }

    if(ids.length == 0)
    {
        ids = NOT_SELECTED;
    }

    var data = "function="+function_name+"&element_id="+el_id+"&ids="+ids;
    if(!return_type)
    {
        var return_type = 2;
    }
    sendRequest(data, return_type, change);
};

/**
 * Übermittelt ajax den eingegebenen Suchstring
 *
 * @params String el_id [Id des Zielelementes]
 * @params Object obj [Das Element, das den Suchstring liefert]
 * @params String function_name [alternativ abweichende Funktion]
 * @params Int return_type [Datentyp der zurückgeliefert werden soll]
 */
function getValues(el_id, obj, function_name, return_type, change)
{
    var value = obj.value;
    if(obj.getAttribute("field"))
    	field = obj.getAttribute("field");

	if(obj.id)
	{
	    field = obj.id;
	}
    if(!field)
    {
        return;
    }

    if(!change)
    {
        change = false;
    }

    if(!function_name)
    {
        function_name = 'getValues';
    }

    var data  = "element_id="+el_id+"&function="+function_name;
	data += "&field="+field+"&value="+encodeURIComponent(value);
    if(!return_type)
    {
        var return_type = 2;
    }
	sendRequest(data, return_type, change);
};

function saveTags()
{
    var value = $(jqid('tags')).val();
    var object_id = $("input[name='tag_dialog[object_id]']").getValue();
    var object_type = $("input[name='tag_dialog[object_type]']").getValue();
    var data  = "function=saveTags&value="+encodeURIComponent(value)+"&element_id="+object_id+"&field="+object_type;
	sendRequest(data, 42);
}

/**
 * Erzeugt einen Ajax-Request um ein oder mehrere Ajaxelemente zu löschen
 *
 * @author Martin Kluge <mail@silkhood-studios.de>
 * @params Array source_id [Array mit den zu löschenden Elementen]
 */
function deleteAjaxElements(source_id)
{
    var data = "function=deleteElements&source_id="+source_id;
    sendRequest(data, 2);
}


/**
 * Funktionen zur Bearbeitung von DIVs
 */
/**
 * loescht den div-container mit der uebergebenen id
 * und ggf. auch das dazugehoerende hidden-Feld
 *
 * Diese Funktion loescht rekursiv auch alle Childs
 *
 * @author Martin Kluge
 * @param String id [id des div-container]
 * @param bool delete_ajax_elements [Sollen auch Ajaxelemente gelöscht werden]
*/
function delDiv(id, delete_ajax_elements)
{
    var div, parent, last, primary, hidden, child_block;

    div = document.getElementById(id);
    if(div == null)
    {
        return false;
    }

    parent = div.parentNode;

    // Lies das letzte Element der ID aus
    last = id.substring(id.lastIndexOf('[')+1, id.lastIndexOf(']'));

    // Wenn last keine Zahl ist, bilde daraus den PK, wenn doch lies den PK aus der Id aus
    if(isNaN(parseInt(last)))
    {
        primary = last+'_id';
    }
    else
    {
        primary = getPrimary(id);
    }
    // Die Id mit angehaengtem PK ergibt die Bezeichnung des hidden-Feldes
    hidden = id+'['+primary+']';

    // Durchlaufe alle Childs des DIV-Containers
    for(var i = 0 ; i < div.childNodes.length ; i++)
    {
        child_block = div.childNodes[i];

       // Wenn das Child ein Div ist und die ID des parent in seiner ID vorkommt, dann
        // ist es auch ein logisches Kind
        if(child_block['id'] && child_block.nodeName == 'DIV' && child_block.getAttribute('id').indexOf(id) != -1)
        {
            // loesche rekursiv die Childs des DIV-Containers
            delDiv(child_block.getAttribute('id'));

            // Wenn ein Div geloescht wurde, den Zaehler verringern, da sich die Anzahl der
            // Childs auch um 1 verringert hat.
            i--;
        }
    }

    // Loeschen des hidden-field
    var form = document.forms.form;
    if(form[hidden] != undefined)
    {
        form.removeChild(form[hidden]);
    }

    // Das Div erst ganz zum Schluss loeschen, wegen der verschachtelten Struktur
    parent.removeChild(div);

    if(delete_ajax_elements && delete_ajax_elements == true)
    {
        deleteAjaxElements(new Array(id));
    }
};

/**
 * Löscht das letzte Element aus einer Reihe von Elementen
 *
 * Ausgewählt werden die Elemente die, die die übergebene Klasse oder Id haben
 * per default wird der Klassenselector verwendet
 *
 * @author Martin Kluge <mail@silkhood-studios.de>
 * @param String identifier [Wert der Klasse oder Id]
 * @param Char selector [JQuery Selector für den Wert]
 */
function delLastElement(identifier, selector)
{
    if(!selector)
    {
        var selector = '.';
    }
    // Suchen der Divs nach den Übergabeparametern
    var divs = $(selector+identifier);

    // Auslesen der Anzahl - 1
    var counter = divs.length - 1;

    // Wenn mehr als ein Element vorhanden ist, dann das letzte löschen
    if(counter > 0)
    {
        delDiv(divs[counter]['id'], true);
    }
}


/**
 * Setzt die Felder eines kopierten Blockes wieder zurück und aktiviert ggf. die Elemente
 *
 * @author Martin Kluge <mail@silkhood-studios.de>
 * @param Obj obj Der kopierte Div-Container
 **/
function resetField(obj)
{
   // Wenn es kein Option-Feld ist, Inhalte l�schen
    if(obj.value && obj.nodeName != 'INPUT' && obj.nodeName != 'OPTION')
    {
        obj.value = "";
    }
    // Wenn es ein Textfeld ist, Inhalte L�schen
    if(obj.nodeName == 'INPUT' && obj.type == 'text')
    {
        obj.value = "";
    }

    if(obj.type == 'select-one')
    {
		obj.selectedIndex = 0;
		obj.disabled      = false;
    }

    if(obj.type == 'select-multiple')
    {
        if(obj.id)
        obj.selectedIndex = -1;
        var klasse = obj.className;
        if(klasse != null && klasse.lastIndexOf('empty') != -1)
        {
            obj.options.length = 0;
        }
    }

    // Buttons aktivieren
    if(obj.type == 'button' || obj.nodeName == 'INPUT')
    {
        if(obj.id)
        {
            var temp = obj.id.substring(0, obj.id.lastIndexOf(']['));
            var id = parseInt(temp.substring(temp.lastIndexOf('][')+2));
            if(id > 0)
            {
                obj.disabled = false;
            }
        }
        else
        {
            obj.disabled = false;
        }
    }

    // Radiobuttons deselectieren
    if(obj.type == 'radio')
    {
        obj.checked = false;
    }
    if(obj.hasChildNodes())
    {
        var cnt_childs = obj.childNodes.length;
        for(var i = 0; i < cnt_childs; i++)
        {
            var child = obj.childNodes[i];
            resetField(child);
        }
    }
};


/**
* funktion loeschen von eingabefeldern
*
* @author Martin Kluge <mail@silkhood-studios.de>
* @param Objekt obj
* @param String value
*/
function clearInputValue(obj, value)
{
	if(obj.value == value)
	{
		obj.value = '';
	}
};

function toogleSelectBox(element_id)
{
    id = element_id.replace(/\[/g,"\\[").replace(/\]/g,"\\]");
    var element = $("."+id);
//    var options = element.options;
    var options = $("#"+id+" option");
    if(options.length > 0)
    {
        showElement(true, element);
    }
    else
    {
        showElement(false, element);
    }

}

function changeRadioGroup(element_id, group_class)
{
    id = element_id.replace(/\[/g,"\\[").replace(/\]/g,"\\]");
    var elements = $("."+group_class+"[id!='"+id+"'");
    //console.log('length: '+elements.length);

    var element = $("."+group_class+":checked");
    for(var i = 0 ; i < element.length ; i++)
    {
        if(element[i].id !== element_id)
        {
            element[i].checked = false
        }
    }
}


/**
* Funktion zum Kopieren von div-containern
* dabei werden eventuelle indizes heraufgezaehlt
*
* @author Martin Kluge <mail@silkhood-studios.de>
* @param source_id 	[zu kopierender container]
* @param create_ajax_elements [Ob ein neuer Zweig eines Ajax-Tree erzeugt werden soll]
*/
function copyDiv(source_id, create_ajax_elements)
{
    async = false;
    var start_el = document.getElementById(source_id);
    if(!start_el)
    {
        return;
    }

    var parent_el = start_el.parentNode;
    if(!start_el || !parent_el)
    {
        return;
    }

    var el_div_copy = start_el.cloneNode(true);

    var cnt_div = 0;
    // Durchlaufe alle Childs, um den neuen Index zu ermitteln
    var max = 0;
    for(var i = 0 ; i < parent_el.childNodes.length ; i++)
    {
        if(parent_el.childNodes[i].nodeName == 'DIV')
        {
            var child_id = parent_el.childNodes[i].id;
            var start = child_id.lastIndexOf('[');
            var stop = child_id.lastIndexOf(']');
            var id = parseInt(child_id.substring(start+1, stop));
            if(id > max)
            {
                max = id;
            }
        }
    }
    max++;

    // loeschen von subbloecken
    deleteSubblocks(el_div_copy);

    // loeschen eventueller fehlermeldungen
    deleteErrorMessage(el_div_copy, '');


    // Ein zu kopierender Container hat immer einen Index als letztes Element der Id
    // Dieser Index, bzw. die koplette Id ist auch Teil der Ids von Kindelementen
    // sowie Event-Handler Aufrufen. Bei kopieren muß der Index der Id aktualisiert werden
    var new_source_id = source_id.substring(0, source_id.lastIndexOf('[') + 1) + max + ']';

    // escapen von []
    var escaped_source_id = source_id.replace(/\[/g,"\\[").replace(/\]/g,"\\]");

    // erzeugen des Pattern zum ersetzen
    var pattern=eval('/' + escaped_source_id + '/g');

    // ersetzen der source_id im gesammten HTML-Code
    var new_HTML = el_div_copy.innerHTML.replace(pattern, new_source_id);

    // Ersetzen des HTML-Codes
    el_div_copy.innerHTML = new_HTML;

    // Erzeugen der neuen Id für den Div-Container
    var new_id = el_div_copy.getAttribute('id').replace(pattern, new_source_id);

    // Wenn der zu kopierende Block ausgeblendet ist, dann muß der neue eingeblendet werden
    var pattern_hidden = eval('/hidden/g');
    if(el_div_copy.getAttribute('class'))
    {
    var new_class = el_div_copy.getAttribute('class').replace(pattern_hidden, '');
    el_div_copy.setAttribute('class', new_class);
    }

    // Setzen der neuen Id des Div-Containers
    el_div_copy.setAttribute('id', new_id);
    // Zurücksetzen der Formularfelder
    resetField(el_div_copy)

    // kopierten container einfuegen
    parent_el.appendChild(el_div_copy);
    if(create_ajax_elements)
    {
        var data = "function=createRegisteredElements&source_id="+source_id+"&counter="+max;
        sendRequest(data, 2);
    }
    return el_div_copy;
}

/**
* Loeschen von Childs eines DIV-Containers
*
* Dabei werden ausser dem ersten Child alle weiteren Childs geloescht
* damit immer nur eine Formularzeile im neuen Element existiert
* die einzelnen Childs werde rekursiv durchlaufen
*
* @author Martin Kluge <mail@silkhood-studios.de>
* @param object element
**/
function deleteSubblocks(element)
{
    if(element.id)
    {
        for(var i = 0 ; i < element.childNodes.length ; i++)
        {
            // Nur wenn das Child ein Div und ein logisches Kind des Parent ist,
            // soll dieses bearbeitet werden das bedeutet das die ID im eine Komponente ergänzt wurde
            if(element.childNodes[i]['id'] && element.childNodes[i].nodeName == 'DIV' &&
               element.childNodes[i].getAttribute('id').indexOf(element.getAttribute('id')) == 0)
            {
                var child_block = element.childNodes[i];
                var first = true;
                var length = child_block.childNodes.length;
                for(var j = 0 ; j < child_block.childNodes.length ; j++)
                {
                    if(child_block.childNodes[j].nodeName == 'DIV')
                    {
                        // Das erste Element soll bestehen bleiben daher werden nur die
                        // Childs geloescht
                        if(first == true)
                        {
                            deleteSubblocks(child_block.childNodes[j]);
                            first = false;
                        }
                        // alle weiteren Elemente werden geloescht
                        else
                        {
                            child_block.removeChild(child_block.childNodes[j]);
                            // Wenn ein Div geloescht wurde, den Zaehler verringern, da sich die Anzahl der
                            // Childs auch um 1 verringert hat.
                            j--;
                        }
                    }
                }
            }
        }
    }
}

function emptySelectFields(class_name)
{
    var obj = $(jqclass(class_name));
    for(var i = 0 ; i < obj.length ; i++)
    {
        var select = obj[i];
        select.options.length = 0;
    }
}

/**
* loeschen von fehlermeldungen bei pflichtfeldern
*
* Dabei werden die Childs rekursiv durchlaufen
*
* @author Martin Kluge <mail@silkhood-studios.de>
* @param obj [zu behandelndes objekt]
*/
function deleteErrorMessage(obj)
{
	for(var i = 0 ; i < obj.childNodes.length ; i++)
	{
		var child = obj.childNodes[i];
		if(child.hasChildNodes())
		{
			deleteErrorMessage(child);
		}
	}
	if(obj.getAttribute('class') == 'error')
	{
		var parent = obj.parentNode;
		// das folgende <br> wird zuerst geloescht
		parent.removeChild(obj.nextSibling);
		parent.removeChild(obj);
	}
};


var selOptAr = new Object;
function getSelectedFieldsJQ(element_id)
{
	if(selOptAr[element_id] && selOptAr[element_id].length > 0)
	{
	    return;
	}

	selOptAr[element_id] = new Array();
    $(jqid(element_id)+' option: selected').each(function()
    {
        if(this.value != 0)
        {
            selOptAr[element_id].push(this.value);
        }
    });
};


function setSelectedFields(obj)
{
	id = obj.id;
	if(!selOptAr[id])
		return;

    for(var i = 0; i < obj.options.length; i++)
    {
        for(var j = 0; j < selOptAr[id].length; j++)
        {
            if(obj.options[i].value == selOptAr[id][j])
            {
                obj.options[i].selected = true;
                if(obj.type == "select-one")
                {
                	selOptAr[id] = new Array();
                	return;
                }
			}
         }
    }
    selOptAr[id] = new Array();
};



/**
 * Funktionen für Formularfunktionalitäten
 */


/**
 * Default Routine zur Behandlung von Formular-Events.
 *
 * Dem Eventhander wird ein Array aus Abhängigkeiten übergeben, die bestimmen welche
 * Werte mit welchen verglichen werden sollen. Dabei können die Werte aus einem
 * Formularfeld kommen oder statisch a übergeben werden. Ausserdem werden die
 * Zielelemente und die auszuführende Funktion übergeben.
 *
 * @param Array params
 *  source    String [ID des Source-Elementes von dem die Daten kommen]
 *  dest      Array  [Die Keys sind die möglichen JQuery Selektoren (id,class,element)]
 *  value     Array  [Fixe Werte die verglichen werden sollen]
 *  equal     Array  [Werte die auf Gleichheit überprüft werden sollen]
 *  not_equal Array  [Werte die auf Ungleicheit geprüft werden sollen]
 *  additionals Array [Wenn der Wert aufgeteilt werden muss]
 *  func      String [Funktion die im Erfolgsfall aufgerufen werden soll]
 */
function defaultEventHandler(params)
{
    // Durchlauf der einzelnen Abhängigkeiten
    for(var i = 0 ; i < params.length ; i++)
    {
        var input = params[i];
        var destination = input['dest'];
        var func = input['func'];
        var equal = new Array;

        // Unterscheidung ob die Werte aus einem Formularfeld ausgelesen werden sollen
        // oder ob übergebene Werte verwendet werden sollen
        if(input['source'] && !input['value'] && !input['checked'])
        {
            // Wenn die Werte aus dem Formular kommen sollen, das entsprechende Feld
            // auslesen
            var value = $(jqid(input['source'])).val();
            // Wenn der Wert eine zusammengesetzte Zeichenkette ist, dann werden die
            // Parameter zum Auslesen als additionals übergeben.
            if(input['additionals'])
            {
                // Splitten des Wertes
                var data = value.split(input['additionals']['seperator']);

                // Übergabe des benötigten Wertes
                value = data[input['additionals']['counter']]
            }
        }
        else if(input['source'] && input['checked'])
        {
            // Werte von Checkbox werden verarbeitet
            if ($(jqid(input['source'])+':checked').val() == 1)
            {
            	var value = 'true';
            }
            else
            {
            	var value = 'false';
            }
        }
        else
        {
            // Wenn fixe Werte übergeben wurden, dann diese verwenden
            var value = input['value'];
        }

        //console.log(input['value']);

       // Wenn die Vegleichswerte als not_equal übergeben werden, wird die
        // Vergleichsvariable auf false gesetzt,
        if(input['not_equal'])
        {
            var compare = input['not_equal'];
            equal = false;
        }
        else if(input['equal'])
        {
            // nsonsten wird die Vergleichsvariable auf true gesetzt
            var compare = input['equal'];
            equal = true;
        }

        // Wenn einige der benötigten Parameter kein Array sind, wird eines erstellt
        if(typeof(compare) != 'object')
        {
            compare = new Array(compare);
        }
        if(typeof(destination) != 'object')
        {
            destination = new Array(destination);
        }

        if(value == null || typeof(value) != 'object')
        {
            value = new Array(value);
        }

        // Den Erfolgsfall auf false setzen
		var hit = valid = false;

		// Durchlauf der ausgewählten Werte
		for(var value_counter = 0 ; value_counter < value.length ; value_counter++)
		{
			// Durchlauf der einzelnen Vergleichswerte
			for(var counter_compare = 0 ; counter_compare < compare.length ; counter_compare++)
			{
				// Vergleichen der aktuellen Werte, im Erlogsfall wird hit auf true gesetzt
			    if(value[value_counter] != null &&
			       (compare[counter_compare] == value[value_counter] ||
			       compare[counter_compare] == '*'))
				{
					hit = true;
				}
			}
		}

		// Wenn es eine Übereinstimmung gab dann wird das Event verarbeitet
		if((equal == false && hit == false) ||
		   (equal == true && hit == true))
		{
		    valid = true;
		}
		// Durchlauf der einzelnen Typen aus dem dest-Array
		for(var type in destination)
		{
			var dest = destination[type];
			switch(type)
			{
				case "id":
					selector = '#';
				  break;

				case "class":
					selector = '.';
				  break;

				case "element":
					selector = '';
				  break;
			}

			// Durchlauf der einzelnen Elemente pro Typ
			for(var dc = 0 ; dc < dest.length ; dc++)
			{

				object = dest[dc].replace(/\[/g,"\\[").replace(/\]/g,"\\]");
				obj = $(selector+object);
			    switch(func)
				{
					case 'showElement':
						showElement(valid, obj);
					  break;

					case 'hideElement':
						hideElement(valid, obj);
					  break;

					case 'disableElement':
						disableElement(valid, obj);
					  break;

					case 'resetField':
						if(valid == true)
						{
							switch(type)
							{
								case "id":
									var divs = document.getElementById(dest[dc]);
								  break;

								case "class":
									var divs = getElementsByClassName(dest[dc]);
								  break;
							}
							if(typeof(divs) != 'object')
							{
								divs = new Array(divs);
							}
							for(var index in divs)
							{
								resetField(divs[index]);
							}
						}
					  break;

					  case 'setSelected':
                            var data = "function=setValues&element_id="+dest[dc]+"&ids="+valid;
                            sendRequest(data, 2);
					  break;

					  case 'submit':
					       if(valid == true)
					       {
					           document.form.submit();
					       }
					  break;

					  case 'block':
						  $.blockUI.defaults.applyPlatformOpacityRules = false;
						  if(valid)
					      {
						  obj.block({message: null});
					      }
					   break;

					  case 'unblock':
						  if(valid)
					      {
						  obj.unblock();
					      }
					   break;
				}
			}
		}
    }
};


/**
 * Ausblenden von selectBoxen, wenn keine options vorhanden
 *
 * Wenn eine Selectbox die Daten per Ajax bekommt, kann es vorkommen das keine Optionen
 * vorhanden sind. In diesem Fall sollen die entsprechenden Divs ausgeblendet werden.
 * Dieses erfolgt im Normalfall durch ein Event des Elternelements. Beim kopieren
 * von Blöcken kann bei einer AMS jedoch kein Event ausgelöst werden. Daher müssen die
 * entsprechenden Boxen manuell überprüft werden.
 *
 * @author Martin Kluge <mail@silkhood-studios.de>
 * @param String obj
 */
function checkSelectVisiblity(class_name)
{
    var elements = $('.'+class_name);
    for(var ec = 0 ; ec < elements.length ; ec++)
    {
        if(elements[ec].options.length == 0)
        {
            var id = elements[ec].getAttribute('id')+'_div';
            var id = id.replace(/\[/g,"\\[").replace(/\]/g,"\\]");
            var div = $('#'+id);
            div.hide();
        }
    }
};


/**
 * Funktion zum Auslesen sämtlicher Element einer bestimmten Klasse
 *
 * Diese Funktion macht eigentlich das selbe wie folgender Aufruf:
 * $('.'+class_name);
 * jedoch wird hier mich ein JQuery Objekt übergeben, sonder ein Array aus
 * HtmlObjekten. Nötig ist diese Funktion, da resetFields() noch nicht auf JQuery
 * umgestellt wurde
 *
 * @param String class_name [Klassenname]
 */
function getElementsByClassName(class_name)
{
  var all_obj,ret_obj=new Array(),j=0,teststr;

  if(document.all)
  {
      all_obj = document.all;
  }
  else if(document.getElementsByTagName && !document.all)
  {
      all_obj = document.getElementsByTagName("*");
  }


  for(i=0;i<all_obj.length;i++)
  {
    if(all_obj[i].className.indexOf(class_name)!=-1)
    {
      teststr=","+all_obj[i].className.split(" ").join(",")+",";
      if(teststr.indexOf(","+class_name+",")!=-1)
      {
        ret_obj[j]=all_obj[i];
        j++;
      }
    }
  }
  return ret_obj;
}


/**
* liefert aus der uebergebenen Id die PK Bezeichnung des Objektes zurueck
*
* @author Martin Kluge <mail@silkhood-studios.de>
* @param String id
* @return String
**/
function getPrimary(id)
{
    var start, stop, substring;

    stop = id.lastIndexOf('][');
    // Wenn es kein Block ist dann gibt es nur eine Ebene
    if(stop != -1)
    {
        substring = id.substring(0, stop);
        start = substring.lastIndexOf('[');
    }
    else
    {
        stop = id.lastIndexOf('[');
        start = -1;
    }
    return id.substring(start+1, stop)+'_id';
}

/**
 * Zeigt ein Objekt an oder versteckt es
 *
 * @author Martin Kluge <mail@silkhood-studios.de>
 * @param bool show
 * @param Object obj [Objekt, das bearbeitet werden soll]
 */
function showElement(show, obj)
{
    if(show == true)
    {
        obj.show();
    }
    else
    {
        obj.hide();
    }
}

function hideElement(hide, obj)
{
    if(hide == true)
    {
        obj.hide();
    }
}

/**
 * Disabled ein Objekt oder enabled es
 *
 * @author Martin Kluge <mail@silkhood-studios.de>
 * @param bool disable
 * @param Object obj [Objekt, das bearbeitet werden soll]
 */
function disableElement(disable, obj)
{
    if(disable == true)
    {
        obj.attr("disabled", 'true');
    }
    else
    {
        obj.removeAttr('disabled');
    }
}


/**
 * Funktion zum Abschicken des Formulars per Enter
 */
function submitEnter(button,e)
{
    var keycode;
    if (window.event) keycode = window.event.keyCode;
    else if (e) keycode = e.which;
    else return true;
    if (keycode == 13)
    {
        var submitbutton = document.getElementById(button);
        if(submitbutton)
        {
            submitbutton.click();
            return false;
        }
    }
    else
    {
        return true;
    }
};


/**
 * Funktion zum Aktivieren einer Checkbox in einem Formular
 *
 * @param String frm [Name des Formulars]
 * @param String field [Name der Checkbox]
 */
function activateCheckbox(frm, field)
{
    if(document.forms[frm].elements[field].checked === false)
    {
        document.forms[frm].elements[field].checked = 1;
    }
    else
    {
        document.forms[frm].elements[field].checked = 0;
    }
};

/**
 * Funktion zum Setzen des Status mehrerer Checkboxen einer Gruppe
 *
 * @param String frm [Name des Formulars]
 * @param String field [Name der Gruppe]
 * @param String status [Status der gesetzt werden soll]
 * @param Int start [Index der ersten Checkbox die bearbeitet werden soll]
 * @param Int number [Index der letzten Checkbox die bearbeitet werden soll]
 */
function activateAllCheckboxes(frm, field, status, start, number)
{
    for (i=start; i<=number; i++)
    {
        if (document.forms[frm].elements[field+'['+i+']'] && document.forms[frm].elements[field+'['+i+']'].disabled != true)
        {
            document.forms[frm].elements[field+'['+i+']'].checked = status;
        }
    }
};

/**
 * Funktion zum Setzen des Status von allen Checkboxen in einer Zeile
 *
 * Diese Funktion wird für eine Kalenderanzeige benötigt, um die Felder einer Woche
 * zu bearbeiten
 *
 * @param String frm [Name des Formulars]
 * @param String field [Name der Gruppe]
 * @param String status [Status der gesetzt werden soll]
 * @param Int start [überflüssig]
 * @param Int number [Index der letzen Checkbox die bearbeitet werden soll]
 * @param Int column [Index der Zeile die bearbeitet werden soll]
 */
function activateColumnCheckboxes(frm, field, status, start, number, column )
{
    var row = 1;

    for (i=1; i<=number; i++)
    {
        if ( i - ((row-1) * 7) == column )
            if (document.forms[frm].elements[field+'['+i+']'] && document.forms[frm].elements[field+'['+i+']'].disabled != true)
                document.forms[frm].elements[field+'['+i+']'].checked = status;

        if ( i / row == 7)
            row += 1;
    }
};


/**
 * Counter-Funktion fuer SMS-Formular
 *
 * @return  boolean  whether pointer is set or not
 */
function wordCount(max_length, total_max_length)
{
    //alert(document.form.elements['sms[sms_message]']);
    var sms_message = document.form.elements['sms[sms_message]'];

    //Behandlung der Sonderzeichen, die doppelt gezaehlt werden
    var extra = 0;
    for(i = 0; i < sms_message.value.length; i++)
    {
        s = sms_message.value.charCodeAt(i);

        //Behandlung der Sonderzeichen
        if((s > 32 && s < 48) || (s > 57 && s < 65) || (s > 90 && s < 97) || (s > 123))
        {
            extra++;
        }
    }

    if(sms_message.value.length > max_length)
    {
        sms_message.value = sms_message.value.substring(0,max_length);
    }

    document.form.elements['sms[counter]'].value = max_length - sms_message.value.length - extra;

    // Länge der Absenderkennung
    var laenge_absender = total_max_length - max_length;

    document.form.elements['sms[num_sms]'].value = Math.ceil((laenge_absender + sms_message.value.length) / 160);
};


/**
 * This array is used to remember mark status of rows in browse mode
 */
var marked_row = new Array;

/**
 * Sets/unsets the pointer and marker in browse mode
 *
 * @param   object    the table row
 * @param   interger  the row number
 * @param   string    the action calling this script (over, out or click)
 * @param   string    the default background color
 * @param   string    the color to use for mouseover
 * @param   string    the color to use for marking a row
 *
 * @return  boolean  whether pointer is set or not
 */
function setPointer(theRow, theRowNum, theAction, theDefaultColor, thePointerColor, theMarkColor)
{
    var theCells = null;

    // 1. Pointer and mark feature are disabled or the browser can't get the
    //    row -> exits
    if ((thePointerColor == '' && theMarkColor == '') ||
        typeof(theRow.style) == 'undefined')
    {
        return false;
    }

    // 2. Gets the current row and exits if the browser can't get it
    if (typeof(document.getElementsByTagName) != 'undefined')
    {
        theCells = theRow.getElementsByTagName('td');
    }
    else if (typeof(theRow.cells) != 'undefined')
    {
        theCells = theRow.cells;
    }
    else
    {
        return false;
    }

    // 3. Gets the current color...
    var rowCellsCnt  = theCells.length;
    var domDetect    = null;
    var currentColor = null;
    var newColor     = null;
    // 3.1 ... with DOM compatible browsers except Opera that does not return
    //         valid values with "getAttribute"
    if (typeof(window.opera) == 'undefined'
        && typeof(theCells[0].getAttribute) != 'undefined')
    {
        currentColor = theCells[0].getAttribute('bgcolor');
        domDetect    = true;
    }
    // 3.2 ... with other browsers
    else
    {
        currentColor = theCells[0].style.backgroundColor;
        domDetect    = false;
    } // end 3

    // 3.3 ... Opera changes colors set via HTML to rgb(r,g,b) format so fix it
    if (currentColor.indexOf("rgb") >= 0)
    {
        var rgbStr = currentColor.slice(currentColor.indexOf('(') + 1,
                                     currentColor.indexOf(')'));
        var rgbValues = rgbStr.split(",");
        currentColor = "#";
        var hexChars = "0123456789ABCDEF";
        for (var i = 0; i < 3; i++)
        {
            var v = rgbValues[i].valueOf();
            currentColor += hexChars.charAt(v/16) + hexChars.charAt(v%16);
        }
    }

    // 4. Defines the new color
    // 4.1 Current color is the default one
    if (currentColor == ''
        || currentColor.toLowerCase() == theDefaultColor.toLowerCase()) {
        if (theAction == 'over' && thePointerColor != '') {
            newColor              = thePointerColor;
        }
        else if (theAction == 'click' && theMarkColor != '') {
            newColor              = theMarkColor;
            marked_row[theRowNum] = true;
        }
    }
    // 4.1.2 Current color is the pointer one
    else if (currentColor.toLowerCase() == thePointerColor.toLowerCase()
             && (typeof(marked_row[theRowNum]) == 'undefined' || !marked_row[theRowNum])) {
        if (theAction == 'out') {
            newColor              = theDefaultColor;
        }
        else if (theAction == 'click' && theMarkColor != '') {
            newColor              = theMarkColor;
            marked_row[theRowNum] = true;
        }
    }
    // 4.1.3 Current color is the marker one
    else if (currentColor.toLowerCase() == theMarkColor.toLowerCase()) {
        if (theAction == 'click') {
            newColor              = (thePointerColor != '')
                                  ? thePointerColor
                                  : theDefaultColor;
            marked_row[theRowNum] = (typeof(marked_row[theRowNum]) == 'undefined' || !marked_row[theRowNum])
                                  ? true
                                  : null;
        }
    } // end 4

    // 5. Sets the new color...
    if (newColor) {
        var c = null;
        // 5.1 ... with DOM compatible browsers except Opera
        if (domDetect) {
            for (c = 0; c < rowCellsCnt; c++) {
                theCells[c].setAttribute('bgcolor', newColor, 0);
            } // end for
        }

    } // end 5

    return true;
}; // end of the 'setPointer()' function


/**
 * Baut eine Hierarchie von aufeinander aufbauenden Selectboxen
 *
 * Wenn selected != 0, lösche alles unter mir und führe ein copyDiv aus
 * Wenn selected == 0, lösche alle unter mir
*/
function buildHierarchy(source_id, selectbox_id_postfix)
{
    // hole das Level auf dem die event-auslösende Box liegt
    var level = source_id.substring(source_id.lastIndexOf('[') + 1, source_id.length - 1);
    // suche den root-path zur event-auslösenden Box
    var root = source_id.substring(0, source_id.lastIndexOf('['));

    var to_delete;
    var to_delete_string;
    var found = true;
    var deleted = false;
    async = false;

    while(found)
    {
        // alle tieferen Boxen müssen gelöscht werden
        to_delete_string = root+"["+ ++level +"]";
        to_delete = $(jqid(to_delete_string));
        if(to_delete.length)
        {
            to_delete.remove();
            if(!deleted)
            {
                // lösche auch in der Ajax-Session
                var data = "function=deleteElements&source_id="+to_delete_string;
                sendRequest(data, 2);
                deleted = true;
            }
        }
        else
        {
            found = false;
        }
    }

    var select_box = source_id+"["+ selectbox_id_postfix +"]"
    // wenn der Wert nicht 0 ist, soll eine neue Box erscheinen
    if($(jqid(select_box)).val() != 0)
    {
        var new_div = copyDiv(source_id, true);
        // verstecke letzten Pfeil
        $(jqid(new_div.id+"[arrow]")).hide();
        // zeige vorletzten Pfeil
        $(jqid(source_id+"[arrow]")).show();
        setSelected(select_box);
    }
    async = true;
};


/**
 * Löscht eine Hierarchie aus dem DOM und aus der Ajax-Session
 *
 */
function delHierarchy(to_delete_string)
{
    // entferne die Hierarchie
    $(jqid(to_delete_string)).remove();
    // das hidden Feld muss auch gelöscht werden, damit es keine
    to_delete_string += "[hierarchy_id]";
    to_delete_string = to_delete_string.replace(/\[/g,"\\[").replace(/\]/g,"\\]") ;
    $("[name="+to_delete_string+"]").remove();
    // lösche auch in der Ajax-Session
    var data = "function=deleteElements&source_id="+to_delete_string;
    sendRequest(data, 2);
};


/**
 * Kopiert eine komplette Hierarchie und blendet den letzten Pfeil aus
 */
function copyHierarchy(source_id)
{
    var new_div = copyDiv(source_id, true);
    // verstecke letzten Pfeil
    $(jqid(new_div.id)+" .hierarchy_arrow").hide();
};


/**
 * Blendet alle überflüssigen Pfeile in den Hierarchies aus
 */
function hideHierarchyArrows(params)
{
    $.each(params, function(key, value)
    {
        $(jqid(value+"[arrow]")).hide();
    });

};


/**
 * Blendet die Update-Selectboxen im Import ein und aus
 */
function toggleUpdateCheck(param)
{
    if($(jqid(param.id)+' option:selected').val() == '1')
    {
        $('.update_check').attr('checked', false);
        $('.update_check').attr('disabled', 'disabled');
    }
    else
    {
        $('.update_check').attr('disabled', '');
    }
};


function setValue(value, name)
{
    var element = document.getElementsByName(name)[0];
    if(value == true)
    {
        element.value = 1;
    }
    else
    {
        element.value = 0;
    }
}

function changeSelectValues()
{
    var start_el = document.getElementById('workflow_message[0]');
    if(!start_el)
    {
        return;
    }

    var parent_el = start_el.parentNode;
    if(!start_el || !parent_el)
    {
        return;
    }
    var max = 0;
    for(var i = 0 ; i < parent_el.childNodes.length ; i++)
    {
        if(parent_el.childNodes[i].nodeName == 'DIV')
        {
            var child_id = parent_el.childNodes[i].id;
            var start = child_id.lastIndexOf('[');
            var stop = child_id.lastIndexOf(']');
            var id = parseInt(child_id.substring(start+1, stop));
            if(id > max)
            {
                max = id;
            }
        }
    }
    var element = $(jqid('workflow_message['+max+'][dispatch_type]')+' option');
    $(jqid('workflow_message['+max+'][dispatch_type]')+' option').remove();
    $(jqid('workflow_message['+max+'][dispatch_type]')).append('<option value="4">nach Vorgänger</option>')
    $(jqid('workflow_message['+max+'][send_type]')).change();
    $(jqid('workflow_message['+max+'][dispatch_type]')).change();

}

function switch_input(this_object)
{
    this_object.style.color = "#000000";
    this_object.select();
}

function array_unique (inputArr) {
    // Removes duplicate values from array
    //
    // version: 1009.2513
    // discuss at: http://phpjs.org/functions/array_unique    // +   original by: Carlos R. L. Rodrigues (http://www.jsfromhell.com)
    // +      input by: duncan
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: Nate
    // +      input by: Brett Zamir (http://brett-zamir.me)    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Michael Grier
    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
    // %          note 1: The second argument, sort_flags is not implemented;
    // %          note 1: also should be sorted (asort?) first according to docs    // *     example 1: array_unique(['Kevin','Kevin','van','Zonneveld','Kevin']);
    // *     returns 1: {0: 'Kevin', 2: 'van', 3: 'Zonneveld'}
    // *     example 2: array_unique({'a': 'green', 0: 'red', 'b': 'green', 1: 'blue', 2: 'red'});
    // *     returns 2: {a: 'green', 0: 'red', 1: 'blue'}
    var key = '', tmp_arr2 = {}, val = '';
    var __array_search = function (needle, haystack) {
        var fkey = '';
        for (fkey in haystack) {
            if (haystack.hasOwnProperty(fkey)) {                if ((haystack[fkey] + '') === (needle + '')) {
                    return fkey;
                }
            }
        }        return false;
    };

    for (key in inputArr) {
        if (inputArr.hasOwnProperty(key)) {            val = inputArr[key];
            if (false === __array_search(val, tmp_arr2)) {
                tmp_arr2[key] = val;
            }
        }    }

    return tmp_arr2;
}



function unserialize (data) {
    // http://kevin.vanzonneveld.net
    // +     original by: Arpad Ray (mailto:arpad@php.net)
    // +     improved by: Pedro Tainha (http://www.pedrotainha.com)
    // +     bugfixed by: dptr1988
    // +      revised by: d3x
    // +     improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +        input by: Brett Zamir (http://brett-zamir.me)
    // +     improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +     improved by: Chris
    // +     improved by: James
    // +        input by: Martin (http://www.erlenwiese.de/)
    // +     bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +     improved by: Le Torbi
    // +     input by: kilops
    // +     bugfixed by: Brett Zamir (http://brett-zamir.me)
    // -      depends on: utf8_decode
    // %            note: We feel the main purpose of this function should be to ease the transport of data between php & js
    // %            note: Aiming for PHP-compatibility, we have to translate objects to arrays
    // *       example 1: unserialize('a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}');
    // *       returns 1: ['Kevin', 'van', 'Zonneveld']
    // *       example 2: unserialize('a:3:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";s:7:"surName";s:9:"Zonneveld";}');
    // *       returns 2: {firstName: 'Kevin', midName: 'van', surName: 'Zonneveld'}

    var that = this;
    var utf8Overhead = function(chr) {
        // http://phpjs.org/functions/unserialize:571#comment_95906
        var code = chr.charCodeAt(0);
        if (code < 0x0080) {
            return 0;
        }
        if (code < 0x0800) {
             return 1;
        }
        return 2;
    };


    var error = function (type, msg, filename, line){throw new that.window[type](msg, filename, line);};
    var read_until = function (data, offset, stopchr){
        var buf = [];
        var chr = data.slice(offset, offset + 1);
        var i = 2;
        while (chr != stopchr) {
            if ((i+offset) > data.length) {
                error('Error', 'Invalid');
            }
            buf.push(chr);
            chr = data.slice(offset + (i - 1),offset + i);
            i += 1;
        }
        return [buf.length, buf.join('')];
    };
    var read_chrs = function (data, offset, length){
        var buf;

        buf = [];
        for (var i = 0;i < length;i++){
            var chr = data.slice(offset + (i - 1),offset + i);
            buf.push(chr);
            length -= utf8Overhead(chr);
        }
        return [buf.length, buf.join('')];
    };
    var _unserialize = function (data, offset){
        var readdata;
        var readData;
        var chrs = 0;
        var ccount;
        var stringlength;
        var keyandchrs;
        var keys;

        if (!offset) {offset = 0;}
        var dtype = (data.slice(offset, offset + 1)).toLowerCase();

        var dataoffset = offset + 2;
        var typeconvert = function(x) {return x;};

        switch (dtype){
            case 'i':
                typeconvert = function (x) {return parseInt(x, 10);};
                readData = read_until(data, dataoffset, ';');
                chrs = readData[0];
                readdata = readData[1];
                dataoffset += chrs + 1;
            break;
            case 'b':
                typeconvert = function (x) {return parseInt(x, 10) !== 0;};
                readData = read_until(data, dataoffset, ';');
                chrs = readData[0];
                readdata = readData[1];
                dataoffset += chrs + 1;
            break;
            case 'd':
                typeconvert = function (x) {return parseFloat(x);};
                readData = read_until(data, dataoffset, ';');
                chrs = readData[0];
                readdata = readData[1];
                dataoffset += chrs + 1;
            break;
            case 'n':
                readdata = null;
            break;
            case 's':
                ccount = read_until(data, dataoffset, ':');
                chrs = ccount[0];
                stringlength = ccount[1];
                dataoffset += chrs + 2;

                readData = read_chrs(data, dataoffset+1, parseInt(stringlength, 10));
                chrs = readData[0];
                readdata = readData[1];
                dataoffset += chrs + 2;
                if (chrs != parseInt(stringlength, 10) && chrs != readdata.length){
                    error('SyntaxError', 'String length mismatch');
                }

                // Length was calculated on an utf-8 encoded string
                // so wait with decoding
 //               readdata = utf8_decode(readdata);
            break;
            case 'a':
                readdata = {};

                keyandchrs = read_until(data, dataoffset, ':');
                chrs = keyandchrs[0];
                keys = keyandchrs[1];
                dataoffset += chrs + 2;

                for (var i = 0; i < parseInt(keys, 10); i++){
                    var kprops = _unserialize(data, dataoffset);
                    var kchrs = kprops[1];
                    var key = kprops[2];
                    dataoffset += kchrs;

                    var vprops = _unserialize(data, dataoffset);
                    var vchrs = vprops[1];
                    var value = vprops[2];
                    dataoffset += vchrs;

                    readdata[key] = value;
                }

                dataoffset += 1;
            break;
            default:
                error('SyntaxError', 'Unknown / Unhandled data type(s): ' + dtype);
            break;
        }
        return [dtype, dataoffset - offset, typeconvert(readdata)];
    };

    return _unserialize((data+''), 0)[2];
}
