//==============================================================================
//	Log
//==============================================================================
var DEBUG = 10;
var INFO = 8;
var WARN = 6;
var ERROR = 4;
var FATAL = 1;

function log( level, message ) {
}
function f_clientWidth() {
	return f_filterResults (
		window.innerWidth ? window.innerWidth : 0,
		document.documentElement ? document.documentElement.clientWidth : 0,
		document.body ? document.body.clientWidth : 0
	);
}
//==============================================================================
//	Utils
//==============================================================================
function f_clientHeight() {
	return f_filterResults (
		window.innerHeight ? window.innerHeight : 0,
		document.documentElement ? document.documentElement.clientHeight : 0,
		document.body ? document.body.clientHeight : 0
	);
}
function f_scrollLeft() {
	return f_filterResults (
		window.pageXOffset ? window.pageXOffset : 0,
		document.documentElement ? document.documentElement.scrollLeft : 0,
		document.body ? document.body.scrollLeft : 0
	);
}
function f_scrollTop() {
	return f_filterResults (
		window.pageYOffset ? window.pageYOffset : 0,
		document.documentElement ? document.documentElement.scrollTop : 0,
		document.body ? document.body.scrollTop : 0
	);
}
function f_filterResults(n_win, n_docel, n_body) {
	var n_result = n_win ? n_win : 0;
	if (n_docel && (!n_result || (n_result > n_docel)))
		n_result = n_docel;
	n_result = n_body && (!n_result || (n_result > n_body)) ? n_body : n_result;
	
//	alert( n_win + ":" + n_docel + ":" + n_body + "->" + n_result );

	return n_result;
}
//==============================================================================
//	Helpers
//==============================================================================
function cstTestNode( node, nodeName, attrName, attrValue ) {
	if( node.nodeType != 1 ) {
		return false;
	}
	
	if( nodeName ) {
		if( nodeName instanceof Array ) {
			if( nodeName.indexOf( node.nodeName ) < 0  ) {
				return false;
			}
		} else {
		
			if( nodeName != node.nodeName ) {
				return false;
			}
		}
	}
	
	if(( attrName != null ) && ( ! node.hasAttribute( attrName ))) {
		return false;
	}
	
	if(( attrValue != null ) && ( node.getAttribute( attrName ) != attrValue )) {
		return false;
	}
	
	return true;
}

function cstFindAllTagsLike( startNode, nodeName, attrName, attrValue, goDeep ) {
	var result = new Array();	
	var cursor = startNode.firstChild;	
	while( cursor != null && cursor != startNode ) {
		var goDeepNow = true;
		if( cstTestNode( cursor, nodeName, attrName, attrValue )) {
			result[ result.length ] = cursor;
			goDeepNow = goDeep;			
		}
		
		if( goDeepNow && cursor.firstChild ) {
			cursor = cursor.firstChild;
			continue;
		} else if( cursor.nextSibling ) {
			cursor = cursor.nextSibling;
			continue;
		}
		
		while( cursor && ( ! cursor.nextSibling ) && ( cursor != startNode )) {
			cursor = cursor.parentNode;			
		}

		if( ! cursor ) {
			break;
		}
		
		if( cursor != startNode ) {
			cursor = cursor.nextSibling;
		} 
	}

	return result;
}

function adoptAllChildren( newParent, oldParent, andClone ) {
	var aChild = oldParent.firstChild;
	while( oldParent.firstChild ) {
		var nextChild = aChild.nextSibling;
		newParent.appendChild( andClone ? cloneNode( aChild, true ) : aChild );
		aChild = nextChild;
	}
}

function cstValue( value ) {
	value = ( value.charAt( 0 ) == '%' ) ? decodeURI( value ) : value;
	if( value.charAt( 0 ) == '{' && value.charAt( value.length - 1 ) == '}' ) {
		return eval( value.slice( 1, -1 ));
	} else {
		return value;
	}	
}

function cstAttribute( cstTag, attrName, defaultValue ) {
	var attrValue = cstTag.getAttribute( attrName );
	
	if( attrValue == null ) {		
		return defaultValue ? defaultValue : null;
	}
	
	attrValue = cstValue( attrValue );	
	return attrValue;
}

function cstCSSNameToJS( cssName ) {
	var parts = cssName.split( "-" );
	var result = parts[0];
	for( var i = 1; i < parts.length; i++ ) {
		result = result + parts[ i ].charAt( 0 ).toUpperCase() + parts[ i ].slice( 1 );
	}
	
	return result;
}

