// ============================================================
// Globale Deklarationen
// ============================================================

// den undefinierten Wert deklarieren
var undefined;


// ============================================================
// Klasse Form
// ============================================================

// ------------------------------------------------------------
// Konstruktor
// ------------------------------------------------------------

// ---------------------------------------
// Form(string)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
function Form(id) {
  // Attribute
  this._id = undefined;
  this._childElementList = [];
  // Initialisierungen
  this.id(id);
  this._setChildElementList();
}

// ------------------------------------------------------------
// Zugriffsfunktionen
// ------------------------------------------------------------

// -----------
// id(string)
// -----------
//
// Beschreibung:
// -------------
//   ...
//
Form.prototype.id = function(str) {
  if (arguments.length) {
    if (typeof str != 'string') {
      throw new Error('Form.prototype.id meldet: Argument ist nicht vom Typ string!');
    }
    this._id = str;
  }
  return this._id;
}

// -----------
// addChildElementList(Field)
// -----------
//
// Beschreibung:
// -------------
//   ...
//
Form.prototype.addChildElementList = function(obj) {
  if (arguments.length) {
    if (! obj instanceof Field) {
      throw new Error("Form.prototype.addChildElementList meldet: Argument ist nicht Instanz von Field!");
    }
    this._childElementList.push(obj);
  }
  return this._childElementList;
}

// -----------
// getChildElementList()
// -----------
//
// Beschreibung:
// -------------
//   ...
//
Form.prototype.getChildElementList = function() {
  return this._childElementList;
}

// ------------------------------------------------------------
// Öffentliche Instanzmethoden
// ------------------------------------------------------------

// ------------------------------------------------------------
// Private Instanzmethoden
// ------------------------------------------------------------

// ---------------------------------------
// _setChildElementList()
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Form.prototype._setChildElementList = function() {

  var newElement;
  var currentFormDomPath = document.getElementById(this.id());
  var inputElements = currentFormDomPath.getElementsByTagName('input');
  var selectElements = currentFormDomPath.getElementsByTagName('select');
  var textareaElements = currentFormDomPath.getElementsByTagName('textarea');

  for (var i=0; i<inputElements.length; i++) {
    if (inputElements[i].type != 'hidden' && inputElements[i].type != 'submit' && inputElements[i].type != 'reset' && inputElements[i].type != 'image' && inputElements[i].type != 'button') {
      if (inputElements[i].id) {
        newElement = Field.createInstance(inputElements[i].id);
        this.addChildElementList(newElement);
      }
    }
  }

  for (var i=0; i<selectElements.length; i++) {
    if (selectElements[i].id) {
      newElement = Field.createInstance(selectElements[i].id);
      this.addChildElementList(newElement);
    }
  }

  for (var i=0; i<textareaElements.length; i++) {
    if (textareaElements[i].id) {
      newElement = Field.createInstance(textareaElements[i].id);
      this.addChildElementList(newElement);
    }
  }

}

// ---------------------------------------
// _setCurrentValues()
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Form.prototype._setCurrentValues = function() {

  var childElementList = this.getChildElementList();

  for (var i=0; i<childElementList.length; i++) {

    var currentElementDomPath = document.getElementById(childElementList[i].id());

    if (childElementList[i].type() == 'select') {
      childElementList[i].currentValue(currentElementDomPath.options[currentElementDomPath.options.selectedIndex].value);
    } else {
      childElementList[i].currentValue(currentElementDomPath.value);
    }

  }

  return childElementList;

}


// ------------------------------------------------------------
// Öffentliche Klasseneigenschaften
// ------------------------------------------------------------


// ------------------------------------------------------------
// Private Klasseneigenschaften
// ------------------------------------------------------------

Form._registeredElementsList = {};
Form._errorLogList = {};


// ------------------------------------------------------------
// Öffentliche Klassenmethoden
// ------------------------------------------------------------

// ---------------------------------------
// initForms()
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Form.initForms = function() {

  var currentFormsDomPath = [];

  currentFormsDomPath = document.getElementsByTagName('form');

  for (var i=0; i<currentFormsDomPath.length; i++) {
    Form.createInstance(currentFormsDomPath[i].id);
  }

  return currentFormsDomPath;

}

