// ein Form ermitteln
function getForm(document, formName)
{
   return document.forms[formName];
}

// ein Feld ermitteln
function getField(document, formName, fieldName)
{
   var form = getForm(document, formName);
   if (form)
   {
      var elements = form.elements;
      var field = elements[fieldName];
      if (field)
      {
         return field;
      }
      else
      {
         var length = elements.length;
         for (var i = 0; i < length; i++)
         {
            var field = elements[i];
            if (field.name == fieldName)
            {
               return field;
            }
         }
      }
   }

   return null;
}

// den Wert eines Feldes ermitteln
function getValue(field)
{
   if (field.type == 'select-one')
   {
      if (field.selectedIndex >= 0)
      {
         return field.options[field.selectedIndex].value;
      }
      else
      {
         return null;
      }
   }
   else
   {
      // TODO: handle other types
      return field.value;
   }
}

// copy all options from one field to another
function copyOptions(from, to)
{
   var length = from.options.length;
   for (var i = 0; i < length; i++)
   {
      var o = from.options[i];
      to.options[i] = new Option(o.text, o.value);
   }
   while (to.options.length > from.options.length)
   {
      to.options[to.options.length - 1] = null;
   }
}

function setValue(field, value)
{
   if (field.type == 'select-one')
   {
      var length = field.options.length;
      for (var i = 0; i < length; i++)
      {
         if (field.options[i].value == value)
         {
            var last = field.selectedIndex;
            field.selectedIndex = i;
            if (i != last && field.onchange)
            {
               field.onchange();
            }
            return;
         }
      }
      // do not change the selection if the value could not be found
   }
   else
   {
      // TODO: handle other types
      var oldValue = field.value;
      field.value = value;
      if (oldValue != value && field.onchange)
      {
         field.onchange();
      }
   }
}

function appendValue(field, value, delimiter)
{
   var v = getValue(field);
   if (delimiter != ' ')
   {
      v = rtrim(v);
   }
   if (v.length > 0 && !endsWith(v, delimiter))
   {
      v += delimiter;
   }
   v += value;
   setValue(field, v);
}

function containsValue(field, value, delimiter)
{
   var v = getValue(field);
   var part = '';
   for (var i = 0; i < v.length; i++)
   {
      var c = v.charAt(i);
      if (c == delimiter)
      {
         if (delimiter != ' ')
         {
            part = trim(part);
         }
         if (value == part)
         {
            return true;
         }
         part = '';
      }
      else
      {
         part += c;
      }
   }
   return (part == value);
}

function setSelectionFromPopup(selection)
{
   var opener = getOpener();
   if (!opener)
   {
      return;
   }

   if (opener.closed)
   {
      return;
   }

   var options = getWindowOptions();
   if (!options)
   {
      return;
   }

   var formName = options.substring(0, options.indexOf(','));
   if (!formName)
   {
      return;
   }

   options = options.substring(options.indexOf(',')+1);
   if (!options)
   {
      return;
   }

   var fieldName = options.substring(0, options.indexOf(','));;
   if (!fieldName)
   {
      return;
   }

   options = options.substring(options.indexOf(',')+1);
   if (!options)
   {
      return;
   }

   var method = options.substring(0, options.indexOf(','));
   if (!method)
   {
      return;
   }

   options = options.substring(options.indexOf(',')+1);
   if (!options)
   {
      return;
   }

   var delimiter = options.charAt(0);

   options = options.substring(2);

   var action = null;
   if (options)
   {
      action = options;
   }

   var field = getField(opener.document, formName, fieldName);

   if (!field)
   {
      return;
   }

   if (startsWith(method, 'set'))
   {
      setValue(field, selection);
   }
   else
   if (startsWith(method, 'appendonce'))
   {
      if (!containsValue(field, selection, delimiter))
      {
         appendValue(field, selection, delimiter);
      }
   }
   else
   if (startsWith(method, 'append'))
   {
      appendValue(field, selection, delimiter);
   }

   if (contains(method, 'close'))
   {
      window.close();
   }

   if (endsWith(method, 'submit'))
   {
      eval('opener.' + action + '();');
   }
}