function cstBaseURL( url ) {
	var result = url;
	if( result.indexOf( "?" ) > 0 ) {
		result = result.substring( 0, result.indexof( "?" ));
	}
	if( result.lastIndexOf( "/" ) > 0 ) {
		result = result.substring( 0, result.lastIndexOf( "/" ));
	}
	
	return result;
}

function cstParseURL() {
	log( "Parsing URL : START " );
	
	try {
		var result = new Object();

		var location = window.location;
		if( location.protocol == "file:" ) {
			result._base_ = "file://" + location.pathname + location.search;
		} else {
			result._base_ = "" + window.location.href;
		}
		
		log( "Parsing URL : _base_ = " + result._base_ );

		var qmarkIndex = result._base_.indexOf( "?" );		
		
		if( qmarkIndex > 0 ) {
			result._search_ = result._base_.substring( qmarkIndex + 1 );

			result._base_ = result._base_.substring( 0, qmarkIndex );
			
			var parts = result._search_.split( "&" );
			for( var i = 0;i < parts.length; i++ ) {
				var subParts = parts[ i ].split( "=" );
				
				result[ subParts[ 0 ]] = subParts[ 1 ];
			}
		} 
		result._self_ = result._base_;

		log( "Parsing URL : _self_ = " + result._base_ );

		result._base_ = result._base_.substring( 0, result._base_.lastIndexOf( "/" ));
		
		
	} catch ( e ) {
		log( "Parsing URL : EXCEPTION " + e );
	}
	
	log( "Parsing URL : DONE" + result);
	
	return result;
}

var URL = cstParseURL();


function cstFixURLs( start, tagName, baseURL, deltaURL ) {
	var allTags = cstFindAllTagsLike( start, tagName, null, null, true );
	$A( allTags ).each (
		function( aTag ) {
			var url = aTag.src ? aTag.src : aTag.href;
			
			if( url.indexOf( baseURL ) == 0 ) {			
				url = baseURL+ "/" + deltaURL + "/" + url.substring( baseURL.length + 1 );
				if( aTag.src ) {
					log( "csiFixURLs : " + aTag.src + " -> " + url );
					aTag.src = url;				
				} else {
					log( "csiFixURLs : " + aTag.href + " -> " + url );
					aTag.href = url;
				}
			}
		}
	);
}

var references = new Object();

function cstFixReferences( start, baseURL, deltaURL ) {
	var allTags = cstFindAllTagsLike( start, "A", null, null, true );
	$A( allTags ).each (
		function( aTag ) {
			var url = aTag.href;
			var referenceURL = deltaURL + "/" + url.substring( baseURL.length + 1 );
			
			var reference = references[ referenceURL ];
			if( reference ) {
				aTag.onclick = reference.onclick;
			}
		}
	);
}

//==============================================================================
//	Contexts
//==============================================================================
var _cst_context_count = 1;
var _cst_contexts_ = new Array();

function cstNewContext() {
	var result = new Object();
	_cst_contexts_[ _cst_context_count ] = result;
	result._context_id_ = _cst_context_count;
	_cst_context_count++;
	return result;
}

function cstGetContext( contextId, andDelete ) {
	var result = _cst_contexts_[ contextId ];
	if( result && andDelete ) {
		_cst_contexts_.splice( contextId, 1 );
	}
	return result;
}
//==============================================================================
//	Tags
//==============================================================================

function cstDoECHO( cstTag ) {
	var value = cstAttribute( cstTag, "value" );
	
	value = value != null ? value : eval( cstTag.innerHTML );
	
	var echoTextNode = document.createTextNode( value );
	cstTag.parentNode.insertBefore( echoTextNode, cstTag );
	cstTag.parentNode.removeChild( cstTag );
	// cstTag.style.display = "none";
}

function cstDoATTRIBUTE( cstTag ) {
	var name = cstAttribute( cstTag, "name" );
	var value = cstAttribute( cstTag, "value" );
	var targetId = cstAttribute( cstTag, "target" );
	
	cstTag.parentNode.removeChild( cstTag );
	// cstTag.style.display = "none";

	value = value != null ? value : eval( cstTag.innerHTML );
	
	var targetNode = targetId == null ? cstTag.parentNode : $( targetId );
	
	targetNode.setAttribute( name, value );
	alert( targetNode.nodeName );
	if( targetNode.getAttribute( "cst" )) {
		var contextId = targetNode.getAttribute( "contextId" );
		if( contextId ) {
			var context = cstGetContext( contextId );
			if( context ) {
				context[ name ] = value;
				alert( "context." + name + "=" + value );
			} else {
				alert( "fail to get context : " + contextId );
			}
		} else {
			alert( "no contextId" );
		}
	}
}

