//
// 类 PatternParser
//
// Copyright 2006 (c) RegExLab.com
// Author: 史寿伟
//
function PatternParser()
{
	// 分解工具（静态变量）
	if( PatternParser.regex == null )
		PatternParser.regex = new RegExp( "([^\\(\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\])+|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\]|\\(([^\\(\\)\\[\\\\]|\\\\.|\\[([^\\]\\\\]|\\\\.)*\\])*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\))*\\)", "g" );

	// 表达式
	this.pattern = null;

	// 分解结果
	this.result = null;

	// 分解
	this.Parse = PatternParser_Parse;

	// 结果数量
	this.ResultCount = PatternParser_ResultCount;

	// 导出 HTML
	this.ExportHTML = PatternParser_ExportHTML;
	
	// 内部使用
	this.DoSpan = PatternParser_DoSpan;
}

//
// 针对 Windows 98, IE 5 中的 exec
//
// Copyright 2006 (c) RegExLab.com
// Author: 史寿伟
//
RegExp.prototype.exec2 = function exec2( stxt )
{
    if( parseFloat( navigator.appVersion.substr(navigator.appVersion.search("MSIE") + 4) ) >= 6 ) return this.exec( stxt );

    var _lI = this.lastIndex;
    this.lastIndex = 0;

    var match = null;

    if( _lI < stxt.length )
    {
        match = this.exec( stxt.substr( _lI ) );

        if( match != null )
        {
            match.input      = stxt;
            match.index     += _lI;
            match.lastIndex  = match.index + match[0].length;

            this. lastIndex  = match.lastIndex;
        }
    }

    return match;
}

//
// PatternParser::DoSpan( curr, spans, pos1, pos2, spanid, spancls )
//
function PatternParser_DoSpan( curr, spans, pos1, pos2, spanid, spancls )
{
  	while( curr<this.result.length && this.result[curr].index < pos2 )
  	{
      	if( pos1 < this.result[curr].index )
      		spans[spans.length] = formatstr( this.pattern.substring( pos1, this.result[curr].index ) );
  
  		spans[spans.length] = spanid + curr + spancls + ">";
  		
  		pos1 = this.result[curr].lastIndex;
  		
  		curr = this.DoSpan( curr+1, spans, this.result[curr].index, this.result[curr].lastIndex, spanid, spancls );
  		
  		spans[spans.length] = "</span>";
  	}

  	if( pos1 < pos2 )
  		spans[spans.length] = formatstr( this.pattern.substring( pos1, pos2 ) );
  		
  	return curr;
}

//
// PatternParser::ExportHTML( spanid, spancls )
//
function PatternParser_ExportHTML( spanid, spancls )
{
	if( this.pattern == null || this.pattern == "" )
		return "&nbsp;";

	// spanid
	if( spanid != null && spanid != "" )
		spanid = "<span id=" + spanid;
	else
		spanid = "<span id=group";

	// class
	if( spancls != null && spancls != "" )
		spancls = " class=" + spancls;
	else
		spancls = "";

	// do
	var spans = new Array();
	this.DoSpan( 0, spans, 0, this.pattern.length, spanid, spancls );

	return spans.join("");
}

//
// PatternParser::ResultCount( )
//
function PatternParser_ResultCount( )
{
	if( this.result == null )
		return 0;
	else
		return this.result.length;
}

//
// PatternParser::Parse( pat )
//
function PatternParser_Parse( pat )
{
	this.pattern = pat;
	this.result  = new Array( new Object() );

	this.result[0].index = 0;
	this.result[0].lastIndex = pat.length;

	var found = true, count = 1;
	PatternParser.regex.lastIndex = 0;

	while( found )
	{
		var match = PatternParser.regex.exec2( pat );

		if( match != null )
		{
			if( match[0].charAt(0) == '(' && match[0].charAt(1) != '?' )
  			{
  				this.result[count] = new Object();
  				this.result[count].index     = match.index;
  				this.result[count].lastIndex = match.lastIndex;

  				count ++;

  				PatternParser.regex.lastIndex = match.index + 1;
  			}
			else if( match[0].charAt(0) == '(' && match[0].charAt(1) == '?' )
			{
				PatternParser.regex.lastIndex = match.index + 3;
			}
			else
			{
				PatternParser.regex.lastIndex = match.lastIndex;
			}
		}
		else
			found = false;
	}
}

