package com.alogic.ik.core;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import com.alogic.ik.dic.Dictionary;
import com.alogic.ik.dic.Hit;

/**
 * 中文量词处理
 * 
 * @author yyduan
 * @since 1.6.11.32
 */
class CN_QuantifierSegmenter implements ISegmenter{
	
	//子分词器标签
	static final String SEGMENTER_NAME = "QUAN_SEGMENTER";
	
	//中文数词
	private static String Chn_Num = "一二两三四五六七八九十零壹贰叁肆伍陆柒捌玖拾百千万亿拾佰仟萬億兆卅廿";//Cnum
	private static Set<Character> ChnNumberChars = new HashSet<Character>();
	static{
		char[] ca = Chn_Num.toCharArray();
		for(char nChar : ca){
			ChnNumberChars.add(nChar);
		}
	}
	
	/*
	 * 词元的开始位置，
	 * 同时作为子分词器状态标识
	 * 当start > -1 时，标识当前的分词器正在处理字符
	 */
	private int nStart;
	/*
	 * 记录词元结束位置
	 * end记录的是在词元中最后一个出现的合理的数词结束
	 */
	private int nEnd;

	//待处理的量词hit队列
	private List<Hit> countHits;
	
	
	private Dictionary dic = null;
	
	CN_QuantifierSegmenter(Dictionary dic){
		this.dic = dic;
		nStart = -1;
		nEnd = -1;
		this.countHits  = new LinkedList<Hit>();
	}
	
	public void analyze(AnalyzeContext context) {
		//处理中文数词
		this.processCNumber(context);
		//处理中文量词
		this.processCount(context);
		
		//判断是否锁定缓冲区
		if(this.nStart == -1 && this.nEnd == -1	&& countHits.isEmpty()){
			//对缓冲区解锁
			context.unlockBuffer(SEGMENTER_NAME);
		}else{
			context.lockBuffer(SEGMENTER_NAME);
		}
	}
	

	public void reset() {
		nStart = -1;
		nEnd = -1;
		countHits.clear();
	}
	
	private void processCNumber(AnalyzeContext context){
		if(nStart == -1 && nEnd == -1){//初始状态
			if(CharacterUtil.CHAR_CHINESE == context.getCurrentCharType() 
					&& ChnNumberChars.contains(context.getCurrentChar())){
				//记录数词的起始、结束位置
				nStart = context.getCursor();
				nEnd = context.getCursor();
			}
		}else{//正在处理状态
			if(CharacterUtil.CHAR_CHINESE == context.getCurrentCharType() 
					&& ChnNumberChars.contains(context.getCurrentChar())){
				//记录数词的结束位置
				nEnd = context.getCursor();
			}else{
				//输出数词
				this.outputNumLexeme(context);
				//重置头尾指针
				nStart = -1;
				nEnd = -1;
			}
		}
		
		//缓冲区已经用完，还有尚未输出的数词
		if(context.isBufferConsumed()){
			if(nStart != -1 && nEnd != -1){
				//输出数词
				outputNumLexeme(context);
				//重置头尾指针
				nStart = -1;
				nEnd = -1;
			}
		}	
	}
	
	private void processCount(AnalyzeContext context){
		// 判断是否需要启动量词扫描
		if(!this.needCountScan(context)){
			return;
		}
		
		if(CharacterUtil.CHAR_CHINESE == context.getCurrentCharType()){
			
			//优先处理countHits中的hit
			if(!this.countHits.isEmpty()){
				//处理词段队列
				Hit[] tmpArray = this.countHits.toArray(new Hit[this.countHits.size()]);
				for(Hit hit : tmpArray){
					hit = dic.matchWithHit(context.getSegmentBuff(), context.getCursor() , hit);
					if(hit.isMatch()){
						//输出当前的词
						Lexeme newLexeme = new Lexeme(context.getBufferOffset() , hit.getBegin() , context.getCursor() - hit.getBegin() + 1 , Lexeme.TYPE_COUNT);
						context.addLexeme(newLexeme);
						
						if(!hit.isPrefix()){//不是词前缀，hit不需要继续匹配，移除
							this.countHits.remove(hit);
						}
						
					}else if(hit.isUnmatch()){
						//hit不是词，移除
						this.countHits.remove(hit);
					}					
				}
			}				

			//*********************************
			//对当前指针位置的字符进行单字匹配
			Hit singleCharHit = dic.matchInQuantifierDict(context.getSegmentBuff(), context.getCursor(), 1);
			if(singleCharHit.isMatch()){//首字成量词词
				//输出当前的词
				Lexeme newLexeme = new Lexeme(context.getBufferOffset() , context.getCursor() , 1 , Lexeme.TYPE_COUNT);
				context.addLexeme(newLexeme);

				//同时也是词前缀
				if(singleCharHit.isPrefix()){
					//前缀匹配则放入hit列表
					this.countHits.add(singleCharHit);
				}
			}else if(singleCharHit.isPrefix()){//首字为量词前缀
				//前缀匹配则放入hit列表
				this.countHits.add(singleCharHit);
			}
			
			
		}else{
			//输入的不是中文字符
			//清空未成形的量词
			this.countHits.clear();
		}
		
		//缓冲区数据已经读完，还有尚未输出的量词
		if(context.isBufferConsumed()){
			//清空未成形的量词
			this.countHits.clear();
		}
	}
	
	private boolean needCountScan(AnalyzeContext context){
		if((nStart != -1 && nEnd != -1 ) || !countHits.isEmpty()){
			//正在处理中文数词,或者正在处理量词
			return true;
		}else{
			//找到一个相邻的数词
			if(!context.getOrgLexemes().isEmpty()){
				Lexeme l = context.getOrgLexemes().peekLast();
				if(Lexeme.TYPE_CNUM == l.getLexemeType() ||  Lexeme.TYPE_ARABIC == l.getLexemeType()){
					if(l.getBegin() + l.getLength() == context.getCursor()){
						return true;
					}
				}
			}
		}
		return false;
	}
	
	private void outputNumLexeme(AnalyzeContext context){
		if(nStart > -1 && nEnd > -1){
			//输出数词
			Lexeme newLexeme = new Lexeme(context.getBufferOffset() , nStart , nEnd - nStart + 1 , Lexeme.TYPE_CNUM);
			context.addLexeme(newLexeme);
			
		}
	}

}
