var arrBrackets = [ '[', ']', '(', ')', '+', '-', '*', '/' ];
var arrOperators = [ '+', '-', '*', '/' ];
var arrGrundzahlen = new Array();

function addElement(arrElements, element) {
	if (arrElements == null || element == null || element.trim() == '') {
		return;
	}

	arrElements[arrElements.length] = element.trim();
};

function arrayContains(item, arr) {
	for (var i = 0; i < arr.length; i++) {
		if (arr[i] == item) {
			return true;
		}
	}
	return false;
};

var editor = {
	formel : '#formel',
	formelEditor : '#formeleditor',
	formelEditorInfo : '#formeleditorInfo',
	copyFormel : '#copyformel',
    isObjektformel : false,
    lastValue : null,

	addText : function(value) {
        if (value == null) {
            return;
        }

		var selected = editor.getSelectedElement();
		if (selected == null) {
			return;
		}

        editor.lastValue = value;

        // avoid useless action
		if (selected.hasClass('insert') && value == '') {
			return;
		}

        // in objektformeleditor mode only '[' and ']' may be deleted
        if (editor.isObjektformel) {
            if (value == '') {
                if (!selected.hasClass('bracket')) {
                    return;
                }

                var html = selected.html();
                if (html == '[' || html == ']') {
                    selected.html('');
                    editor.updateHidden();
		            editor.updateFormelEditor();                    
                }
                return;
            }

            if (!selected.hasClass('insert')) {
                return;
            }
        }

		if (selected.hasClass('insert')) {
			selected.removeClass('insert');
            selected.html(value);
		} else
        if (selected.hasClass('number') && value == '') {
            selected.html(value);
        } else
        if (selected.hasClass('number') && value != '') {
            selected.html(selected.html() + ' ' + value);
        } else
        if (selected.hasClass('operator') && value == '') {
            selected.html(value);
        } else
        if (selected.hasClass('bracket') && value == '') {
            selected.html(value);
        } else
        if (selected.hasClass('operator') && value != '') {
            selected.html(selected.html() + ' ' + value);
        }

		editor.updateHidden();
		editor.updateFormelEditor();
    },

	clearErrors : function() {
		$(this.formelInfo).html('');
        $(this.formel).removeClass('errorInFormel');
	},
	
	format : function(formel) {
		var arrElements = this.getFormulaElements(formel);
		var formatted = '';

		for (var i in arrElements) {
			formatted += arrElements[i] + ' ';
		}

		// this.validateFormulaElements(arrElements);
		return formatted;
	},

	getFormulaElements : function(formel) {
		if (formel == null || formel.trim() == '') {
			return null;
		}

		var arrElements = new Array();
		var lastPos = 0;
		var element;
		var isInCurlyBracket = false;

		for (var i=0;i<formel.length;i++) {
			if (formel.charAt(i) == '{') {
				isInCurlyBracket = true;
			}

			if (isInCurlyBracket) {
				if (formel.charAt(i) == '{') {
					element = formel.substring(lastPos, i);
					addElement(arrElements, element);
					lastPos = i ;
				}
			} else
			if (this.isStopChar(formel.charAt(i))) {
				element = formel.substring(lastPos, i);
				addElement(arrElements, element);
				addElement(arrElements, formel.charAt(i));
				lastPos = i + 1;
			}

			if (formel.charAt(i) == '}') {
				isInCurlyBracket = false;

				element = formel.substring(lastPos, i + 1);
				addElement(arrElements, element);
				lastPos = i + 1;
			}
		}

		element = formel.substring(lastPos);
		addElement(arrElements, element);
		addElement(arrElements, formel[i]);

		return arrElements;
	},

	getSelectedElement : function() {
		var lis = $(editor.formelEditor + ' li');
		var li;

		lis.each(function(obj) {
			if ($(lis[obj]).hasClass('selected')) {
				li = lis[obj];
			}
		});

		if (li == null) {
			return null;
		}

		return $(li);
	},

	isBracket : function(str) {
		return arrayContains(str, arrBrackets);
	},

	isNumeric : function(input) {
		return (input - 0) == input && input.length > 0;
	},

	isOperator : function(str) {
		return arrayContains(str, arrOperators);
	},

	isStopChar : function(str) {
		if (arrayContains(str, arrOperators)) {
			return true;
		}

		return arrayContains(str, arrBrackets);
	},

    liInputBlur : function(e) {
        editor.addText($(e).val());
    },

    select : function(elem) {
        var obj = $(elem);
        var html = obj.children('option:selected').html();
        var value = obj.val();

        if (html != null && html != '') {
            editor.addText('{' + html + '}');

            var isInArray = false;
            for (i in arrGrundzahlen) {
                if (arrGrundzahlen[i] == value) {
                    isInArray = true;
                    break;
                }
            }

            if (!isInArray) {
                arrGrundzahlen.push(value);
            }
        }

        var select = document.getElementById(elem.id);
        if (select != null && select.selectedIndex != null) {
               select.selectedIndex = 0;
        }
    },

	selectEditorElement : function(evt) {
        var element = (evt.target) ? evt.target : evt.srcElement;
        var li;
		var lis;
        var input;

        if (element.nodeName == null) {
            return;
        } else
        if (element.nodeName == 'INPUT') {
            input = element;
            li = $(input).parent();
        } else
        if (element.nodeName == 'LI') {
            li = $(element);
        } else {
            return;
        }

        lis = $(editor.formelEditor + ' li');

		lis.each(function(li) {
			obj = $(lis[li]);
            obj.css('width', '');
            obj.removeClass('selected');

            input = obj.find('input');
            input.removeClass('selected');
            input.css('width', '');
		});

		if (li == null) {
			return;
		}
        
		li.addClass('selected');

        if (!editor.isObjektformel) {
            input = li.find('input');
            input.focus();

            if (li.hasClass('insert')) {
                li.css('width', '25px');
                input.css('width', '25px');
                input.bind('blur', function() { editor.liInputBlur(this); });
            }
        }
	},

    submit : function() {
        $('#grundzahlenIds').val(arrGrundzahlen.join(' '));
        return editor.validateFormula();
    },

	toggle : function(str) {
        var obj = $(str);
        if (obj.css('display') == 'block') {
            obj.css('display', 'none');
        } else  {
            obj.css('display', 'block');
        }
    },
    
	updateFormelEditor : function() {
		var formel = $(editor.formel).val();
        var prevSelectedLi = editor.getSelectedElement();
        var pos = -1;

        if (prevSelectedLi != null) {
            pos = $(editor.formelEditor + ' li').index($(prevSelectedLi));
        }

		var arrElements = editor.getFormulaElements(formel);
        var liInsert = '<li class="insert"><input type="text" value="" onkeydown="if (event.keyCode == 13) editor.addText(this.value);"/></li>';

        if (editor.isObjektformel) {
            liInsert = '<li class="insert"><input type="text" value="" readonly="readonly"/></li>';
        }

        var html = liInsert;
		var css = '';
		for (i in arrElements) {
			if (editor.isOperator(arrElements[i])) {
				css = 'operator';
			} else
			if (editor.isBracket(arrElements[i])) {
				css = 'bracket';
			} else {
				css = 'number';
			}

			html += '<li class="' + css + '">' + arrElements[i] + '</li>';
            html += liInsert;
		}

		$(editor.formelEditor).html(html);

        if (!editor.isObjektformel) {
            var sel = $(editor.formelEditor + ' li :last');
            if (pos > -1) {

                if (editor.lastValue == '') {
                    pos += -1;
                } else {
                    pos += 2;
                }

                var obj = $(editor.formelEditor + ' li').get(pos);
                if (obj) {
                    sel = $(obj);
                }
            }

            if (sel) {
                if (sel[0].nodeName == 'INPUT') {
                    var li = sel.parent();
                    li.addClass('selected');
                    if (!sel.hasClass('number')) {
                        li.css('width','25px');
                    }
                }

                sel.addClass('selected');
                if (!sel.hasClass('number')) {
                    sel.css('width','25px');
                }
                sel.bind('blur', function() { editor.liInputBlur(this); });
                sel.focus();
            }
        }
	},

	updateHidden : function() {
		var lis = $(editor.formelEditor + ' li');
		var str = '';
		var obj;

		lis.each(function(li) {
			obj = $(lis[li]);
			if (obj.hasClass('insert')) {
				str += ' ';
			} else {
				str += obj.html();
			}
		});

		str = editor.format(str);
		$(editor.formel).val(str);
	},

    validateFormula : function() {
        var formel = $(editor.formel).val();
        if (formel == '') {
            return true;
        }

        var arrElements = editor.getFormulaElements(formel);
        if (arrElements == null || arrElements.length == 0) {
            return true;
        }

        return editor.validateFormulaElements(arrElements);
    },

    validateFormulaElements : function(arrElements) {
		if (arrElements == null || arrElements.length == 0) {
			return false;
		}

		var bracketCount1 = 0;
		var bracketCount2 = 0;
        var bracketSum1 = 0;
        var bracketSum2 = 0;
		var bracketOpenIndex1 = 0;
		var bracketOpenIndex2 = 0;
		var bracketCloseIndex1 = 0;
		var bracketCloseIndex2 = 0;
        var errorPos = -1;

		for (var i=0;i<arrElements.length;i++) {
			if (arrElements[i] == '[') {
				bracketCount1++;
				bracketOpenIndex1 = i;

                if (bracketSum1 >= 0) {
                    bracketSum1++;
                }
			} else
			if (arrElements[i] == ']') {
				bracketCount1--;
				bracketCloseIndex1 = i;
                bracketSum1--;

                if (bracketSum1 < 0 && errorPos < 0) {
                    errorPos = i;
                }
			} else
			if (arrElements[i] == '(') {
				bracketCount2++;
				bracketOpenIndex2 = i;

                if (bracketSum2 >= 0) {
                    bracketSum2++;
                }
			} else
			if (arrElements[i] == ')') {
				bracketCount2--;
				bracketCloseIndex2 = i;
                bracketSum2--;

                if (bracketSum2 < 0 && errorPos < 0) {
                    errorPos = i;
                }
			}
		}

		var info = $(editor.formelEditorInfo);

		if (bracketCount1 != 0 || bracketCount2 != 0) {
			info.html(error.bracketCount);
		} else
		if (bracketOpenIndex1 > bracketCloseIndex1 || bracketOpenIndex2 > bracketCloseIndex2) {
			info.html(error.brackets);
		} else {
			// validate formula
			var validate = '';
			var isValid = true;

			for (i=0;i< arrElements.length;i++) {
				if (arrElements[i] == '[' || arrElements[i] == ']' || arrElements[i] == '(' || arrElements[i] == ')') {
					validate += arrElements[i];
				} else
				if (arrElements[i] == '+' || arrElements[i] == '-' || arrElements[i] == '*' || arrElements[i] == '/') {
					validate += 'o';
				} else
				if (arrElements[i].indexOf('{') > -1) {
					validate += 'n';
				} else
				if (editor.isNumeric(arrElements[i])) {
					validate += 'n';
				} else {
					validate += 'e';
				}
			}

            if (bracketSum1 < 0 || bracketSum2 < 0) {
                info.html(error.brackets);
                errorPos--;
                isValid = false;
            } else
			if ((errorPos = validate.indexOf('e')) > -1) {
				info.html(error.unknownNumber);
				isValid = false;
			} else
			if ((errorPos = validate.indexOf('(o')) > -1 ||
                (errorPos = validate.indexOf('[o')) > -1) {
                info.html(error.bracketOpenOperator);
                isValid = false;
            } else
            if ((errorPos = validate.indexOf('o)')) > -1 ||
                (errorPos = validate.indexOf('o]')) > -1) {
				info.html(error.bracketCloseOperator);
				isValid = false;
			} else
			if ((errorPos = validate.indexOf('nn')) > -1) {
				info.html(error.numberSyntax);
				isValid = false;
			} else
			if ((errorPos = validate.indexOf('oo')) > -1) {
				info.html(error.doubleOperator);
				isValid = false;
			} else
			if ((errorPos = validate.indexOf('n(')) > -1 ||
                (errorPos = validate.indexOf('n[')) > -1) {
				info.html(error.numberBracket);
				isValid = false;
			} else
            if ((errorPos = validate.indexOf(')n')) > -1 ||
                (errorPos = validate.indexOf(']n')) > -1) {
                info.html(error.bracketNumber);
                isValid = false;
            } else
            if ((errorPos = validate.indexOf('()')) > -1 ||
                (errorPos = validate.indexOf('[]')) > -1) {
                info.html(error.emptyBracket);
                isValid = false;
            } else
			if (validate[0] == 'o') {
                errorPos = 0;
				info.html(error.formulaSyntax);
				isValid = false;
            } else
			if (validate.substr(validate.length - 1) == 'o') {
                errorPos = validate.length;
				info.html(error.formulaSyntax);
				isValid = false;
			}

            if (editor.isObjektformel) {
                var brackets = validate.replace(/[n|o]/g,'');
                if (brackets.indexOf('(]') > -1 ||
                    brackets.indexOf('[)') > -1) {
                    info.html(error.brackets);
                    isValid = false;
                }
            }
		}

        if (isValid) {
            $(editor.formelEditorInfo).removeClass('errorInFormel');
            info.html(error.formulaCheckDone);
        } else {
            $(editor.formelEditorInfo).addClass('errorInFormel');
        }

        if (errorPos > -1) {
            var lis = $(editor.formelEditor + ' li');
            $(lis[errorPos*2+2]).css('border','1px solid #e00');
        }

        return isValid;
	},

	init : function() {
        editor.updateFormelEditor();
        
		$("#copy").click(function(){
			$(editor.formel).val($(editor.copyFormel).val());
            editor.updateFormelEditor();
		});

		$("#formeleditorOperators input").each(function(){
			$(this).click(function() {
				var value = $(this).val();
				var formeleditor = $(editor.formel);

				if (value == 'C') {
					if (confirm(error.confirm)) {
						$(editor.formel).val('');
						editor.updateFormelEditor();
						formeleditor.val('');
						$(editor.formelEditorInfo).html('');
                        arrGrundzahlen = new Array();
					}
				} else if (value == '<') {
					editor.addText('');
				} else {
					editor.addText(value);
				}
			});
		});

		$(editor.formelEditor).bind('click', this.selectEditorElement);
	}
};