function cstDoSTYLE( cstTag ) {
	var name = cstCSSNameToJS( cstAttribute( cstTag, "name" ));
	var value = cstAttribute( cstTag, "value" );
	var targetId = cstAttribute( cstTag, "target" );
	
	value = value != null ? value : eval( cstTag.innerHTML );

	if( targetId == null ) {	
		cstTag.parentNode.style[ name ] = value ;
	} else {
		$( targetId ).style[ name ] = value ;
	}

	cstTag.parentNode.removeChild( cstTag );
	// cstTag.style.display = "none";
}

function cstDoSET( cstTag ) {
	var name = cstAttribute( cstTag, "name" );
	var value = cstTag.getAttribute( "value" );
	
	cstTag.parentNode.removeChild( cstTag );
	// cstTag.style.display = "none";

	value = value != null ? value : cstTag.innerHTML;

	value = cstValue( value );
	if( value instanceof String ) {
		eval( name + "='" + value + "'" );
	} else {
		eval( name + "= value " );
	}	
}

function cstDoIF( cstTag ) {
	var test = cstAttribute( cstTag, "test" );
	if( test ) {
		cstDoAllTags( cstTag );
	} else {
		cstTag.style.display = "none";
	}
}

function cstDoREPEAT( cstTag ) {
	var name = cstAttribute( cstTag, "name" );
	var from = cstAttribute( cstTag, "from", 0 );
	var to = cstAttribute( cstTag, "to" );
	
	var forAll = cstAttribute( cstTag, "forAll" );
	
	var orgInnerHTML = cstTag.getAttribute( "orgInnerHTML" );
	if( ! orgInnerHTML ) {
		orgInnerHTML = cstTag.innerHTML;
		cstTag.setAttribute( "orgInnerHTML", orgInnerHTML );
	}
	
	var repeatedInnerHTML = "";
	
	if( forAll ) {
		from = 0;
		to = ( forAll instanceof Array ) ? forAll.length : eval( forAll + ".length" );
	}
	
	for( var i = from; i < to; i++ ) {
		if( name ) {
			var cstSet;
			
			if( ! forAll ) {
				cstSet = "<hr cst='set' name='" + name + "' value='" + i + "' >";
			} else if( forAll instanceof Array ) {
				cstSet = "<hr cst='set' name='" + name + "' value='" + forAll[ i ] + "' >";
			} else {			
				cstSet = "<hr cst='set' name='" + name + "' value='{" + forAll + "[ " +  i  + "]  }' >";
			}
			// alert( cstSet );
			repeatedInnerHTML = repeatedInnerHTML + cstSet;
		}
		repeatedInnerHTML = repeatedInnerHTML + orgInnerHTML;
	}
	
	cstTag.innerHTML = repeatedInnerHTML;
	cstDoAllTags( cstTag );
}

function cstDoINCLUDE( cstTag ) {
	var href = cstAttribute( cstTag, "href" );
	var cstAjax =  new Ajax.Request( href, { method: 'get', asynchronous: false });
	var transport = cstAjax.transport;
	
	if( transport.status == 200 ) {
		cstTag.innerHTML = transport.responseText;
		
		cstFixURLs( cstTag, "IMG", URL._base_, cstBaseURL( href ));
		cstFixReferences( cstTag, URL._base_, cstBaseURL( href ));		
		
		
		cstDoAllTags( cstTag );
	} else {
		cstTag.innerHTML = "Fail to include " + href;
	}
}

var _cst_imports_ = new Object();

function cstImport( href, ignoreCache ) {
	var result = ignoreCache ? null : _cst_imports_[ href ];
	
	if( result ) {
		return result;
	}
	
	if( URL._self_.indexOf( "file:/" ) == 0 ) {
		href = URL._base_ + "/" + href;
	}
	
	var cstAjax =  new Ajax.Request( href, { method: 'get', asynchronous: false });
	var transport = cstAjax.transport;
	
	if( transport.status == 200 ) {
		result = eval( transport.responseText );
	} else {
		result = new Error(  "Fail to import " + href );
	}
	
	_cst_imports_[ href ] = result;
	return result;
}

function cstDoIMPORT( cstTag ) {
	var href = cstAttribute( cstTag, "href" );
	cstImport( href );
}