// prepare the reset fields of a form
function prepareForm(form, resetFieldName)
{
   var elements = form.elements;
   var length = elements.length;
   for (var i = 0; i < length; i++)
   {
      var field = elements[i];
      if (i > 0 && field.name == resetFieldName)
      {
         var previousField = elements[i-1];
         if (previousField)
         {
            if (previousField.disabled)
            {
               field.value = '';
            }
            else
            {
               field.value = previousField.name;
            }
         }
      }
   }
}

// den Focus auf ein bestimmtes Feld setzen
function setFocus(document, formName, fieldName)
{
   var form;
   if (formName)
   {
      form = getForm(document, formName);
   }
   else
   {
      form = document.forms[0];
   }

   var field;
   var visibleIndex = -1;
   var length = form.elements.length;
   for (var i = 0; i < length; i++)
   {
      var f = form.elements[i];
      if (f.type != 'hidden' && !f.disabled)
      {
         visibleIndex++;
         if (!fieldName
             || fieldName == visibleIndex
             || fieldName == f.name
             || (startsWith(fieldName, '*') && endsWith(f.name, fieldName.substring(1)))
             || (endsWith(fieldName, '*') && startsWith(f.name, fieldName.substring(0, fieldName.length()-1))))
         {
            field = f;
            break;
         }
      }
   }

   if (field)
   {
      field.focus();
   }

   return null;
}

// Enter als Submit interpretieren...
function enableEnterDefaultSubmit(document)
{
   if (document.addEventListener)
   {
      document.addEventListener("keypress", _EventHandlerWithParameter_KeyPress, false);
   }
   else
   if (document.captureEvents)
   {
      document.captureEvents(Event.KEYPRESS);
      document.onkeypress = _EventHandlerWithParameter_KeyPress;
   }
   else
   {
      document.onkeypress = _EventHandlerWithoutParameter_KeyPress;
   }
}

function _handleEnterSubmit(target)
{
   if (target.type == 'text'
       || target.type == 'password'
       || target.type == 'checkbox'
       || target.type == 'radio'
       || target.type == 'select-one'
       || target.type == 'select-multiple')
   {
      if (target.form && (!target.form.onsubmit || target.form.onsubmit()))
      {
         target.form.submit();
      }
      return false;
   }
   else
   {
      return true;
   }
}

function _EventHandlerWithParameter_KeyPress(event)
{
   if (event.which == 13)
   {
      if (!_handleEnterSubmit(event.target))
      {
         // stop propagation and prevent the default action
         if (event.stopPropagation)
         {
            event.stopPropagation();
         }
         if (event.preventDefault)
         {
            event.preventDefault();
         }
         return false;
      }
   }
   return true;
}

function _EventHandlerWithoutParameter_KeyPress()
{
   if (event.keyCode == 13)
   {
      return _handleEnterSubmit(event.srcElement);
   }
   return true;
}

// Die normale GET-URL eines Formulars erzeugen
function getFormSubmitUrl(document, formName, append)
{
   var form = getForm(document, formName);
   var result = form.action;
   if (result.indexOf('?') < 0)
   {
      result += '?';
   }
   else
   if (!endsWith(result, '&'))
   {
      result += '&';
   }
   var length = form.elements.length;
   for (var i = 0; i < length; i++)
   {
      var field = form.elements[i];
      var value = getValue(field);
      if (value != null)
      {
         result += escape(field.name) + '=' + escape(value) + '&';
      }
   }
   if (append)
   {
      result += append;
   }

   return result;
}

// DatePicker (by Ole.Keller@eurogate.eu)

