  var cachedIndex = 0;

  function makeRequest() {
      var request = null;

      try {
          request = new XMLHttpRequest();
      }
      catch( exception ) {
          try {
              request = new ActiveXObject("Msxml2.XMLHTTP");
          }
          catch( exception ) {
              try {
                  request = new ActiveXObject("Microsoft.XMLHTTP");
              }
              catch( exception ) {
                  try {
                      request = window.createRequest();
                  }
                  catch( exception ) {
                      throw "This browser does support the XMLHttpRequest protocol.";
                  }
              }
          }
      }

      return request;
  };

  //-----------------------------------------------

  function handleRequestChange( aRequest, aContext, aUseChildConstruction, anUrl, anIsHistoryRequest ) {
      if( aRequest.readyState == 4 ) {
          try {
              if( aRequest.status == 200 ) {
                  var responseContent = aRequest.responseText;

                  if( responseContent.search( /javascript:/i ) == 0 ) {
                      try {
                          eval( responseContent );
                      }
                      catch( e ) {
                          // TODO, GR: What should we do with the error?
                      }
                  }
                  else {
                      var headerContext = aRequest.getResponseHeader( "ecl_context" );
                      var redirectUrl = aRequest.getResponseHeader( "ecl_redirect_url" );
                      var context = aContext || headerContext;

                      if( iHas( redirectUrl )) {
                          redirectUrl = redirectUrl.toString();
                      }

                      if( !iIsEmpty( headerContext ) && ( context != headerContext )) {
                          context = headerContext;
                      }

                      if( iHas( context )) {
                          context = context.toString();
                      }

                      // INFO, GR:
                      //  We need to retrieve the main frame using the construction below.
                      //  This construction is needed because we introduced the 'ecl_history'
                      //  frame in index.asp (back-button support).
                      var main = null;

                      if( anIsHistoryRequest ) {
                          try {
                              // INFO, GR:
                              //  Changed from window.top.document to parent.document.
                              //  This should resolve a Studieplanner issue.
                              main = parent.document.getElementById( "ecl_main" );
                          }
                          catch(e) {
                              // INFO, GR:
                              //  The try..catch was added for the Studieplanner project.
                              //  Studieplanner is running inside an iFrame on a different server/host
                              //  This can cause an access denied error.
                          }
                      }

                      if( main ) {
                          var mainDocument = main.contentWindow.document;
                          var mainWindow = main.contentWindow;
                      }
                      else {
                          var mainDocument = window.document;
                          var mainWindow = window;
                      }

                      if( !iIsEmpty( context ) && iIsEmpty( redirectUrl )) {
                          var element = mainDocument.getElementById( context );

                          if( iHas( element )) {
                              if( aUseChildConstruction ) {
                                  var newDiv = mainDocument.createElement( "div" );
                                  newDiv.innerHTML = responseContent;
                                  element.appendChild( newDiv );
                              }
                              else
                                  element.innerHTML = responseContent;

                              // INFO, GR: If a specified context is provided... jump to the beginning of the context.
                              mainWindow.location.hash = "anchor_" + context;
                          }
                      }
                      else {
                          if( !iIsEmpty( redirectUrl )) {
                              var topDocument = window.top.document;
                              topDocument.location.replace( redirectUrl );
                          }
                          else {
                              var element = mainDocument.getElementById( "ecl_main_context" );

                              if( iHas( element )) {
                                  element.innerHTML =  responseContent;
                              }
                              else // INFO, GR: When all else fails, we'll just past de response to the document. Dirty but effective.
                                  mainDocument.write( responseContent );
                          }
                      }

                      //--------------------------------------------------------------------------------
                      //-- Browser History support
                      //--------------------------------------------------------------------------------

                      if( !anIsHistoryRequest ) {
                          try {
                              var history = window.top.document.getElementById( "ecl_history" );

                              if( history ) {
                                  var historyDocument = history.contentWindow.document;

                                  if( historyDocument ) {
                                      cachedIndex = parseInt( cachedIndex ) + 1;

                                      history.src = "/misc/history.asp?ecl_title=" + window.top.document.title + "&ecl_index=" + cachedIndex + "&ecl_cache=" + element.id + "&ecl_url=" + encodeURIComponent( anUrl );
                                  }
                                  else
                                      throw "History document not found.";
                              }
                              else
                                  throw "History frame not found.";
                          }
                          catch( exception ) {
                              // INFO, GR:
                              //      The history could not be updated. We'll just ignore the exception and continue.
                          }
                      }

                      //--------------------------------------------------------------------------------
                      //--------------------------------------------------------------------------------

                  }
              }
              else
                  throw "An unknown error occured while executing the XMLHTTPRequest method. Error: " + responseContent;
          }
          catch( exception ) {
              var errorMessage = (typeof(exception) == "string") ? exception : exception.description;

              if( !iIsEmpty( errorMessage ) && !iIsEmpty( errorPageName )) {
                  var url = addQueryStringParameter( errorPageName, "message=" + encodeURIComponent( errorMessage ));

                  try {
                      gotoLocation( url );
                  }
                  catch( exception2 ) {
                      writeError( errorMessage, responseContent );
                  }
              }
              else
                  writeError( errorMessage, responseContent );
          }
          finally {
              updateStateImage( "done" );

              try {
                  if( handleProjectSpecificJavascript ) {
                      handleProjectSpecificJavascript( aRequest.responseText, context, anUrl );
                  }
              }
              catch(e) {}
          }
      }
  };

  //-----------------------------------------------

  function sendRequest( anUrl, aContext, aType, aParameters, aUseChildConstruction, aCallSynchronous, anIsHistoryRequest ) {
      var url = anUrl;
      var requestType = aType || "GET";
      var callAsynchronous = (aUseChildConstruction && aCallSynchronous) ? false : true;
      var localContext = iIsNil( aContext ) ? null : trim( aContext );
      var request = null;

      if( localContext != "ecl_download" ) {
          request = makeRequest();
          request.open( requestType, url, callAsynchronous );
          request.onreadystatechange = function() { handleRequestChange( request, localContext, aUseChildConstruction, url, (anIsHistoryRequest || (requestType == "POST"))); };

          if( requestType == "POST" ) {
              request.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" );
              //request.setRequestHeader( "Content-length", aParameters.length );

              url = addQueryStringParameter( url, "registerPage=false" );
          }

          updateStateImage( "loading" );

          try {
              request.sendAsBinary( aParameters );
          }
          catch( exception ) {
              request.send( aParameters );
          }

          return false;
      }
      else {
          if( aParameters != undefined ) {
              url = addQueryStringParameter( url, aParameters );
          }

          gotoLocation( url );

          return false;
      }
  };

  //-----------------------------------------------

  function sendHistoryRequest( anUrl, aContext ) {
      sendRequest( anUrl, aContext, null, null, null, null, true );
  };

  //-----------------------------------------------

  function submitForm( aFormName, anUrl, aContext ) {
      var radioButtons = new Array();
      var parameters = "";
      var parameter = "";
      var element = null;
      var isValid = true;

      if( !iIsEmpty( aFormName )) {
          var form = document.getElementById( aFormName );
          var elements = form.elements;
          var index = 0;
          var length = elements.length;

          for( ; index < length; index++ ) {
              element = elements[index];
              isValid = true;

              if( element.type == "radio" ) {
                  isValid = validateRadioButtonsForName( element.id );

                  if( !isValid && !containsElement( radioButtons, element.id )) {
                      parameters += !iIsEmpty( parameters ) ? "&" : "";
                      parameters += element.id + "=";

                      radioButtons.push( element.id );
                  }
              }

              if( isValid ) {
                  parameter = parameterForElement( element );

                  if( !iIsEmpty( parameter )) {
                      parameters += iIsEmpty( parameters ) ? parameter : "&" + parameter;
                  }
              }
          }
      }

      sendRequest( anUrl, aContext, "POST", parameters );
  }

  //-----------------------------------------------

  function uploadFile( formName, action ) {
      try {
          var form = document.getElementById( formName ) || documents.forms[formName];

          // INFO, GR:
          //      We only need the action page here. We'll extract the action page name
          //      and add the needed parameters.
          var actionParts = form.action.split( '?' );
          var formAction = addQueryStringParameter( actionParts[0], "ecl_is_binary_action=true&action=" + action );
          form.action = formAction;

          if( form.encoding ){
              form.encoding = "multipart/form-data";
          }
          else
              form.enctype = "multipart/form-data";

          updateStateImage( "loading" );

          return true;
      }
      catch( exception ) {
          return false;
      }
  };

  //-----------------------------------------------

  function parameterForElement( element ) {
      var value = "";
      var elementId = element.id;
      var elementValue = element.value;
      var elementType = element.type;

      if( elementType == "checkbox" ) {
          if( !iIsEmpty( elementValue ) && ( elementValue != "true" ) && ( elementValue != "false" ) && ( element.checked )) {
              value = elementId + "=" + elementValue;
          }
          else if( iIsEmpty( elementValue ) || ( elementValue == "true" ) || ( elementValue == "false" )) {
              value = elementId + "=";

              if (element.checked) {
                  value = value + element.checked;
              }
          }

      }
      else if(( elementType == "radio" ) && ( element.checked )) {
          value = elementId + "=" + elementValue;
      }
      else if( elementType == "select-multiple" ) {
          var selectedOptions = "";
          var options = element.options;
          var option = null;
          var index = 0;
          var length = options.length;

          for( ; index < length; index++ ) {
              option = element.options[index];

              if( option.selected ) {
                  selectedOptions += !iIsEmpty( selectedOptions ) ? ", " : "";
                  selectedOptions += option.value;
              }
          }

          if( !iIsEmpty( selectedOptions )) {
              value = elementId + "=" + selectedOptions;
          }
      }
      else if(( elementType != "button" ) && ( elementType != "submit" ) && ( elementType != "reset" ) && ( elementType != "checkbox" ) && ( elementType != "radio" )) {
          // INFO, GR: FireFox only uses LF's. We need to insert the CR's here.
          if((elementType == "textarea") && !isInternetExplorer()) {
              value = elementValue.replace( /\n/ig, "\r\n" );
              value = elementId + "=" + escape( value );
          }
          else
              value = elementId + "=" + encodeURIComponent( elementValue );

          // INFO, GR: Euro and '+' symbols need special treatment, because theye are not encoded by the escape method.
          value = value.replace( /%u20AC/ig, encodeURIComponent( /*"%u20AC"*/ "&euro;" ));
          value = value.replace( /[+]/ig, encodeURIComponent( "+" ));
      }

      return value;
  };

  //-----------------------------------------------

  function validateRadioButtonsForName( elementName ) {
      var radioElements = document.getElementsByName( elementName );
      var index = 0;
      var length = radioElements.length;

      for( ; index < length; index++ ) {
          var radioElement = radioElements[index];

          if( radioElement.checked ) {
              return true;
          }
      }

      return false;
  };

  //-----------------------------------------------

  function containsElement( elements, elementName ) {
      var index = 0;
      var length = elements.length;

      for( ; index < length; index++ ) {
          if( elements[index] == elementName ) {
              return true;
          }
      }

      return false;
  };

  //-----------------------------------------------

  function addQueryStringParameter( url, value ) {
      var tempUrl = url;
      var lastChar = tempUrl.charAt( tempUrl.length-1 );

      if(( lastChar != "?" ) && ( lastChar != "&" )) {
          tempUrl += (tempUrl.indexOf( "?" ) == -1) ? "?" : "&";
      }

      if( !iIsEmpty( value )) {
          tempUrl += value;
      }

      return tempUrl;
  };

  //-----------------------------------------------

  function updateStateImage( aState ) {
      try {
          var imageSource = "";
          var stateImageElement = document.getElementById( "ecl_state_image" );

          if( iHas( stateImageElement )) {
              if( aState == "done" ) {
                  imageSource = getImageSourceDone() || "";
                  document.body.style.cursor = "auto";
              }
              else {
                  document.body.style.cursor = "wait";
                  imageSource = getImageSourceLoading() || "";
              }

              if( !iIsEmpty( imageSource )) {
                  stateImageElement.src = imageSource;
              }
          }

          if( aState == "done" ) {
              document.body.style.cursor = "auto";
          }
          else {
              document.body.style.cursor = "wait";
          }

          return true;
      }
      catch( exception ) {
          return false;
      }
  };

  //-----------------------------------------------
  // private functions
  //-----------------------------------------------

  function trim( value ) {
      var localValue = value.replace(/^\s+/,'');
      return localValue.replace(/\s+$/,'');
  };

  //-----------------------------------------------

  function iIsNil( anObject ) {
      return (anObject == null);
  };

  //-----------------------------------------------

  function iHas( anObject ) {
      return (anObject != null);
  };

  //-----------------------------------------------

  function iIsEmpty( anObject ) {
      return (anObject == null) || (anObject === '');
  };

  //-----------------------------------------------

  function writeError( aMessage, aContent ) {
      window.document.write( '<font style="color:#FF0000; font-weight: bold;">' + aMessage + '<br>Response generated:<br><br></font>' + aContent );
  };

  //-----------------------------------------------

  function gotoLocation( url ) {
      try {
          window.navigate( url );
      }
      catch( exception ) {
          window.open( url, "_self", "", false );
      }
  };

  //-----------------------------------------------