// ---------------------------------------
// createInstance(string)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Form.createInstance = function(id) {

  if (!id) {
    throw new Error('Form.createInstance meldet: Es wurde keine ID übergeben');
  }

  if (Form._registeredElementsList[id]) {
    throw new Error('Form.createInstance meldet: Die ID "' + id + '" ist bereits vergeben.');
  }

  Form._registeredElementsList[id] = new Form(id);

  return Form._registeredElementsList[id];

}

// ---------------------------------------
// getFormInstanceById(string)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Form.getFormInstanceById = function(id) {
  return Form._registeredElementsList[id];
}

// ---------------------------------------
// standardCheck(string)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Form.standardCheck = function(id) {

  var currentFormInstance = Form.getFormInstanceById(id);
  var errorLog = {};

  if (!currentFormInstance) {
    throw new Error('Form.standardCheck meldet: Die ID "' + id + '" ist nicht vergeben.');
  }

  errorLog = Form.getErrorLog(id);

  if (errorLog['id']) {
    Form.setErrorMessage(errorLog);
    return false;
  }

  return true;

}

// ---------------------------------------
// getErrorLog(string)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Form.getErrorLog = function(id) {

  var currentForm = Form.getFormInstanceById(id);
  var childElementList = currentForm.getChildElementList();
  var currentFormDomPath = document.getElementById(currentForm.id());
  var isError;
  var errorLog = {};

  currentForm._setCurrentValues();

  for (var i=0; i<childElementList.length; i++) {

    if (childElementList[i].required() == true) {

      isError = Form._checkRequired(currentFormDomPath,childElementList[i]);

      if (isError == true) {
        errorLog['id'] = childElementList[i].id();
        errorLog['type'] = childElementList[i].type();
        errorLog['errorType'] = 'required';
        errorLog['expected'] = '';
        break;
      }

    }

    if (childElementList[i].contentType()) {

      isError = Form._checkContentType(childElementList[i]);

      if (isError == true) {
        errorLog['id'] = childElementList[i].id();
        errorLog['type'] = childElementList[i].type();
        errorLog['errorType'] = 'contentType';
        errorLog['expected'] = childElementList[i].contentType();
        break;
      }

    }

    if (childElementList[i].contentSyntax()) {

      isError = Form._checkContentSyntax(childElementList[i]);

      if (isError == true) {
        errorLog['id'] = childElementList[i].id();
        errorLog['type'] = childElementList[i].type();
        errorLog['errorType'] = 'contentSyntax';
        errorLog['expected'] = childElementList[i].contentSyntax();
        break;
      }

    }

  }

  return errorLog;

}

// ---------------------------------------
// setErrorMessage(array)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Form.setErrorMessage = function(errorLog) {

  var errorString = '';
  var currentFormFieldDomPath = document.getElementById(errorLog['id']);
  var currentFormFieldName = currentFormFieldDomPath.name;

  errorString += 'Fehler im Formular\n';

  if (errorLog['errorType'] == 'required') {
    errorString += 'Das Feld "' + currentFormFieldName + '" ist ein Pflichtfeld.';
  }

  if (errorLog['errorType'] == 'contentType') {
    if (errorLog['expected'] == 'number') {
      errorString += 'Bitte geben Sie im Feld "' + currentFormFieldName + '" eine Zahl ein.';
    }
  }

  if (errorLog['errorType'] == 'contentSyntax') {
    if (errorLog['expected'] == 'e-mail') {
      errorString += 'Bitte geben Sie im Feld "' + currentFormFieldName + '" eine gültige E-Mail-Adresse ein.';
    }
    if (errorLog['expected'] == 'date') {
      errorString += 'Bitte geben Sie im Feld "' + currentFormFieldName + '" ein Datum im Format tt.mm.jjjj ein.';
    }
    if (errorLog['expected'] == 'plz') {
      errorString += 'Bitte geben Sie im Feld "' + currentFormFieldName + '" eine Postleitzahl ein.';
    }
    if (errorLog['expected'] == 'telefon') {
      errorString += 'Bitte geben Sie im Feld "' + currentFormFieldName + '" eine Telefonnummer ein.';
    }
  }

  alert(errorString);

  currentFormFieldDomPath.focus();

  if (errorLog['type'] == 'text' || errorLog['type'] == 'textarea') {
    currentFormFieldDomPath.select();
  }

  return errorString;

}