//
// 类 MatchShop
//
// Copyright 2006 (c) RegExLab.com
// Author: 史寿伟
//
function MatchShop()
{
	// 表达式分析
	this.pparser = new PatternParser();

	// 匹配表达式
	this.re = null;

	// 表达式
	this.pattern = null;
	
	// 忽略大小写
	this.ignorecase = false;
	
	this.multiline = false;
	
	// 匹配结果
	this.matches = null;

	// 文本
	this.text = null;
	
	// 递增类型
	this.deltatype = 0;
	
	// 递增量
	this.delta1  = 0;
	this.delta2s = new Array();
	this.delta2  = null;

	// 匹配到次数
	this.matchTimes = 0;

	// 设定表达式和文本
	this.PatternAndText = MatchShop_PatternAndText;
	
	// 标记为从头匹配
	this.SetFirst = MatchShop_SetFirst;
	
	// 设定忽略大小写
	this.SetIgnorecase = MatchShop_SetIgnorecase;
	
	this.SetMultiline = MatchShop_SetMultiline;
	
	// 匹配
	this.Match = MatchShop_Match;
	
	// 计算递增量
	this.DoDelta = MatchShop_DoDelta;

	// 设定递增量
	this.SetDelta = MatchShop_SetDelta;

	// 返回递增量描述
	this.GetDelta = MatchShop_GetDelta;
	
	// 匹配结果导出
	this.ExportResultHTML = MatchShop_ExportResultHTML;
	
	// 分组结果导出
	this.ExportGroupsHTML = MatchShop_ExportGroupsHTML;
	
	this.GetFlags = MatchShop_GetFlags;
}

//
// MatchShop::ExportGroupsHTML( callbackname, notfound )
//
function MatchShop_ExportGroupsHTML( callbackname, notfound )
{
	// 函数名
	if( callbackname == null )
		callbackname = "javascript:void";

	if( notfound == null )
		notfound = "Not found."

	var radios = new Array();

	radios[0] = "<input type=radio name=__mss id=__msrs0 onclick=\""+callbackname+"(0)\"><label for=__msrs0> $&: " + (this.matches!=null?formatstr(this.matches[0]):notfound) + "</label> <br>\r\n";

	for( i=1; i<this.pparser.ResultCount(); i++ )
	{
		radios[radios.length] = "<input type=radio name=__mss id=__msrs"+i+" onclick=\""+callbackname+"(" + i + ")\"><label for=__msrs"+i+"> $" + i + (this.matches!=null&&this.matches[i]!="" ? ": "+formatstr(this.matches[i]) :"") + "</label> <br>\r\n";
	}

	return radios.join("");
}

//
// 匹配结果导出
//
function MatchShop_ExportResultHTML()
{
	if( this.text == null || this.text == "" )
		return "&nbsp;";

	if( this.matches != null )
		return formatstr( this.text.substring(0, this.matches.index) )
		     + "<span style='background-color: #FFFF00'>" + formatstr( this.text.substring(this.matches.index, this.matches.lastIndex) ) + "</span>"
		     + formatstr( this.text.substr(this.matches.lastIndex) );
	else
		return formatstr( this.text );
}

