C5 = window.C5 || {};

// ******** C5 Functional ************
C5.Functional = (function() {
  var publix = {};
  function as(a,s,e) { return Array.prototype.slice.apply(a,e?[s,e]:(s?[s]:[0])); }

  publix.forEach = function(f,a) { 
    if (a.forEach) a.forEach(f); 
    else for (var i=0,l=a.length; i<l; i++) f(a[i]); }

  publix.map = function(f,a) { 
    if (a.map) return a.map(f);  
    var b=[]; for (var i=0,l=a.length; i<l; i++) b.push(f(a[i])); return b; }

  publix.forKVPair = function(f,o) { for (var k in o) if (o.hasOwnProperty(k)) f(k,o[k]); }
  publix.curry = function(f) { var a=as(arguments,1); return function(){return f.apply(this,a.concat(as(arguments)));}}
  publix.choosef = function(t,f1,f2) {
    return function(){return (t.apply(this,arguments)?f1.apply(this,arguments):f2.apply(this,arguments));}}
    
  publix.sequence = function() {
    var args = arguments, next = function() { 
      var f=args[0]; 
      if (f) { args = as(args,1); f.apply(this,[next].concat(as(arguments))); }; 
    }
    return next;
  }
  
  var forEach = publix.forEach, curry = publix.curry, sequence = publix.sequence;
  
  return publix })();

// ******** C5 Request ************
C5.Request = (function() {
  var publix = {}, Fun=C5.Functional, each = Fun.forEach, forkv = Fun.forKVPair, map = Fun.map, cur=Fun.curry,
                   choosef=Fun.choosef;
  
  publix.parseJSON = function(str) { return (new Function('return ('+str+')'))(); }
  publix.encode = function(o) {
    var a = [], 
      isArray = function(o) {return (Object.prototype.toString.call(o) === '[object Array]')},
      addPair = function(k,v) { a.push(escape(k) + '=' + escape(v)) };
    forkv(function(key,value) { choosef(isArray,cur(each,cur(addPair,key)),cur(addPair,key))(value); }, o);
    return a.join('&');
  }

  publix.request = function( method, content, headers, url, handler, error_handler ) {    
    var xhr =  window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
    xhr.onreadystatechange = function() {
      if ( xhr.readyState < 4 )
        return;
      if ( ( !xhr.status && location.protocol == "file:") ||
        ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223 )
        handler(xhr.responseText);
      else if (error_handler)
        error_handler(xhr)
      else
        throw "Could not load file at " + url;
    };
    xhr.open(method, url, true );
    if (headers) for (var k in headers) xhr.setRequestHeader(k, headers[k]);
    if ("POST" == method)
      xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
    xhr.send(content);
  }

  return publix  })();
  
// ******** C5 Template ************
C5.Template = (function() {
  var publix = {};

  var templatize = publix.templatize = function( re, parameterizer, str ) {
    re.lastIndex = 0;
    var index = 0, li = 0, txt=[], variables = [];
    for ( var m = re.exec(str); m; m = re.exec(str) ) {
      txt[index++] = str.substring(li,m.index);
      variables[index++] = parameterizer(m);
      li = re.lastIndex;
    }
    txt[index++] = str.substring(li);
    return function(o) {
      for (var i=1, l=variables.length; i < l; i += 2) txt[i] = variables[i](o);
      return txt.join('');
    }
  }

  return publix;
  })();
  
// ******** C5 Dom ************
var Dom = C5.Dom = (function() {
  var publix = {};
  
  var el = publix.el = function(id) { return document.getElementById(id); }
  
  publix.event = function(f) { return function(e) { f(e || window.event); }; }

  publix.lastevent = function(f) { 
    return function(e) { 
      var e = e || window.event; 
      if ( e.preventDefault ) e.preventDefault(); e.cancelBubble = true; 
      if (e.stopPropagation) e.stopPropagation();  f(e); return false
    }
  }

  publix.offset = function(el) {
    var o = {top:el.offsetTop-el.scrollTop+document.body.scrollTop, 
             left:el.offsetLeft-el.scrollTop+document.body.scrollLeft, 
             width:el.offsetWidth, height:el.offsetHeight }
    for (var p = el.offsetParent; p; p = p.offsetParent) {
      o.top += p.offsetTop - p.scrollTop; 
      o.left += p.offsetLeft - p.scrollLeft;
    }
    return o;
  }
  
  publix.target = function(e) {
    var targ;
    if (e.target) targ = e.target;
    else if (e.srcElement) targ = e.srcElement;
    if (targ && targ.nodeType == 3)
      targ = targ.parentNode;
    return targ;
  }
  
  
  return publix; })();