// ------------------------------------------------------------
// Private Klassenmethoden
// ------------------------------------------------------------

// ---------------------------------------
// _checkRequired(object,object)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Form._checkRequired = function(currentFormDomPath,currentFieldInstance) {

  var isError;

  if (currentFieldInstance.type() == 'radio' || currentFieldInstance.type() == 'checkbox') {
    isError = Form._checkRadioCheckBoxes(currentFormDomPath,currentFieldInstance);
    return isError;
  }

  isError = Form._checkFormFields(currentFieldInstance);
  return isError;

}

// ---------------------------------------
// _checkRadioCheckBoxes(object,object)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Form._checkRadioCheckBoxes = function(currentFormDomPath,currentFieldInstance) {

  var elementList = currentFormDomPath[currentFieldInstance.name()];
  var isError = true;

  if (elementList.length) {
    for (var i=0; i<elementList.length; i++) {
      if (elementList[i].checked) {
        isError = false;
        break;
      }
    }
  } else {
    if (elementList.checked) {
      isError = false;
    }
  }

  return isError;

}

// ---------------------------------------
// _checkFormFields(object)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Form._checkFormFields = function(currentFieldInstance) {

  var isError = false;
  var defaultValue = currentFieldInstance.defaultValue();
  var currentValue = currentFieldInstance.currentValue();
  var regularExpressionValue = /^\s*$/;
  var isEmptyString = regularExpressionValue.test(currentValue);

  /*if (isEmptyString == true || currentValue == defaultValue) {
    isError = true;
  }*/

  if (isEmptyString == true) {
    isError = true;
  }

  return isError;

}

// ---------------------------------------
// _checkContentType(object)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Form._checkContentType = function(currentFieldInstance) {

  var isError = false;
  var currentContentType = currentFieldInstance.contentType();
  var currentValue = currentFieldInstance.currentValue();
  var regularExpressionNumber = /^\d+([.,]\d+)?$/;
  var isNumber = regularExpressionNumber.test(currentValue);

  if (currentValue) {
    if (currentContentType == 'number' && isNumber != true) {
      isError = true;
    }
  }

  return isError;

}

// ---------------------------------------
// _checkContentSyntax(object)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Form._checkContentSyntax = function(currentFieldInstance) {

  var isError = false;
  var currentContentSyntax = currentFieldInstance.contentSyntax();
  var currentValue = currentFieldInstance.currentValue();
  var regularExpressionEmail = /^\s*[a-zA-Z0-9_][-.a-zA-Z0-9_]*\@[\-a-zA-Z0-9]+(?:\.[\-a-zA-z0-9]+)*\.([a-z]{2,4})\s*$/;
  var regularExpressionDate = /^[0-9]{2}\.[0-9]{2}\.[0-9]{4}$/;
  var regularExpressionPlz = /^[0-9]{5}$/;
  var regularExpressionTelefon = /^[0-9\s-\/\+\(\)]+$/;
  var isEmail = regularExpressionEmail.test(currentValue);
  var isDate = regularExpressionDate.test(currentValue);
  var isPlz = regularExpressionPlz.test(currentValue);
  var isTelefon = regularExpressionTelefon.test(currentValue);

  if (currentValue) {

    if (currentContentSyntax == 'e-mail' && isEmail != true) {
      isError = true;
    }

    if (currentContentSyntax == 'date' && isDate != true) {
      isError = true;
    }

    if (currentContentSyntax == 'plz' && isPlz != true) {
      isError = true;
    }

    if (currentContentSyntax == 'telefon' && isTelefon != true) {
      isError = true;
    }

  }

  return isError;

}

// ------------------------------------------------------------
// toString()
// ------------------------------------------------------------

