/**
 * Request Handler
 * Work with parameters that can come from URIs, window objects or cookies
 * Relocate a window to a newly built address
 *
 * @package     widgets
 * @author      Dieter Raber <raber@h2a.lu>
 * @copyright   Dieter Raber 26.07.2007 11:12:47
 *
 * $Id: requestHandler.js 17 2007-08-07 13:08:02Z dieter $
 */
function requestHandler(res){
  /* setting up the object
   *****************************************/
  res = res || window;
  this.hash     = '';
  this.search   = '';
  this.protocol = '';
  this.port     = '';
  this.fileName = '';
  this.fileExt  = '';

  if(typeof(res) == 'object') {
    for(prop in res.location) {
      if(typeof(res.location[prop]) != 'function') {
        this[prop] = res.location[prop];
      }
    }
    var pathArr   = this.pathname.split('/');
    this.baseUri  = this.protocol + '//' + this.host + this.pathname;
    this.window   = res;
  }
  else if(typeof(res) == 'string') {
    // complete an incomplete uri
    if(res.indexOf('://') == -1) {
      // cut off a possible ./ at the beginning
      if(res.substring(0,2) == './') {
        res = res.substring(2);
      }
      // if string starts with /, protocol and host are missing
      if(res.substring(0,1) == '/') {
        res = window.location.protocol + '//' + window.location.host + res;
      }
      // relative to absolute
      else if(res.substr(0,3) == '../') {
        // window.pathname without possible file name
        var windowPart    = window.location.href.length != window.location.href.lastIndexOf('/')
                          ? window.location.href.substring(0, window.location.href.lastIndexOf('/'))
                          : window.location.href;
        var windowPathArr = windowPart.split('/');
        var uriPathArr    = res.split('/');
        var uriPath = '';
        for(var i = 0; i < uriPathArr.length; i++) {
          if(uriPathArr[i] == '..') {
            windowPathArr.pop();
          }
          else {
            uriPath += uriPathArr[i] + '/';
          }
        }
        if(windowPathArr.length < 3) {
          throw "requestHandler says: Too many ../ in argument";
          return false;
        }
        res = windowPathArr.join('/') + '/' + uriPath.substring(0, uriPath.length - 1);
      }
      // #foo only
      else if(res.substring(0,1) == '#') {
        res = window.location.protocol + '//' + window.location.host + window.location.pathname + res;
      }
      // get only
      else if(res.substring(0,1) == '?') {
        res = window.location.protocol + '//' + window.location.host + window.location.pathname + res;
      }
      else {
        // if res contains a file name, it must be discarded from the current url
        if(window.location.pathname.length == window.location.pathname.lastIndexOf('/')) {
          res = window.location.href + res;
        }
        else {
          res = window.location.href.substring(0, window.location.href.lastIndexOf('/') + 1) + res;
        }
      }
    }
    // now all sorts of uri are complete with host etc.
    this.href = res;

    // hash, see anchor for hash without #
    if(res.indexOf('#') > - 1) {
      this.hash = res.substring(res.indexOf('#'));
      res = res.substring(0, res.indexOf('#'));
    }

    // search, see getPara for getParas-parameters as hashtable
    if(res.indexOf('?') > - 1) {
      this.search = res.substring(res.indexOf('?'));
      res = res.substring(0, res.indexOf('?'));
    }

    // protocol
    this.protocol = res.substring(0, res.indexOf(':') + 1);
    res = res.substring(res.indexOf(':') + 3);

    // discard username and password
    if(res.indexOf('@') != -1) {
      res = res.substring(res.indexOf('@') + 1);
    }

    // plain uri without parameters
    this.baseUri = this.protocol + '//' + res;

    // host, hostname, port
    var pathArr = res.split('/');
    this.host     = pathArr[0];
    this.hostname = pathArr[0];
    if(pathArr[0].indexOf(':') != -1) {
      var hostArr   = pathArr[0].split(':');
      this.port     = hostArr[1];
      this.hostname = hostArr[0];
    }

    // pathname
    this.pathname = res.replace(this.host, '');

    // window to relocate
    this.window = window;
  }
  else {
    return;
  }
  // like hash, but without #
  this.anchor = this.hash.replace('#', '');

  // getParas-parameters as hashtable
  this.getParas = {};
  var tmpObj    = this.search.replace('?', '').split('&');
  for(var i = 0; i < tmpObj.length; i++) {
    tmpObj[i] = tmpObj[i].split('=');
    this.getParas[tmpObj[i][0]] = tmpObj[i][1]
              ? decodeURI(tmpObj[i][1].replace(/\+/g, ' '))
              : '';
  }

  // like protocol, but without :
  this.plainProtocol = this.protocol.replace(':', '');

  // file name
  if(pathArr.length > 1) {
    var dotPos = pathArr[(pathArr.length - 1)].lastIndexOf('.');
    if(((pathArr[(pathArr.length - 1)]).length - dotPos < 7) && (dotPos != -1)) {
      this.fileName = pathArr[pathArr.length -1];
    }
  }

  // file extension
  if(this.fileName.indexOf('.') !=  - 1) {
    this.fileExt = this.fileName.substring(this.fileName.lastIndexOf('.') + 1);
  }

  // cookies
  this.cookieParas = {};
  var cookieStr = document.cookie ? document.cookie.replace(/; /g, ';') : '';
  if(cookieStr) {
    var tmpObj = cookieStr.split(';');
    for(var i = 0; i < tmpObj.length; i++) {
      tmpObj[i].indexOf('=') > -1 ? tmpObj[i] : tmpObj[i] + '=';
      tmpObj[i] = tmpObj[i].split('=');
      this.cookieParas[tmpObj[i][0]] = tmpObj[i][1];
    }
  }

  /* Functions to deal with get and cookie parameters
   ****************************************************/
  // unset a specific parameter or all parameters
  this.unset = function(type, para) {
    if(para) {
      switch(type) {
        case 'get' :
          delete this.getParas[para];
          return true;
        case 'cookie' :
          document.cookie = para + '=; expires=-1;';
          delete this.cookieParas[para];
          return true;
        default:
          return false;
      }
    }
    else {
      switch(type) {
        case 'get' :
          this.getParas = {};
          return true;
        case 'cookie' :
          for(prop in this.cookieParas) {
            document.cookie = prop + '=; expires=-1; path=/';
          }
          this.cookieParas = {};
          return true;
        default:
          return false;
      }
    }
  }

  // change the value of a parameter or set a new one
  // if the third parameter is set to true, all other parameters will be unset first
  this.handle = function(arg1, arg2, days, clear, type) {
    if(!type) { return; }

    var tmpObj = {};

    if(clear) {
      this.unset(type);
    }
    if(!arg2 && typeof(arg1) == 'string') {
      if(type == 'get') {
        return this.getParas[arg1];
      }
      else if(type == 'cookie') {
        return this.cookieParas[arg1];
      }
      return false;
    }
    else if(typeof(arg1) == 'string' && typeof(arg2) == 'string') {
      tmpObj[arg1] = arg2;
    }
    else if(typeof(arg1) == 'object') {
      tmpObj = arg1;
    }
    else {
      return false;
    }
    if(tmpObj) {
      for(prop in tmpObj){
        if(type == 'get') {
          this.getParas[prop] = tmpObj[prop];
        }
        else if(type == 'cookie') {
          this.cookieParas[prop] = tmpObj[prop];
          var cookieStr = prop + '=' + this.cookieParas[prop];
          if (days) {
            var date = new Date();
            date.setTime(date.getTime() + (days * 86400000));
            cookieStr += '; expires=' + date.toGMTString();
          }
          else {
            cookieStr += '; expires=; path=/';
          }
          document.cookie = cookieStr;
        }
      }
    }
  }

  this.get = function(arg1, arg2, clear) {
    arg1  = arg1  || '';
    arg2  = arg2  || '';
    clear = clear || false;
    return this.handle(arg1, arg2, '', clear, 'get');
  }

  this.cookie = function(arg1, arg2, days, clear) {
    arg1  = arg1  || '';
    arg2  = arg2  || '';
    days  = days  || '';
    clear = clear || false;
    return this.handle(arg1, arg2, days, clear, 'cookie');
  }
    

  // relocate the window to the new res
  this.relocate = function(cwp) {
    var cwp = cwp || new Object();
    var wp = {
      conf     : cwp.conf  || false,
      get      : cwp.get   || false,
      clear    : cwp.clear || false,
      uri      : cwp.uri   || false,
      hash     : cwp.hash  || false
    }

    if(wp.conf && !confirm(wp.conf)) {
      return false;
    }

    // delete existing get parameters, if needed
    if(wp.clear) { this.unset('get'); }

    // split in base url, get and anchor
    if(wp.uri) {
      if(wp.uri.indexOf('#') > -1) {
        wp.hash = wp.uri.substring(wp.uri.indexOf('#') + 1);
        wp.uri  = wp.uri.substring(0, wp.uri.indexOf('#'));
      }
      if(wp.uri.indexOf('?') > -1) {
        var queryStr = wp.uri.substring(wp.uri.indexOf('?') + 1);
        this.unset('get');
        var i = 0;
        var tmpObj = queryStr.split('&');
        for(var i = 0; i < tmpObj.length; i++) {
          tmpObj[i] = tmpObj[i].split('=');
          this.getParas[tmpObj[i][0]] = tmpObj[i][1]
                    ? decodeURI(tmpObj[i][1].replace(/\+/g, ' '))
                    : '';
        }
        wp.uri = wp.uri.substring(0, wp.uri.indexOf('?'));
      }
    }
    else {
      wp.uri = this.baseUri;
    }

    // add get paras if needed
    if(typeof(wp.get) == 'object') {
      this.get(wp.get);
    }

    // build the query string
    var paraStr     = '';
    for(var para in this.getParas) {
      paraStr += para + '=' + this.getParas[para] + '&';
      i++;
    }
    if(paraStr) {
      paraStr = '?' + paraStr.substring(0, paraStr.length -1);
    }

    // add the anchor if needed
    if(wp.hash) {
      paraStr += wp.hash;
    }

    wp.uri += paraStr;
    this.window.location.href = wp.uri;
    return true;
  }
}