function cstDoOnClickUPDATE( contextId ) {
	var updateContext = cstGetContext( contextId );
	// alert( contextId + " -> " + updateContext.attributes[ 0 ].value );
	if( ! updateContext ) {
		return;
	}
	var target = updateContext.target;
	var href = updateContext.template ? updateContext.template : updateContext.href;
	
	var cstAjax =  new Ajax.Request( href, { method: 'get', asynchronous: false });
	var transport = cstAjax.transport;
	
	var targetNode = $( target );
	if( transport.status == 200 ) {
		targetNode.innerHTML = transport.responseText;
		eval( "href='" + updateContext.href + "'" );
		eval( "target='" + updateContext.target + "'" );
		if( updateContext.template ) {
			eval( "template='" + updateContext.template + "'" );
		}
		for( var i = 0; i < updateContext.updateAttributes.length; i++ ) {
			var name = updateContext.updateAttributes[ i ].name;
			var value = updateContext.updateAttributes[ i ].value;
			// alert( name + "=" + cstValue( value ) );
			eval( name + "='" + value  + "'" );
		}
		cstFixURLs( targetNode, "IMG", URL._base_, cstBaseURL( updateContext.href ));
		cstFixReferences( targetNode, URL._base_, cstBaseURL( updateContext.href ));

		cstDoAllTags(targetNode);
	
	} else {
		targetNode.innerHTML = "Fail to update " + href + " : " + transport.status ;
	}
}

function cstDoUPDATE( cstTag ) {
	var updateContext = cstNewContext();
	
	updateContext.updateAttributes = new Array();
	updateContext.target = cstAttribute( cstTag, "target" );
	updateContext.href = cstAttribute( cstTag, "href" );
	updateContext.template = cstAttribute( cstTag, "template" );
	
	var orgInnerHTML = cstTag.innerHTML;
	var newAnchor = document.createElement( "a" );
	cstTag.parentNode.replaceChild( newAnchor, cstTag );
		newAnchor.setAttribute( "contextId", updateContext._context_id_ );
		newAnchor.setAttribute( "href", "##" );
		newAnchor.setAttribute( "onclick", "cstDoOnClickUPDATE(" + updateContext._context_id_ + " ); return false;" );
		adoptAllChildren( newAnchor, cstTag, false );
	cstTag = newAnchor;
	references[ updateContext.href ] = newAnchor;
	
	cstDoAllTags( cstTag );
}

function cstDoPARAMETER( cstTag ) {
	var contextId = cstTag.parentNode.getAttribute( "contextId" ) ;

	if (  contextId == null ) {
		alert( cstTag.parentNode.cst + " :" + cstTag.parentNode.getAttribute( "contextId" ) );
		return;
	}
	var updateContext = cstGetContext( contextId );


	var name = cstAttribute( cstTag, "name" );
	var value = cstAttribute( cstTag, "value" );

	updateContext.updateAttributes[ updateContext.updateAttributes.length ] = { name: name, value: value  };	

	cstTag.parentNode.removeChild( cstTag );
	// cstTag.style.display = "none";
}

function cstDoOnClickTOC( contextId, tagIndex ) {
	var tocContext = cstGetContext( contextId );
	
	tocContext.tags[ tagIndex ].scrollIntoView( true );	
}

function cstDoTOC( cstTag ) {
	var startAt = cstAttribute( cstTag, "start" );
	var endAt = cstAttribute( cstTag, "end" );
	
	var tags = new Array();
	
	for( var i = startAt; i <= endAt; i++ ) {
		tags[ tags.length ] = "H" + i;
	}
	
	var allTags = cstFindAllTagsLike( cstTag.parentNode, tags, null, null, true );
	
	var tocContext=cstNewContext();
	tocContext.tags = allTags;

	for( var i = 0; i < allTags.length; i++ ) {
		var level = allTags[ i ].nodeName.slice( 1 ) - startAt;
		
		var tocEntry = document.createElement( "A" );
			tocEntry.setAttribute( "href", "##" );
			tocEntry.setAttribute( "class", "toc" + level );
			tocEntry.setAttribute( "onClick", "cstDoOnClickTOC(" + tocContext._context_id_ + "," + i + "  )" );
			tocEntry.innerHTML = allTags[ i ].innerHTML;
		cstTag.appendChild( tocEntry );
		cstTag.appendChild( document.createElement( "BR" ));
	}
}
//==============================================================================
//	SNOUTs : CMS
//==============================================================================

var _cst_pages_ = null;
var _cst_book_ = null;
var _cst_chapter_ = null;