Form.prototype.toString = function() {
  // zunaechst an Methode der Basisklasse weiterleiten
  return Object.prototype.toString.apply(this);
}




// ============================================================
// Klasse Field
// ============================================================

// ------------------------------------------------------------
// Konstruktor
// ------------------------------------------------------------

// ---------------------------------------
// Field(string)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
function Field(id) {
  // Attribute
  this._id = undefined;
  this._name = undefined;
  this._type = undefined;
  this._className = undefined;
  this._required = false;
  this._contentType = undefined;
  this._contentSyntax = undefined;
  this._defaultValue = undefined;
  this._currentValue = undefined;
  // Initialisierungen
  this.id(id);
  this._setAttributes();
}

// ------------------------------------------------------------
// Zugriffsfunktionen
// ------------------------------------------------------------

// -----------
// id(string)
// -----------
//
// Beschreibung:
// -------------
//   ...
//
Field.prototype.id = function(str) {
  if (arguments.length) {
    if (typeof str != 'string') {
      throw new Error('Field.prototype.id meldet: Argument ist nicht vom Typ string!');
    }
    this._id = str;
  }
  return this._id;
}

// -----------
// name(string)
// -----------
//
// Beschreibung:
// -------------
//   ...
//
Field.prototype.name = function(str) {
  if (arguments.length) {
    if (typeof str != 'string') {
      throw new Error('Field.prototype.name meldet: Argument ist nicht vom Typ string!');
    }
    this._name = str;
  }
  return this._name;
}

// -----------
// type(string)
// -----------
//
// Beschreibung:
// -------------
//   ...
//
Field.prototype.type = function(str) {
  if (arguments.length) {
    if (typeof str != 'string') {
      throw new Error('Field.prototype.type meldet: Argument ist nicht vom Typ string!');
    }
    this._type = str;
  }
  return this._type;
}

// -----------
// className(string)
// -----------
//
// Beschreibung:
// -------------
//   ...
//
Field.prototype.className = function(str) {
  if (arguments.length) {
    if (typeof str != 'string') {
      throw new Error('Field.prototype.className meldet: Argument ist nicht vom Typ string!');
    }
    this._className = str;
  }
  return this._className;
}

// -----------
// required(boolean)
// -----------
//
// Beschreibung:
// -------------
//   ...
//
Field.prototype.required = function(b) {
  if (arguments.length) {
    if (typeof b != 'boolean') {
      throw new Error('Field.prototype.required meldet: Argument ist nicht vom Typ boolean!');
    }
    this._required = b;
  }
  return this._required;
}

// -----------
// contentType(string)
// -----------
//
// Beschreibung:
// -------------
//   ...
//
Field.prototype.contentType = function(str) {
  if (arguments.length) {
    if (typeof str != 'string') {
      throw new Error('Field.prototype.contentType meldet: Argument ist nicht vom Typ string!');
    }
    this._contentType = str;
  }
  return this._contentType;
}

// -----------
// contentSyntax(string)
// -----------
//
// Beschreibung:
// -------------
//   ...
//
Field.prototype.contentSyntax = function(str) {
  if (arguments.length) {
    if (typeof str != 'string') {
      throw new Error('Field.prototype.contentSyntax meldet: Argument ist nicht vom Typ string!');
    }
    this._contentSyntax = str;
  }
  return this._contentSyntax;
}

// -----------
// defaultValue(string)
// -----------
//
// Beschreibung:
// -------------
//   ...
//
Field.prototype.defaultValue = function(str) {
  if (arguments.length) {
    if (typeof str != 'string') {
      throw new Error('Field.prototype.defaultValue meldet: Argument ist nicht vom Typ string!');
    }
    this._defaultValue = str;
  }
  return this._defaultValue;
}

// -----------
// currentValue(string)
// -----------
//
// Beschreibung:
// -------------
//   ...
//
Field.prototype.currentValue = function(str) {
  if (arguments.length) {
    if (typeof str != 'string') {
      throw new Error('Field.prototype.currentValue meldet: Argument ist nicht vom Typ string!');
    }
    this._currentValue = str;
  }
  return this._currentValue;
}

