// JavaScript Document

/****
 *
 *  Created: 07/27/2010 Paul Carlton
 *  Currently Supports:
 *    PHP
 *    Javascript
 *    Perl
 *  Dependency: 
 *    javas_syn.js
 *    php_syn.js
 *    perl_syn.js
 *
 ***/
var EpicParser={
	GLOBAL_COMPARTMENT:{},
	SPECIAL:{Reg:new RegExp("^$"),Color:'COLOR5'},
	SUPERCOMMENT_REG:/^\/\*$/,
	REGEX:true,
	SUPERCOMMENT_END:/^\*\/$/,
	LANG:{
		JAVAS:false,
		PHP:false,
		PERL:false
	},
	init:function()
	{
		this.REGEX=true;
		this.GLOBAL_COMPARTMENTS=null;
		this.GLOBAL_COMPARTMENTS={'COLOR1':[],'COLOR2':[],'COLOR3':[],'COLOR2 bold':[],'COLOR4':[],'COLOR5':[],'COLOR6':[],'COLOR7':[]};
		for( var item in this.LANG )
			this.LANG[item]=false;
		// my epic parser!!  la!!!
	},
	parse:function( type, raw_html ) //html must be in html entities and slashes escaped
	{
		this.init(  );
		if(type==='javascript'){
			//javascript global compartmentalizing
			for( k=0;k<JavascriptSyntax['COLOR1'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR1'].push(JavascriptSyntax['COLOR1'][k]);
			for( k=0;k<JavascriptSyntax['COLOR2'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR2'].push(JavascriptSyntax['COLOR2'][k]);
			for( k=0;k<JavascriptSyntax['COLOR3'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR3'].push(JavascriptSyntax['COLOR3'][k]);
			for( k=0;k<JavascriptSyntax['COLOR4'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR4'].push(JavascriptSyntax['COLOR4'][k]);
			for( k=0;k<JavascriptSyntax['COLOR5'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR5'].push(JavascriptSyntax['COLOR5'][k]);
			for( k=0;k<JavascriptSyntax['COLOR6'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR6'].push(JavascriptSyntax['COLOR6'][k]);
			this.LANG.JAVAS=true;
		} else if( type ==='php' ) {
			for( k=0;k<PhpSyntax['COLOR1'].length;k++)	this.GLOBAL_COMPARTMENTS['COLOR1'].push(PhpSyntax['COLOR1'][k]);
			for( k=0;k<PhpSyntax['COLOR2'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR2'].push(PhpSyntax['COLOR2'][k]);
			for( k=0;k<PhpSyntax['COLOR3'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR3'].push(PhpSyntax['COLOR3'][k]);
			for( k=0;k<PhpSyntax['COLOR4'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR4'].push(PhpSyntax['COLOR4'][k]);
			for( k=0;k<PhpSyntax['COLOR5'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR5'].push(PhpSyntax['COLOR5'][k]);
			this.LANG.PHP=true;
			//set special variable
			this.SPECIAL.Reg=/(\$\w+)/g;
		} else if( type ==='perl' ) {
			//for( k=0;k<PerlSyntax['COLOR1'].length;k++)	this.GLOBAL_COMPARTMENTS['COLOR1'].push(PerlSyntax['COLOR1'][k]);
			for( k=0;k<PerlSyntax['COLOR2'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR2'].push(PerlSyntax['COLOR2'][k]);
			for( k=0;k<PerlSyntax['COLOR3'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR3'].push(PerlSyntax['COLOR3'][k]);
			//for( k=0;k<PerlSyntax['COLOR4'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR4'].push(PerlSyntax['COLOR4'][k]);
			//for( k=0;k<PerlSyntax['COLOR5'].length;k++ )	this.GLOBAL_COMPARTMENTS['COLOR5'].push(PerlSyntax['COLOR5'][k]);
			this.LANG.PERL=true;
			this.SPECIAL.Reg=/(\$\w+)/g;
		}
		else if( type === 'terminal' )
		{
			this.REGEX=false;
		}
		var element=null;
		raw_html=raw_html.replace(/\&amp;/g,'&');
		element=this.run( raw_html );
		var raw_html=null;
		return element;
	},
	run:function( data )
	{
		//reference
		//jQuery.debug(this.GLOBAL_COMPARTMENTS);
		for( var item in this.LANG )
			eval('var '+item+'='+this.LANG[item].toString());
		SynHighlight=this.GLOBAL_COMPARTMENTS;

		text=data.replace(/class/,'^^class^^');
		text=text.replace(/^\n/,'');
		text=text.replace(/\</g,'&lt;');
		text=text.replace(/\>/g,'&gt;');
		text=text.replace(/\&lt;/g,'@<@');
		text=text.replace(/\&gt;/g,'@>@');
		text=text.replace(/\&/g,'&amp;');
		text=text.replace(/\n/g,'<br>');
		text=text.replace(/\t/g,'    ');
		text=text.replace(/\s/g,'&nbsp;');



		var string=text.split('');
		var G_QUOTE={'type':'none','bool':false};
		var G_ESCAPE=false;
		var G_REG=false;
		var COMMENT=false;
		var SUPERCOMMENT=false;
		var SUPERCOMMENT_DELIM=this.SUPERCOMMENT_REG;
		var SUPERCOMMENT_END=this.SUPERCOMMENT_END;
		var str_concat='';
		for( var j=0;j<string.length;j++ )
		{
			if( /\\/.test( string[j] ) ){
				//in case it's escaping itself
				if( G_ESCAPE )G_ESCAPE=false;
				else G_ESCAPE=true;
				str_concat+='\\';
			}
			else if( 
					(!SUPERCOMMENT) && 
					(!COMMENT) && 
					(!G_QUOTE.bool) && 
					(
						string[j]==='/' && 
						string[j+1]!=='/' && 
						string[j-1]!=='/' && 
						string[j+1]!=='*'
					)
					&& (!PERL ) && (!this.REGEX) //skip perl, this is causing an infinite loop, must be debugged
				)
			{
				//this is most likely a regular expression
				if( G_REG===true ){
					//already set
					G_REG=false;
					str_concat+='/</span>';
					string.shift();
					continue;
				}
				//if( string[j+1]==='=' ){ //this is not a regular expression
				//to determine if this is a regular expression...
				//we will have to cycle through the remainder of the string until the <br> is hit
				i=0;
				num=(j+1);
				
				do{
					if( string[num]==='/' )G_REG=true;
					else if( string[num]==='<'&&string[num+1]==='b'&&string[num+2]==='r'&&string[num+3]==='>' )i++;
					num++;
				}
				while( i==0 );
				if( G_REG )
					str_concat+='<span class="COLOR7">/';
				else str_concat+='<span class="COLOR2">/';
			}
			else if( G_REG===true )
			{
				str_concat+=string[j];
				string.shift();
			}
			/*******************************\
			*
			*  DETERMINE IF A COMMENT
			*
			\*******************************/
			else if( ((PHP)||(JAVAS))&&(SUPERCOMMENT_DELIM.test(string[j]+string[j+1]) ) && (!SUPERCOMMENT) && (!COMMENT) )
			{
				
				SUPERCOMMENT=true
				str_concat+='<span class="COMENT">/';
				string.shift();
			}
			else if( SUPERCOMMENT )
			{
				if( SUPERCOMMENT_END.test(string[j]+string[j+1]) ){
					j++;
					str_concat+='*/</span>';
					SUPERCOMMENT=false;
				}
				else{ str_concat+=string[j]; }
			}
			else if( ((PHP)||(JAVAS)||(PERL))&&(string[j]+string[j+1])==='//' && (!COMMENT) && (!G_QUOTE.bool) )
			{
				COMMENT=true;
				str_concat+='<span class="COMENT">/';
			}
			else if( (PERL) && string[j]==='#' && string[j-1]!=='$' ){
				COMMENT=true;
				str_concat+='<span class="COMENT">#';
			}
			else if( COMMENT )
			{
				if( ( string[j]+string[j+1]+string[j+2]+string[j+3] )==='<br>' ){
					COMMENT=false;
					str_concat+='</span>'+string[j];
				}
				else str_concat+=string[j];
			}
			else if( string[j]==='"' && (!G_ESCAPE) )
			{
				if( G_QUOTE.type==='DOUBLE'&&G_QUOTE.bool===true ){
					G_QUOTE.type='none';
					G_QUOTE.bool=false;
					str_concat+='"</span>';
				}
				else if ( G_QUOTE.bool===true ){
					//it's a single tick string
					str_concat+=string[j];
				}
				else
				{
					G_QUOTE.type='DOUBLE';
					G_QUOTE.bool=true;
					str_concat+='<span class="COLOR1">"';
				}
			}
			else if( string[j]==="'" && (!G_ESCAPE) )
			{
				if( G_QUOTE.type==='SINGLE'&&G_QUOTE.bool===true ){
					G_QUOTE.type='none';
					G_QUOTE.bool=false;
					str_concat+="'</span>";
				}
				else if( G_QUOTE.bool===true ){
					//it's a double string
					str_concat+=string[j];
				}
				else
				{
					G_QUOTE.type='SINGLE';
					G_QUOTE.bool=true;
					str_concat+='<span class="COLOR1">'+"'";
				}
			}
			else if( G_QUOTE.bool===true ){
				//just concat the rest while the string is in there
				str_concat+=string[j];
			}
			else if(string[j] === '@') {
				if (string[j+1]==='>') {
					str_concat+= '<span class="COLOR2">@>@</span>';
					j+=2;
					continue;
				}
				//else {
					str_concat+= '@';
					continue;
				//}
			}
			else
			{
				var CONCAT=true;
				//for( var item in SynHighlight )
				//{
					//they are layered in priority to a certain extent
					for( var c=0;c<SynHighlight['COLOR2'].length;c++ )
					{
						//alert(item);
						//return;
						chr=SynHighlight['COLOR2'][c];
						if( chr==null )//I HATE INTERNET EXPLORER WITH A PASSION
							continue;
						else if( chr.length==1&&chr===string[j] )
						{
							if     ( chr==='<' && (string[j+1]+string[j+2]+string[j+3])==='br>' )continue;
							else if( chr==='>' && (string[j-3]+string[j-2]+string[j-1])==='<br' )continue;
							else if( (chr==='>'||chr==='<') && (string[j+1])==='@'&&(string[j-1])==='@' )continue;
							else if( chr==='&' && (string[j+1]+string[j+2]+string[j+3]+string[j+4]+string[j+5])==='nbsp;' )continue;
							else if( chr===';' && (string[j-5]+string[j-4]+string[j-3]+string[j-2]+string[j-1])==='&nbsp' )continue;
							else if( chr==='@' && (string[j+1]+string[j+2])==='<@' ){continue;}
							else if( chr==='@' && (string[j+1]+string[j+2])==='>@' )continue;
							else if( chr==='@' && (string[j-2]+string[j-1])==='@<' )continue;
							else if( chr==='@' && (string[j-2]+string[j-1])==='@>' )continue;
		
							CONCAT=false;
							str_concat+='<span class="COLOR2">'+string[j]+'</span>';
							break;
						}
						else
						{
							var HIGHLIGHT=true;
							//this code below significantly slows down IE
							//a while loop DOES NOT help the speed in this case
							//in fact, it pops up "unresponesive script" even faster

							/****
							k=0;
							while( k<chr.length ){
								k++;
							}
							for( var k=0;k<chr.length;k++ )
							{
								if( string[j+k]!==chr[k] ){
									HIGHLIGHT=false;
									break;
								}
								else continue;
							}
							if( ( /\w/.test(string[j-1]) && string[j-1]!=undefined ) )HIGHLIGHT=false;
							else if( (/\w/.test(string[j+chr.length]) ) && string[j+chr.length]!=undefined )HIGHLIGHT=false;
							if( HIGHLIGHT )
							{
								j=j+(chr.length-1);
								str_concat+='<span class="'+item+'">'+chr+'</span>';
								CONCAT=false;
							}
							***/
						}
					}
					//if(!CONCAT)break;
				//}
				if(CONCAT)str_concat+=string[j];
			}
			G_ESCAPE=false;
		}
		text=str_concat;
		for( var item in SynHighlight )
		{
			if( item ==='COLOR2' )continue;
			for( var c=0;c<SynHighlight[item].length;c++ )
			{
				var Regex=new RegExp("([^A-Z])("+SynHighlight[item][c]+")(?![A-Za-z])","g");
				text=text.replace(Regex,"$1<span class='"+item+"'>$2</span>");
			}
		}
		text=text.replace(/(function|protected|extends)/g,'<span class="COLOR2 BOLD">$1</span>');
		text=text.replace(/\^\^class\^\^/g,'<span class="COLOR2 BOLD">class</span>');


		//special variable
		//alert(text);
		text=text.replace(this.SPECIAL.Reg,'<span class="'+this.SPECIAL.Color+'">$1</span>');
		text=text.replace(/\@<\@/g,'&lt;');
		text=text.replace(/\@>\@/g,'&gt;');
		text=text.replace(/\n|\r/g,'<br />'); //alert(text);
		//text=text.replace(/&gt;/g,'<span class="COLOR2 BOLD">&gt;</span>');
		text=text.replace(/&amp;/g,'<span class="COLOR2 BOLD">&amp;</span>');
		return text;
	}
}