//
// MatchShop::GetDelta()
//
function MatchShop_GetDelta()
{
	if( this.deltatype == 0 )
		return "0";

	var desc = new Array();

	if( this.delta2 != null && this.delta2.length > 0 )
	{
		desc[0] = (this.delta2s[0] > 0 ? "" : "- ") + "$" + this.delta2[0];
		
		for(var i=1; i<this.delta2.length; i++)
		{
			desc[i] = (this.delta2s[i] > 0 ? " + " : " - ") + "$" + this.delta2[i];
		}
	}
	
	if( desc.length > 0 )
    	desc[desc.length] = (this.delta1 >= 0 ? " + " : " - ") + Math.abs(this.delta1);
    else
    	desc[0] = (this.delta1 >= 0 ? "" : "- ") + Math.abs(this.delta1);

	return desc.join("");
}

//
// MatchShop::SetDelta( delta )
//
function MatchShop_SetDelta( delta )
{
	if( delta == null || delta == "" || delta == "0" )
	{
		this.deltatype = 0;
		return;
	}

	if( MatchShop.delta_re == null )
		MatchShop.delta_re = new RegExp("([\\+\\-]?)\\s*(\\$*)\\s*(\\d+)", "g");

	MatchShop.delta_re.lastIndex = 0;

	this.deltatype = 1;
	this.delta1    = 0;
	this.delta2    = new Array();

	var match = MatchShop.delta_re.exec( delta );
	while( match != null )
	{
		var dec = parseInt( match[3] );
		var sig = match[1] != "-" ? 1 : -1;
		var dls = match[2];

		if( dls.length > 0 )
		{
			this.delta2s[this.delta2.length] = sig;
			this.delta2 [this.delta2.length] = dec;
		}
		else
		{
			this.delta1 += sig * dec;
		}

		// 查找下一个
		match = MatchShop.delta_re.exec( delta );
	}
}

//
// MatchShop::DoDelta()
//
function MatchShop_DoDelta()
{
	if( this.deltatype == 0 || this.re == null )
		return;

	if( this.matches == null )
	{
		this.re.lastIndex = 0;
		return;
	}

	var delta = this.delta1;
	if( this.delta2 != null && this.delta2s != null )
	{
		for( var i=0; i<Math.min(this.delta2.length, this.delta2s.length); i++ )
		{
			var grp = this.delta2[i];
			if( grp < this.matches.length )
			{
				var sign = this.delta2s[i] >= 0 ? 1 : -1;
				delta += sign * this.matches[grp].length;
			}
		}
	}

	if( delta <= 0 )
		delta = 1;

	this.re.lastIndex = this.matches.index + delta;
}

//
// MatchShop::Match( bfirst )
//
function MatchShop_Match( bfirst )
{
	if( bfirst != null && bfirst )
		this.SetFirst();

	// 递增
	this.DoDelta();

	// 计数
	if( this.re.lastIndex == 0 )
		this.matchTimes = 0;

	this.matchTimes ++;

	// 匹配
	this.matches = this.re.exec2( this.text );
}

//
// MatchShop::SetIgnorecase( icase )
//
function MatchShop_SetIgnorecase( icase )
{
	if( icase == null )
		this.ignorecase = true;
	else
		this.ignorecase = icase;

	if( this.pattern != null )
		this.re = new RegExp( this.pattern, this.GetFlags() );

	this.SetFirst();
}

function MatchShop_SetMultiline( mline )
{
    if( mline == null )
        this.multiline = true;
    else
        this.multiline = mline;

    if( this.pattern != null )
        this.re = new RegExp( this.pattern, this.GetFlags() );

    this.SetFirst();
}

//
// MatchShop::SetFirst()
//
function MatchShop_SetFirst()
{
	if( this.re != null )
		this.re.lastIndex = 0;

	this.matches = null;
}

//
// MatchShop::PatternAndText( pat, txt )
//
function MatchShop_PatternAndText( pat, txt )
{
    pat = pat.replace( /\r\n?|\n\r?/g, "\n" );
    txt = txt.replace( /\r\n?|\n\r?/g, "\n" );

	if( pat != this.pattern )
	{
		this.pattern = pat;

		this.pparser.Parse( pat );
		this.re = new RegExp( pat, this.GetFlags() );

		this.SetFirst();
	}
	
	if( txt != this.text )
	{
		this.text = txt;
		this.SetFirst();
	}
}