function DatePicker(field, element, pattern, texts)
{
   this.field = field;
   this.element = element;
   this.pattern = pattern;
   this.datePattern = this.stripPattern(pattern, 'Hms', 'yMd');
   this.timePattern = this.stripPattern(pattern, 'yMd', 'Hms');
   this.current = this.normalize(new Date());
   this.firstDayOfWeek = parseInt(texts.substring(0, 1));

   var l = parseInt(texts.substring(1, 2));
   this.weekdays = new Array(7);
   for (var d = 0; d < 7; d++)
   {
      this.weekdays[d] = texts.substring(2 + d*l, 2 + d*l + l);
   }

   var s = 2 + 7*l;
   l = parseInt(texts.substring(s, s+1));
   s++;
   this.months = new Array(12);
   for (var m = 0; m < 12; m++)
   {
      this.months[m] = texts.substring(s + m*l, s + m*l + l);
   }

   this.selectMessage = texts.substring(s + 12*l);
}

DatePicker.prototype.stripPattern = function(pattern, strip, keep)
{
   var result = pattern;
   for (var i = 0; i < strip.length; i++)
   {
      result = result.replace(strip.charAt(i), '');
   }

   while (result.length > 0 && keep.indexOf(result.charAt(0)) < 0)
   {
      result = result.substring(1);
   }

   while (result.length > 0 && keep.indexOf(result.charAt(result.length-1)) < 0)
   {
     result = result.substring(0, result.length - 1);
   }

   return result;
}

DatePicker.prototype.normalize = function(date)
{
   if (date.getMinutes() != 0 && date.getMinutes() < 30)
   {
      date.setMinutes(30);
   }
   else
   if (date.getMinutes() > 30)
   {
      date.setHours((date.getHours() + 1) % 24);
      date.setMinutes(0);
   }

   return date;
}

DatePicker.prototype.update = function()
{
   var content = '<table>';
   content += '<tr class="month">';
   content += '<th><a href="javascript:getElement(\'' + this.element.id + '\').datePicker.previousMonth()">&laquo;</a></th>';
   content += '<th colspan="4">' + this.months[this.current.getMonth()] + ' ' + this.current.getFullYear() + '</th>';
   content += '<th><a href="javascript:getElement(\'' + this.element.id + '\').datePicker.hide();">X</a></th>';
   content += '<th><a href="javascript:getElement(\'' + this.element.id + '\').datePicker.nextMonth();">&raquo;</a></th>';
   content += '</tr>';

   content += '<tr class="week">';
   for (var d = 0; d < this.weekdays.length; d++)
   {
      content += '<td>' + this.weekdays[(this.firstDayOfWeek + d) % this.weekdays.length] + '</td>';
   }
   content += '</tr>';

   var first = new Date(this.current.getFullYear(), this.current.getMonth(), 1);
   var prefix = first.getDay() - this.firstDayOfWeek;
   if (prefix < 0)
   {
      prefix += this.weekdays.length;
   }
   content += '<tr class="days">';
   for (var d = 0; d < prefix; d++)
   {
      content += '<td>&#160;</td>';
   }

   var nextYear = this.current.getFullYear();
   var nextMonth = this.current.getMonth();
   nextMonth++;
   if (nextMonth > 11)
   {
      nextMonth = 0;
      nextYear++;
   }
   var last = new Date(new Date(nextYear, nextMonth, 1).getTime() - 86400000);

   for (var d = 1; d <= last.getDate(); d++)
   {
      if ((d + prefix) % 7 == 1)
      {
         content += '<tr class="days">';
      }

      var selected = (d == this.current.getDate());
      content += selected ? '<td class="selected">' : '<td>';
      content += '<a href="javascript:getElement(\'' + this.element.id + '\').datePicker.selectDate(' +  d + ');"';
      if (selected)
      {
         content += ' title="' + this.selectMessage  + '"';
      }
      content += '>' + d + '</a></td>';

      if ((d + prefix) % 7 == 0)
      {
        content += '</tr>';
      }
   }

   var postfix = (this.weekdays.length + this.firstDayOfWeek - last.getDay() - 1) % 7;
   for (var d = 0; d < postfix; d++)
   {
      content += '<td>&#160;</td>';
      if (d == postfix - 1)
      {
        content += '</tr>';
      }
   }

   content += '<tr class="time">';
   content += '<td colspan="4">';
   content += '<a href="javascript:getElement(\'' + this.element.id + '\').datePicker.setValueToField();" '
           + 'title="' + this.selectMessage  + '">' + this.format(this.current, this.datePattern) + '</a>';
   content += '</td>';
   content += '<td colspan="3">';

   if (this.timePattern)
   {
      content += '<select onchange="getElement(\'' + this.element.id + '\').datePicker.selectTime(this);">';
      for (var h = 0; h < 24; h++)
      {
         for (var m = 0; m < 60; m += 30)
         {
            var t = new Date(this.current.getTime());
            t.setHours(h);
            t.setMinutes(m);
            t.set

            content += '<option value="' + h + ':' + m + '"';
            if (this.current.getHours() == h && this.current.getMinutes() == m)
            {
               content += ' selected="selected"';
            }

            content += '>' + this.format(t, this.timePattern) + '</option>';;
         }
      }
      content += '</select>';
   }

   content += '</td>';
   content += '</tr>';

   content += '</table>';
   this.element.innerHTML = content;
}