// ------------------------------------------------------------
// Öffentliche Instanzmethoden
// ------------------------------------------------------------

// ---------------------------------------
// xxx(VariablenTypXxx1, VariablenTypXxx2)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//

// ------------------------------------------------------------
// Private Instanzmethoden
// ------------------------------------------------------------

// ---------------------------------------
// _setAttributes()
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Field.prototype._setAttributes = function() {

  var element = document.getElementById(this.id());

  // Name setzen

  if (element.name) {
    this.name(element.name);
  }

  // Typ setzen

  if (element.tagName.toLowerCase() == 'input') {
    this.type(element.type.toLowerCase());
  } else {
    this.type(element.tagName.toLowerCase());
  }

  // Klassenname auslesen

  var elementClassName = element.className;

  this.className(elementClassName);

  // Required setzen

  var regularExpressionRequired = /(^|\s)required($|\s)/;
  var typeRequired = regularExpressionRequired.test(elementClassName);

  if (typeRequired == true) {
    this.required(true);
  }

  // Content-Typ setzen

  var regularExpressionNumber = /(^|\s)number($|\s)/;
  var typeNumber = regularExpressionNumber.test(elementClassName);

  if (typeNumber == true) {
    this.contentType('number');
  }

  // Content-Syntax setzen

  var regularExpressionEmail = /(^|\s)e\-mail($|\s)/;
  var regularExpressionDate = /(^|\s)date($|\s)/;
  var regularExpressionPlz = /(^|\s)plz($|\s)/;
  var regularExpressionTelefon = /(^|\s)telefon($|\s)/;
  var typeEmail = regularExpressionEmail.test(elementClassName);
  var typeDate = regularExpressionDate.test(elementClassName);
  var typePlz = regularExpressionPlz.test(elementClassName);
  var typeTelefon = regularExpressionTelefon.test(elementClassName);

  if (typeEmail == true) {
    this.contentSyntax('e-mail');
  }

  if (typeDate == true) {
    this.contentSyntax('date');
  }

  if (typePlz == true) {
    this.contentSyntax('plz');
  }

  if (typeTelefon == true) {
    this.contentSyntax('telefon');
  }

  // Value setzen

  if (this.type() == 'select') {
    this.defaultValue(element.options[element.options.selectedIndex].value);
  } else {
    this.defaultValue(element.value);
  }

}


// ------------------------------------------------------------
// Öffentliche Klasseneigenschaften
// ------------------------------------------------------------


// ------------------------------------------------------------
// Private Klasseneigenschaften
// ------------------------------------------------------------

Field._registeredElementsList = {};


// ------------------------------------------------------------
// Öffentliche Klassenmethoden
// ------------------------------------------------------------

// ---------------------------------------
// createInstance(string)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Field.createInstance = function(id) {

  if (!id) {
    throw new Error('Field.createInstanceField meldet: Es wurde keine ID übergeben');
  }

  if (Field._registeredElementsList[id]) {
    throw new Error('Field.createInstance meldet: Die ID "' + id + '" ist bereits vergeben.');
  }

  Field._registeredElementsList[id] = new Field(id);

  return Field._registeredElementsList[id];

}

// ---------------------------------------
// getFieldInstanceById(string)
// ---------------------------------------
//
// Beschreibung:
// -------------
//   ...
//
// Beispiel:
// ---------
//   ...
//
Field.getFieldInstanceById = function(id) {
  return Field._registeredElementsList[id];
}

// ------------------------------------------------------------
// Private Klassenmethoden
// ------------------------------------------------------------


// ------------------------------------------------------------
// toString()
// ------------------------------------------------------------

Field.prototype.toString = function() {

  var meinString = '';

  meinString += String('ID: ' + this.id() + '\n');
  meinString += String('Type: ' + this.type() + '\n');
  meinString += String('ClassName: ' + this.className() + '\n');
  meinString += String('Required: ' + this.required() + '\n');
  meinString += String('ContentType: ' + this.contentType() + '\n');
  meinString += String('Value: ' + this.value() + '\n');

  return meinString;

}