function MatchShop_GetFlags()
{
    var flags = "g";

    if( this.ignorecase )
        flags = "i" + flags;
    
    if( this.multiline )
        flags = flags + "m";
    
    return flags;
}

//
// 可指定替换次数的字符串替换方法
//
//    $$  The literal character '$'  
//    $&  The entire matched string  
//    $`  The substring preceding the matched substring  
//    $'  The substring following the matched substring  
//    $n  The n'th captured submatch  
//    $+  The last matched substring  
//    $_  The entire input string  
//
// Copyright 2006 (c) RegExLab.com
// Author: 史寿伟
//
String.prototype.replace2 = function replace2( regexp, replacetxt, dotimes )
{
	// 如果没有第三个参数
	if( dotimes == null || dotimes <= 0 )
		return this.replace( regexp, replacetxt );

	if( replace2.topattern == null )
		replace2.topattern = new RegExp("\\$([$&`'+_]|\\d\\d?)", "g");

	// 按次数匹配
	regexp.global    = true;
	regexp.lastIndex = 0;

	var lastpos = 0, toIndex = 0;
	var result  = new Array();

	for(var i=0; i<dotimes; i++)
	{
		var match = regexp.exec( this );

		// 如果找到
		if( match != null )
		{
			regexp.index = match.index;
			match.lastIndex = match.index + match[0].length;
		}
		else
		{
			regexp.index = null;
			break;
		}

		// 之前部分		
		if( lastpos < match.index )
		{
			var subs = this.substring( lastpos, match.index );
			result[result.length] = subs;

			toIndex += subs.length;
		}

		// 得到各种定义
		var enm = match[0];
		var pre = this.substring( 0, match.index );
		var fol = this.substr( match.lastIndex );
		var lam = match[match.length-1];
		var inp = this;

		// 开始组装替换为字符串
		replace2.topattern.lastIndex = 0;

		var replto = new Array();
		var lastp  = 0;

		var m = replace2.topattern.exec2( replacetxt );
		while( m != null )
		{
			if( lastp < m.index )
				replto[replto.length] = replacetxt.substring( lastp, m.index );

			switch( m[1] )
			{
			case "$":
				replto[replto.length] = "$"; break;

			case "&":
				replto[replto.length] = enm; break;

			case "`":
				replto[replto.length] = pre; break;

			case "'":
				replto[replto.length] = fol; break;

			case "+":
				replto[replto.length] = lam; break;
			
			case "_":
				replto[replto.length] = inp; break;
		
			default:
				{
					var grpnum = m[1];
					while( grpnum >= match.length && grpnum.length > 0 )
						grpnum = grpnum.substring(0, grpnum.length-1);

					var numtxt = m[1].substr(grpnum.length);

					if( grpnum.length > 0 )
					{
						if( grpnum > 0 )
							replto[replto.length] = match[parseInt(grpnum.replace(/^0+/, ""))] + numtxt;
						else
							replto[replto.length] = "$" + grpnum + numtxt;
					}
					else
						replto[replto.length] = "$" + numtxt;

					break;
				}
			}

			lastp = m.lastIndex;

			// 下一个
			m = replace2.topattern.exec2( replacetxt );	
		}

		if( lastp < replacetxt.length )
			replto[replto.length] = replacetxt.substr( lastp );

		var subs = replto.join("");
		result[result.length] = subs;

		// 反馈匹配到位置
		regexp.toIndex     = toIndex;
		regexp.toLastIndex = toIndex + subs.length;

		toIndex += subs.length;

		// 剩下部分
		lastpos = match.lastIndex;
	}

	if( lastpos < this.length )
		result[result.length] = this.substr( lastpos );

	return result.join("");
}