DatePicker.prototype.previousMonth = function()
{
   var previousYear = this.current.getFullYear();
   var previousMonth = this.current.getMonth();
   previousMonth--;
   if (previousMonth < 0)
   {
      previousMonth = 11;
      previousYear--;
   }

   this.current.setFullYear(previousYear);
   this.current.setMonth(previousMonth);

   this.update();
}

DatePicker.prototype.nextMonth = function()
{
   var nextYear = this.current.getFullYear();
   var nextMonth = this.current.getMonth();
   nextMonth++;
   if (nextMonth > 11)
   {
      nextMonth = 0;
      nextYear++;
   }

   this.current.setFullYear(nextYear);
   this.current.setMonth(nextMonth);

   this.update();
}

DatePicker.prototype.selectDate = function(day)
{
   if (this.current.getDate() == day)
   {
      this.setValueToField();
   }

   this.current.setDate(day);

   this.update();
}

DatePicker.prototype.selectTime = function(field)
{
     var times = field.options[field.selectedIndex].value.split(":");
     this.current.setHours(parseInt(times[0]));
     this.current.setMinutes(parseInt(times[1]));

     this.update();
}

DatePicker.prototype.getValueFromField = function()
{
   var value = getValue(this.field);
   var parsed = this.parse(value, this.pattern);
   if (!parsed && this.datePattern)
   {
      parsed = this.parse(value, this.datePattern);
   }
   if (!parsed && this.timePattern)
   {
      value = this.parse(value, this.timePattern);
   }

   if (parsed)
   {
      this.current = this.normalize(parsed);
   }

   this.update();
}

