// Client-Side Includes. Details and legal notices at    http://csincludes.org
// Copyright (C) 1997-2008 Richard Van Hall, Jr.         http://richhall.com
// NO WARRANTY OF ANY KIND. USE AT OWN RISK.

new(function($global){var $package=this;this.isLoadingTemplate=true;

var isFirefox3 = navigator.userAgent.indexOf('Firefox/3') > -1;

var library = $global.$js2 || ($js2={$id:'js2',$uri:'http://js2.org/'});
var debug = $js2.debug? $js2.debug.log: function(){return ''};

var tags=(navigator.userAgent.indexOf('Firefox')>-1)?function(s){
  // override W3C live NodeList "feature"
  var a=[].slice.call(document.getElementsByTagName(s||'*'));
  return a.length?a:null
}:document.all?function(s){ //IE7 can't handle Firefox fix
  var i,r=[],a=document.getElementsByTagName(s||'*'),l=a.length;
  for(i=0;i<l;i++)if(a[i])r.push(a[i]);
  return r.length?r:null
}:function(s){ //everybody else has more useful non-standard behavior.
  return document.getElementsByTagName(s||'*');
};

var scripts=tags('script'), script=scripts[scripts.length-1]; //self-aware

// Firefox 2 and every other browser allow synchronous script elements,
// except Firefox 3, which breaks `document.write()`, which is essential
// to any cross-browser client-side templating (CST) system.
// The workaround I developed assumes you want to write to the current
// document, not one in another window or frame, and that the variable
// `script` points to the currently-executing script element.
//
var write = isFirefox3? function(s){
  // I'd use a DocumentFragment here, but that didn't work in FF3:
  var e = document.createElement('div'); //div seems to work for head+body.
  e.innerHTML = s;
  while (e.hasChildNodes()){
    script.parentNode.insertBefore( e.firstChild, script );
  }
  delete e; //clean up the temporary element.
}: function(s){
  // No browser except FF3 breaks document.write(), and most execute it
  // faster than the function above, so we use it when we can:
  document.write(s)
};

$package.$export=function(){
  this.$id = 'csi'; this.$uri='http://csincludes.org/';
  this.$lib = library;
  this.URI = URI;
  this.CSI = CSI;
  this.Include = Include;
  this.includes = includes;
  this.include = include;
  //also exports $js2.hf
  return this
}

var CSI=function(o){ //Decoder for CSI-encoded JS/HTML files.
  var t=typeof o;
  //debug('Decoding script');
  if(t=="string"){
    o=o.replace(/(^\-\->|<\!\-\-$)/g,'').replace(/<\!\-\-\s*\-\->/g,'\n');
  }else if(o&&(t=='object')&&!o.nodeType){
    if(o instanceof Array) for(var i=0;i<o.length;i++) o[i]=CSI(o[i]);
    else for(var p in o)o[p]=CSI(o[p]);
  }
  return o
};

var URI=function(u){//try{ //the missing API, fixes IE7
  if(u&&(typeof u=="object")){
    if(u.href){if(!u.host)u.host=location.host;
      if((this==$global)||(this==$package))return u; else u=u.href;
    }else u=URI.serialize(u);
  }
  var a=document.createElement('a');a.title="URI";if(u)a.href=String(u);
  if(!a.host)a.host=location.host;/*IE7*/
  return a;
  //}catch(err){debug('Bug in URI()')}
}
URI.action=function(a){return URI(a).href.replace(/[\#\?].*$/g,'')};
URI.hashless=function(a){a=URI(a);return a.href.replace(a.hash||'#','')};
URI.encode=function(s){return encodeURIComponent(s).replace(/\%20/g,'+')};
URI.decode=function(s){return decodeURIComponent(s).replace(/\+/g,'%20')};
URI.escape=function(s){return encodeURI(s)};
URI.unescape=function(s){return decodeURI(s)};
URI.sanitize=function(s){return s.replace(/[\"\']+/g,'' ).replace(/\-+([a-z])/gi,function(m,a){return a.toUpperCase()}).replace(/[^a-z0-9]+/gi,'_' ).replace(/(^[^a-z]+|_+$)/i,'') || ''};
URI.serialize=function(o){var s=[],p;
  for(p in o)if(p.match(/^[a-z]\w*$/i))s.push(p+'='+URI.encode(o[p]));
  s=s.join('&'); if(o.$action){s=(s?URI.action(o.$action)+'?'+s: URI.action(o.$action))};
  return s
};
URI.unserialize=function(s){var o={$s:s},l=0,q=s.indexOf('?');
  if(q>-1){o.$action=URI.action(s);s=s.substring(q+1,s.length)}
  s=s.replace(/([^\=\&]+)(\=([^\&]*))?(\&|$)/g,function(){var a=arguments;
    if(a[1]) o[URI.sanitize(URI.decode(a[1]))||'$none']=( a[3]? URI.decode(a[3]): a[2]? '': true);
    return '';
  });
  return o
};
URI.path=function(a){return '/'+ URI(a).pathname.replace(/^\/+/,'').replace( /\/[^\/]*\.[^\/]*$/, '')+ '/'};

var path = $js2.$path || ( $js2.$path = URI.path(script.src) );
//alert(path);

//Hyperformats (hf)

var hf = $js2.hf = function(s,p,o){ //was hf.add()
  if(!hf[s]){o.$id=s; o.$priority=p;
    hf[s]=o;
    hf.formats.push(s);
    hf.formats.sort(function(a,b){return (hf[a].$priority||0)-(hf[b].$priority||0)});
  }
  return o
};
hf.formats=[];
hf('markdown',25,{src:'hf/showdown2.js', //
  detect:function(t){return (t.indexOf('markdown')>-1)}
});
hf('crunch',25,{src:'hf/crunch.js', //
  detect:function(t){return (t.indexOf('crunch')>-1)} 
});
hf('jsmin',25,{src:'hf/fulljsmin.js', //
  detect:function(t){return (t.indexOf('jsmin')>-1)} 
});
hf('html',50,{
  detect:function(t){return (t.indexOf('html')>-1)},
  parse:function(){var o=this; if(o.source)o.target=o.source; o.html=o.content=o.toContent(); return o},
  toContent:function(){return this.source? this.source.split( /(?:<\/?body[^>]*>|(?:<\!\-\-)?\s*<a[^>]+(?:id|name)\=\"foot\"[^>]*>[^<]*<\/a>\s*(?:\-\->)?)/gi )[1]||this.source: ''},
  toHTML:function(){return this.html||this.content||this.source||''},
  encode:function(s){return s.replace( /\&/g,'&amp;' ).replace('\\','&#92;' ).replace(/</g,'&lt;' ).replace(/>/g,'&gt;' ).replace(/\"/g, '&quot;' ).replace(/\'/g,'&#39;') },
  decode:function(s){return s.replace(/\&\#39\;/g,"'" ).replace(/\&quot\;/g,'"' ).replace(/\&gt\;/g,'>' ).replace(/\&lt\;/g,'<' ).replace(/\&\#92\;/g,'\\' ).replace(/\&amp\;/g,'&')}
});
hf('js',50,{
  detect:function(t){return t.match(/(?:java|j|ecma|live)script/i)?true:false},
  parse:function(){var o=this;
    if(o.source){try{
      if(document.all)o.source=o.source.replace(/^<\!\-\-[^\n]*\n/,'');
      o.model=eval(o.source);
      //debug('Script for ',o.type,' returned a ',typeof o.model)
    }catch(e){
      debug('Script for ',o.type,' bugged out.')
    }}
    if(o.model && o.source.match(/\/\*\s*http\:\/\/csincludes\.org\s*\*\//i)){
      //debug('Script requires manual CSI decoding.');
      o.model=CSI(o.model);
    }
    o.html=o.content=o.toContent();
    return o;
  },
  toContent:function(){var o=this;
    return (o.model&& (typeof o.model.body=='string'))? o.model.body: ''
  },
  toString:function(){return this.getContent()}
});
hf('plain',75,{
  detect:function(t){return (t.indexOf('text/plain')>-1)}
});

var include=function(u){//try{
  var o=new Include(u);return o.model||o.getHTML() 
  //}catch(err){ debug("Error while loading ",u);return null }
};//PHP?
var includes={};
var Include=function(a,f,r){//try{
  if(this==$global||this==$package)return new Include(a,f,r);
  if(!a)return this; else a=URI(a);
  //debug('Including ',a.rel||a.tagName,' ',a.href);
  if(includes[a.href])r=includes[a.href].request||false; else includes[a.href]=this;
  var m,o=this; o.link=a; o.type=a.type||''; o.href=a.href;
  //debug('File type of ',o.href,' is ',o.type||'not set.');
  if(a.title&&(m=a.title.match(/\#(\w+)(?:\W|$)/))&&m[1]) includes[o.id=m[1]]=o;
  o.onload=(typeof f=="function")? f: (typeof a.ondblclick=="function")? a.ondblclick: false;
  if(r){o.request=r; //piggyback a freeloader on an existing request
    if(r.responseText){
      if(f!==false)o.load();
    }else if(f){
      includes[a.href].freeloaders.push(o); //Firefox bugs out on evt wrapper
    }
  }else{ //send new request
    try{r=new XMLHttpRequest()}catch(e){
    try{r=new ActiveXObject('MSXML3.XMLHTTP')}catch(e){
    try{r=new ActiveXObject('MSXML2.XMLHTTP')}catch(e){
    try{r=new ActiveXObject('Microsoft.XMLHTTP')}catch(e){ }}}}
    if(r&&r.open){
      o.request=r;
      o.freeloaders=[o];
      r.open('GET',a.href,f?true:false);
      //debug('Opening new ',a.href);
      if(f){
        r.onreadystatechange=function(){if(r.readyState==4){
          while(o.freeloaders.length)(o.freeloaders.shift()).load();
        }};
        r.send(null);
      }else{
        r.send(null);
        if(f!==false)o.load()
      }
    }
  }
  return this;
  //}catch(err){debug('Bug in Include()')}
};
Include.prototype={
  extend:function(){//try{
    var o=this,f=null,a=hf.formats,i,p,t;
    //debug('Extending ',o.type,' ',o.href);
    for(i=0; (f=hf[a[i]])&&(!f.detect||!f.detect(o.type||'',o.source||'',o.href||'')); i++);
    if(!f)f=hf.plain; else if(f.src)f=hf[f.$id]=include(path+f.src);
    for(p in f)if(((t=typeof f[p])=="function")||(f[p]&&(t=="object")))o[p]=f[p];
    if(f.toString&&(f.toString!=Object.prototype.toString))o.toString=f.toString;
    //debug('Finished extending ',o.type,' ',o.href);
    return o
    //}catch(err){debug('Bug in Include.prototype.extend')}
  },
  load:function(){//try{
    var o=this, a=o.link, e;
    //debug('Loading ',a.rel||a.tagName,' ',a.href);
    o.source=o.request.responseText||'';
    //debug('Response ',o.source?'found':'missing');
    if(!o.type)o.type=o.request.getResponseHeader('Content-Type')||'text/plain';//
    //debug('Type is ',o.type||'not set.');
    if(o.source){
      o.extend().parse();
      if(a.tagName.toLowerCase()=="a"&&(!a.title||a.title!="URI")){
        try{a.parentNode.replaceChild(o.toElement(),a)}catch(e){
          //debug('Failed Replacement')
        }
      }
    }
    //debug('Trying custom load event...');
    if(typeof o.onload=="function")o.onload();
    o.isLoaded=true
    //debug('Finished loading ',o.type,' ',o.href);
    //}catch(err){debug('Bug in Include.prototype.load()')}
  },
  write:function(d){//try{
    if(!d)d=document;var s=this.toHTML();
    if(d.write)d.write(s);else{try{if(d.body)d=d.body;d.innerHTML+=s}catch(err){}}
    return s
    //}catch(err){debug('Bug in Include.prototype.write()')}
  },
  parse:function(){var o=this;if(o.source)o.content=o.target=o.source;return o},
  getElement:function(){return this.element||(this.element=this.toElement())},
  toElement:function(){//try{
    var o=this, a=o.link, e=document.createElement('div');
    if(a.className)e.setAttribute('class',a.className);
    if(o.id)e.setAttribute('id',o.id);
    e.innerHTML=o.getHTML();return e
    //}catch(err){debug('Bug in toElement()')}
  },
  getHTML:function(){return this.html||(this.html=this.toHTML())},
  toHTML:function(){return Include.asTextarea( String(this), this.id||this.href||'' )},
  getContent:function(){return this.content||(this.content=this.toContent())},
  toContent:function(){return this.source||''},
  getSource:function(){return this.source||(this.source=this.toSource())},
  toSource:function(){return this.source||this.request.responseText||''},
  toString:function(){return this.content||this.source|| this.request.responseText||''}
}
Include.asTextarea=function(s,t,c,r){//try{ //string, title, cols, rows
  if(!c)c=80; if(!s)s='Empty'; if(!t)t='Untitled';
  if(!r){var a=s.split(/\n/g); r=a.length;
    for(var i=0,l=a.length;i<l;i++)r+=Math.floor(a[i].length/c);
    if($global.opera&&opera.postError)r=Math.floor(r*1.018)+1;
    else if(document.all&&document.all.tags)r=Math.floor(r*1.19)+2;
  }
  return ['<textarea title="',t,'" cols="',c,'" rows="',r,'" wrap="virtual" class="csi_source">', hf.html.encode(s), '</textarea>'].join('')
  //}catch(err){debug('Bug in asTextarea')}
};
Include.setup=function(){//try{
  //debug('Setting up Include');
  var l=tags('link'),a=false,r,e,t=false,w,i;
  if(l)for(i=0;(a=l[i])&&!(a.rel&&(a.rel.indexOf('template')>-1));i++);
  //if(!a)a=tags('base')[0]||false;
  if(a&&a.href){
    var o=includes.template=new Include(a,false);
    if(o.request.responseText){
      t=o.source=o.request.responseText;
      t=t.split( /(?:(?:<\!\-\-)?\s*<a[^>]+(?:id|name)\=\"(?:head|neck|body|foot)\"[^>]*>[^<]*<\/a>\s*(?:\-\->)?|<\/head>[^<]*<body[^>]*>|<\/body>)/gi );
      if(t.length!=7)return; 
      o.parts=t;
      write( t[1] );
    }
  }
  w=window.onload||false;window.onload=function(e){if(typeof w=="function")w(e);
    var l,a,i,b,p;
    if(t){
      b=document.body, p=b.innerHTML.split( /<[aA][^>]+(?:id|name|ID|NAME)\=\"?(?:foot|FOOT)(?:[\"\s][^>]*>|>)[^<]*<\/[aA]>/i );
      b.innerHTML=[ '<'+'!-- t[3] --'+'>', t[3], '<'+'!-- p[0] --'+'>', p[0]||'', '<'+'!-- t[4] --'+'>', t[4], '<'+'!-- p[1] --'+'>', p[1]||'', '<'+'!-- t[5] --'+'>', t[5], '<'+'!-- end --'+'>' ].join('\n');
    }
    if(l=tags('link')){
      //debug('Found headlinks...');
      for(i=0;a=l[i];i++){
        //debug('Head link rel="',a.rel||'','"');
        if(a.rel&& (a.rel.indexOf('include')>-1))new Include(a,true);
      }
    }
    if(l=tags('meta')){var m=[' '];
      //debug('Found metas...');
      for(i=0;a=l[i];i++)if(a.name&& (a.name.toLowerCase()=='include-params')) m.push(a.content);
      if(m.length>1){
        m.push(' ');
        m=m.join(' ').split(/\W+/).join(' ');
        var u=URI.unserialize(String(location.href));
        for(var p in u)if(p.match(/^[a-z]\w*$/i)&& (m.indexOf(' '+p+' ')>-1)&& !u[p].match(/(?:^\w*\:|(?:^|\/)\.+\/)/)){
          includes[p]=new Include(u[p],true);
          includes[p].id=p
        }
      }
    }
    if(l=tags('a')){
      for(i=0;a=l[i];i++)if(a.rel&& (a.rel.indexOf('include')>-1))new Include(a,true);
    }
    //if( isFirefox3 ) history.back();
    $package.isLoadingTemplate=false;
    //debug('Window.onload number ',++window.loadCount);
  };
  //debug('Setup number ',++window.setupCount);
  return true
  //}catch(err){debug('Bug in setup()')}
}
//window.setupCount=0;
//window.loadCount=0;
$package.isLoadingTemplate = Include.setup();

return $js2.csi=$package.$export() })(this)