function cstLoadChapter( chapterDef,  index ) {
	chapterDef.fullHref = chapterDef.parent.fullHref + "/" + chapterDef.href;
	chapterDef.oid = chapterDef.parent.oid + "." + index;
	chapterDef.index = index;
	
	_cst_pages_[ chapterDef.oid ] = chapterDef;
	
	var chapterToc = null;
	if( chapterDef.href.indexOf( "." ) < 0 ) {
		chapterToc = cstImport( chapterDef.fullHref + "/cst.toc.js" );	
		
		if( chapterToc instanceof Error ) {
			chapterToc = null;
		}
		
		if( chapterToc && chapterToc.title ) {
			chapterDef.title = chapterToc.title;
		}
	}

	log( "Chapter : " + chapterDef.oid + " : " + chapterDef.title + " : " + chapterDef.fullhref );		

	if( chapterToc ) {	
		
		chapterDef.chapters = chapterToc.chapters;
		
		// alert( chapterDef.title + " : " + chapterDef.chapters );
		
		for( var i = 0; chapterDef.chapters && i < chapterDef.chapters.length; i++ ) {
			chapterDef.chapters[ i ].parent  = chapterDef;
			cstLoadChapter( chapterDef.chapters[ i ], i+1 );
		}
	} else {
		chapterDef.chapters = null;
	}
}

function cstLoadPages() {
	if( _cst_pages_ != null ) {
		return;
	}
	_cst_pages_ = new Object();
	
	_cst_book_ = cstImport( "cst.toc.js" );
	
	if(! ( _cst_book_ instanceof Error )) {
		_cst_book_.fullHref = ".";
		_cst_book_.oid = "1";
		_cst_pages_[ _cst_book_.oid ] = _cst_book_;
	
		for( var i = 0; i < _cst_book_.chapters.length; i++ ) {
			var chapter = _cst_book_.chapters[ i ];
			chapter.parent = _cst_book_;
			
			cstLoadChapter( chapter, i+1 );
		}
	} else {
		alert( _cst_book_ );
	}
}

//==============================================================================
//	CST	
//==============================================================================
var _cst_initialized_ = false;

function cstInitialize() {
	cstLoadPages();
}

function cstFindAllTags( startNode ) {
	var result = new Array();
	
	var cursor = startNode.firstChild;
	
	while( cursor != null && cursor != startNode ) {

		log( DEBUG, cursor + ": " + cursor.nodeType + " " + cursor.nodeName );

		if(( cursor.nodeType == 1 ) && ( cursor.getAttribute( "cst" ) != null )) {
			log( DEBUG, "Got One : " + cursor + ": " + cursor.nodeType + " " + cursor.nodeName   );
			
			result[ result.length ] = cursor;
			
			if( cursor.nextSibling ) {
				cursor = cursor.nextSibling;
				continue;
			}
		} else if( cursor.firstChild ) {
			log( DEBUG, "DOWN : " + cursor + ": " + cursor.nodeType + " : " + cursor.nodeName + " : " + cursor.parentNode  );
			cursor = cursor.firstChild;
			continue;
		} else if( cursor.nextSibling ) {
			log( DEBUG, "RIGHT : " + cursor + ": " + cursor.nodeType + " : " + cursor.nodeName + " : " + cursor.parentNode  );
			cursor = cursor.nextSibling;
			continue;
		}

		log( DEBUG, "UP : " + cursor + ": " + cursor.nodeType + " : " + cursor.nodeName + " : " + cursor.parentNode  );
		
		while( ( ! cursor.nextSibling ) && ( cursor != startNode )) {
			cursor = cursor.parentNode;
			
			if( ! cursor ) {
				log( DEBUG, "STOP : " + cursor + ": " + cursor.nodeType + " : " + cursor.nodeName + " : " + cursor.parentNode  );
				break;
			}
		}
		if( ! cursor ) {
			break;
		}
		
		if( cursor != startNode ) {
			cursor = cursor.nextSibling;
		} 
	}

	return result;
}

function cstDoTag( cstTag ) {

	if( cstTag.getAttribute( "cst-done" ) == "YES" ) {
		return;
	}
	cstTag.setAttribute( "cst-done", "YES" );

	var whenAttr = 	cstAttribute( cstTag, "when", true );
	if( ! whenAttr) {
		// alert( whenAttr );
		cstTag.style.display = "none";
		return;
	}

	var tagName = cstTag.getAttribute( "cst" );

	log( "START :  " + tagName );
	
	eval( "cstDo" + tagName.toUpperCase() + "( cstTag );" );
	
	log( "FINISH : " + tagName );
}

function cstDoAllTags( document ) {
	var allTags = cstFindAllTags( document );
	
	for( var i = 0; i < allTags.length; i++ ) {
		cstDoTag( allTags[ i ] );
	}
}

function CST() {
	if( ! _cst_initialized_ ) {	
		_cst_initialized_ = true;
		cstInitialize();
	}
	
	cstDoAllTags( document );
}