DatePicker.prototype.parse = function(value, pattern)
{
   var valuePattern = 'yMdHms';
   var values = new Array(valuePattern.length);

   var p = 0;
   var v = 0;
   while (p < pattern.length && v < value.length)
   {
      var c = pattern.charAt(p);
      var valueIndex = valuePattern.indexOf(c);
      if (valueIndex >= 0)
      {
         // determine size of the pattern
         var count = 1;
         p++;
         while (p < pattern.length && pattern.charAt(p) == c)
         {
            p++;
            count++;
         }

         var x;
         if (p >= pattern.length)
         {
            // we have reached the end
            x = value.substring(v);
            v = value.length;
         }
         else
         if (valuePattern.indexOf(pattern.charAt(p)) < 0)
         {
            // we have reached a delimiter
            // find the next delimiter in the value
            var i = v;
            while (i < value.length && !isNaN(parseInt(value.charAt(i))))
            {
               i++;
            }

            var l = i - v;
            if (l == 0 || l > count)
            {
               // not found
               return null;
            }

            x = value.substring(v, v + l);

            // skip the delimiters in pattern and value
            while (p < pattern.length && valuePattern.indexOf(pattern.charAt(p)) < 0)
            {
               p++;
            }
            v = v + l;
            while (v < value.length && isNaN(parseInt(value.charAt(v))))
            {
               v++;
            }
         }
         else
         {
            // fixed length field
            x = value.substring(v, v + count);
            v += count;
         }

         // check consistency
         for (var i = 0; i < x.length; i++)
         {
            if (isNaN(parseInt(x.charAt(i))))
            {
               // garbage
               return null;
            }
         }

         values[valueIndex] = parseInt(x, 10);
      }
      else
      {
         // skip the delimiters in pattern and value
         while (p < pattern.length && valuePattern.indexOf(pattern.charAt(p)) < 0)
         {
            p++;
         }
         while (v < value.length && isNaN(parseInt(value.charAt(v))))
         {
            v++;
         }
      }
   }

   if (p < pattern.length || v < value.length)
   {
      // missing or garbage
      return null;
   }

   var result = new Date();
   if (!isNaN(values[0]))
   {
      if (values[0] < 100)
      {
         values[0] = Math.floor(result.getFullYear() / 100) * 100 + values[0];
      }

      result.setFullYear(values[0]);
   }
   if (!isNaN(values[1]))
   {
      result.setMonth(values[1] - 1);
   }
   if (!isNaN(values[2]))
   {
      result.setDate(values[2]);
   }
   if (!isNaN(values[3]))
   {
      result.setHours(values[3]);
   }
   if (!isNaN(values[4]))
   {
      result.setMinutes(values[4]);
   }
   if (!isNaN(values[5]))
   {
      result.setSeconds(values[5]);
   }

   return result;
}

DatePicker.prototype.format2 = function(value)
{
   if (value < 10)
   {
      return '0' + value;
   }
   else
   {
      return value;
   }
}

DatePicker.prototype.format = function(date, pattern)
{
   var result = pattern;
   result = result.replace(/yyyy/, date.getFullYear());
   result = result.replace(/yy/, this.format2(date.getFullYear() % 100));
   result = result.replace(/MM/, this.format2(date.getMonth() + 1));
   result = result.replace(/dd/, this.format2(date.getDate()));
   result = result.replace(/HH/, this.format2(date.getHours()));
   result = result.replace(/mm/, this.format2(date.getMinutes()));
   result = result.replace(/ss/, this.format2(date.getSeconds()));
   return result;
}

DatePicker.prototype.setValueToField = function()
{
   setValue(this.field, this.format(this.current, this.pattern));
   this.hide();
}

DatePicker.prototype.show = function()
{
   setPageX(this.element, getPageX(this.field) + getWidth(this.field));
   setPageY(this.element, getPageY(this.field));
   this.element.style.display = 'inline';
   this.savedOnclick = document.onclick;
   document.currentDatePicker = this;
   document.onclick = function(event)
   {
      if (!isInside(document.currentDatePicker.element, getEventX(event), getEventY(event)))
      {
         document.currentDatePicker.hide();
      }
   }
}

DatePicker.prototype.hide = function()
{
   document.onclick = this.savedOnclick;
   document.currentDatePicker = null;
   this.element.style.display = 'none';
}

DatePicker.prototype.toggle = function()
{
   if (this.element.style.display == 'inline')
   {
      this.hide();
   }
   else
   {
      this.getValueFromField();
      this.show();
   }
}

function toggleDatePicker(document, formName, fieldName, pattern, texts)
{
   var field = getField(document, formName, fieldName);
   if (!field)
   {
      return;
   }

   var picker = field.datePicker;
   if (!picker)
   {
      var element = getElement(formName + '#' + fieldName + '#datePicker');
      picker = new DatePicker(field, element, pattern, texts);
      element.datePicker = picker;
      field.datePicker = picker;
   }

   picker.toggle();
}
