  function AjaxRequest(u, cb) {
    this.callback = cb;
    this.url = u;
  }

  AjaxRequest.prototype.send = function() {
    this.request = (window.XMLHttpRequest ? new XMLHttpRequest() : (window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : null));
    var that = this;
    this.request.onreadystatechange = function() {
      that.callback(that);
    }
    this.request.open("GET", this.url, true);
    this.request.send(null);
  }

  function hasEvent(day, events) {
    for (var i=0;i<events.length;++i) {
      if (day == DateFormatter.format(new Date(events[i].startDate), 'j')) {
        return true;
      }
    }
    return false;
  }

  function eventsReceived(req) {
    var request = req.request;
    if (request.readyState == 4) {

      if (request.status == 200) {
        var resultText = request.responseText;
        var result = eval('(' + resultText + ')');

        var x = document.getElementById(req.resultDiv);
        x.innerHTML = "";
        x.style.display = 'block';
        if (req.renderCalendar) {
          var prevMonth = DateFormatter.format(new Date(result.prevMonth), "Ym");
          var month = DateFormatter.format(new Date(result.month), "Ym");
          var monthStr = DateFormatter.format(new Date(result.month), "F Y");
          var nextMonth = DateFormatter.format(new Date(result.nextMonth), "Ym");

          var code = '<table class="cal" cellspacing="0" border="0">';
          
          // navigation
          code += '<tr><td colspan="7" class="cal_nav">';
          code += '<a class="cal_nav" href="#' + req.calendarAnchorName + '" onclick="renderCalendar(\'' + req.resultDiv + '\', \'' + req.targetDiv + '\', \'' + req.targetDivToHide + '\', \'' + req.calendarAnchorName + '\', \'' + req.eventsAnchorName + '\', \'' + prevMonth + '\');return false;">&laquo;</a>';
          code += '<span class="cal_cur_date">' + monthStr + '</span>';
          code += '<a class="cal_nav" href="#' + req.calendarAnchorName + '" onclick="renderCalendar(\'' + req.resultDiv + '\', \'' + req.targetDiv + '\', \'' + req.targetDivToHide + '\', \'' + req.calendarAnchorName + '\', \'' + req.eventsAnchorName + '\', \'' + nextMonth + '\');return false;">&raquo;</a>';
          code += '</td></tr>';
          
          // days header
          code += '<tr>';
          for (i=0;i<7;++i) {
            code += '<th class="cal_day_title">' + DateFormatter.weekFull_nl[i].substr(0, 1) + '</td>';
          }
          code += '</tr>';

          var day = 1;
          var startWeekDay = DateFormatter.startWeekDay(new Date(result.month));
          var lastDayOfMonth = DateFormatter.lastDayOfMonth(new Date(result.month));

          // first row of days
          code += '<tr>';
          for (i=0;i<7;++i) {
            if (i < startWeekDay) {
              code += '<td class="cal_day other">&nbsp;</td>';
            } else {
              if (hasEvent(day, result.events)) {
                code += '<td class="cal_active"><a class="cal_active" href="#' + req.eventsAnchorName + '" onclick="getEvents(\'' + 'eventList' + '\',\'eventList_tpl\', \'' + month + day + '\', \'' + month + (day + 1) + '\');return false;">' + day + '</a></td>';
              } else {
                code += '<td class="cal_day">' + day + '</td>';
              }
              day++;
            }
          }
          code += '</tr>';

          // middle days
          while (day + 7 <= lastDayOfMonth) {
            code += '<tr>';
            for (i=0;i<7;++i) {
              if (hasEvent(day, result.events)) {
                code += '<td class="cal_active"><a class="cal_active" href="#' + req.eventsAnchorName + '" onclick="getEvents(\'' + 'eventList' + '\',\'eventList_tpl\', \'' + month + day + '\', \'' + month + (day + 1) + '\');return false;">' + day + '</a></td>';
              } else {
                code += '<td class="cal_day">' + day + '</td>';
              }
              day++;
            }
            code += '</tr>';
          }

          // last row of days
          finalEmptyFields = day - lastDayOfMonth + 6;
          code += '<tr>';
          while (day <= lastDayOfMonth) {
            if (hasEvent(day, result.events)) {
              code += '<td class="cal_active"><a class="cal_active" href="#' + req.eventsAnchorName + '" onclick="getEvents(\'' + 'eventList' + '\', \'eventList_tpl\', \'' + month + day + '\', \'' + month + (day + 1) + '\');return false;">' + day + '</a></td>';
            } else {
              code += '<td class="cal_day">' + day + '</td>';
            }
            day++;
          }
          for (i=0;i<finalEmptyFields;++i) {
            code += '<td class="cal_day other">&nbsp;</td>';
          }
          code += '</tr>';

          code += '</table>';
          x.innerHTML = code;
        } else {
          if (result.events.length == 0) {
            x.innerHTML = "Geen events gevonden";
          } else {
            var baseContent = document.getElementById(req.sourceDiv).innerHTML;
            for (i=0;i<result.events.length;++i) {
              var line = baseContent;
              line = line.replace(/@ID@/g, result.events[i].id);
              line = line.replace(/@TITLE@/g, result.events[i].title);
              line = line.replace(/@SUMMARY@/g, result.events[i].summary);
              line = line.replace(/@CONTENT@/g, result.events[i].content);
              line = line.replace(/@LOCATION@/g, result.events[i].location);
              line = line.replace(/@STARTDATE@/g, DateFormatter.format(new Date(result.events[i].startDate), 'd-m-y'));
              line = line.replace(/@STARTTIME@/g, DateFormatter.format(new Date(result.events[i].startDate), 'H:i'));
              line = line.replace(/@ENDDATE@/g, DateFormatter.format(new Date(result.events[i].endDate), 'd-m-y'));
              line = line.replace(/@ENDTIME@/g, DateFormatter.format(new Date(result.events[i].endDate), 'H:i'));
              line = line.replace(/@ORGANIZER@/g, result.events[i].organizer);
              x.innerHTML = x.innerHTML + line;
            }
          }
        }
      } else {
        var x = document.getElementById(req.resultDiv);
        x.innerHTML = "";
        x.style.display = 'block';
        x.innerHTML = "Er is een probleem opgetreden in de eventmanager.";
      }
    }
  }

  function eventReceived(req) {
    var request = req.request;
    if (request.readyState == 4) {

      if (request.status == 200) {
        var resultText = request.responseText;
        var result = eval('(' + resultText + ')');

        if (req.customCallback) {
          req.customCallback(result.event);
        }

        var x = document.getElementById(req.resultDiv);
        x.innerHTML = "";
        x.style.display = 'block';
        var baseContent = document.getElementById(req.sourceDiv).innerHTML;
        var line = baseContent;
        line = line.replace(/@ID@/g, result.event.id);
        line = line.replace(/@TITLE@/g, result.event.title);
        line = line.replace(/@SUMMARY@/g, result.event.summary);
        line = line.replace(/@CONTENT@/g, result.event.content);
        line = line.replace(/@LOCATION@/g, result.event.location);
        line = line.replace(/@STARTDATE@/g, DateFormatter.format(new Date(result.event.startDate), 'd-m-y H:i'));
        line = line.replace(/@ENDDATE@/g, DateFormatter.format(new Date(result.event.endDate), 'd-m-y H:i'));
        line = line.replace(/@ORGANIZER@/g, result.event.organizer);
        x.innerHTML = line;
      } else {
        var x = document.getElementById(req.resultDiv);
        x.innerHTML = "";
        x.style.display = 'block';
        x.innerHTML = "Er is een probleem opgetreden in de eventmanager.";
      }
    }
  }

  function getEvents(outputDiv, templateDiv, from, to, max) {
    var url = '/oopwijk/servlet/jsonevent?method=getEvents';
    if (from) {
      url += '&from=' + from;
    }
    if (to) {
      url += '&to=' + to;
    }
    if (max) {
      url += '&max=' + max;
    }

    var ajax = new AjaxRequest(url, eventsReceived);
    ajax.resultDiv = outputDiv;
    ajax.sourceDiv = templateDiv;
    ajax.renderCalendar = false;
    ajax.send();
  }

  function renderCalendar(div, targetDiv, targetDivToHide, calendarAnchorName, eventsAnchorName, month) {
    var url;
    url = '/oopwijk/servlet/jsonevent?method=getEvents&month=' + month;
    var ajax = new AjaxRequest(url, eventsReceived);
    ajax.resultDiv = div;
    ajax.targetDiv = targetDiv;
    ajax.targetDivToHide = targetDivToHide;
    ajax.calendarAnchorName = calendarAnchorName;
    ajax.eventsAnchorName = eventsAnchorName;
    ajax.renderCalendar = true;
    ajax.send();
  }

  function getEvent(id, outputDiv, templateDiv, customCallback) {
    var url;
    url = '/oopwijk/servlet/jsonevent?method=getEvent&id=' + id;
    var ajax = new AjaxRequest(url, eventReceived);
    ajax.resultDiv = outputDiv;
    ajax.sourceDiv = templateDiv;
    ajax.customCallback = customCallback;
    ajax.send();
  }

