/** 
 * @description: 标签类型
 * @return {*}
 */
enum LabelType
{
    color = 0,
    color_end,
    u,
    u_end,
    b,
    b_end,
    i,
    i_end,
    size,
    size_end,
    s,
    s_end,
    notShown,
    unknown
}

/** 
 * @description: 标签记录类
 * @return {*}
 */
class LabelRecord
{
    id: number;

    startIndex: number;

    endIndex: number;

    type: LabelType;

    isPair: boolean;

    inserted: boolean;

    constructor(id: number,startIndex: number,endIndex: number,type: LabelType,isPair: boolean)
    {
        this.id = id;
        this.startIndex = startIndex;
        this.endIndex = endIndex;
        this.type = type;
        this.isPair = isPair;
        this.inserted = false;
    }
}


export default class TalkGuidePanel extends UI.UIBehavior {
    
    private _intervalId: number = 0;
    onStart()
    {
        let str = '<s>测<color=#cyan>试</color></s><u><size=80><color=#red>富文本</color></size>标签<!--haha--></u>';
        let textArray = this.showRichText(str);
        
        let i = 0;
        this._intervalId = setInterval(()=>
        {
            //换成自己UI里的文本框
            this.textBlock.text = textArray[i];
            i++;
            if(i >= textArray.length)
            {
                clearInterval(this._intervalId);
            }
        },500);
    }

    //todo：支持嵌套标签
    private showRichText(str: string = ""): string[] {
        //str = '<s>测<color=#cyan>试</color></s><u><size=80><color=#red>富文本</color></size>标签<!--haha--></u>';
        //先找到所有<>标签
        const labelArr = str.match(/<.+?\/?>/g);
        let tempStr = str;  
        //记录标签的起点和长度
        const labelRecords = [];
        const labelStack = [];
        //记录要单独显示的index
        let id = 0;
        //用来标签记录在原数组的位置
        let spliceCharLength = 0;
        //有富文本标签
        if(labelArr)
        {
            for(let i = 0; i < labelArr.length; i++){
                if(labelArr[i][1] === '!')
                {
                    //说明是<!--not shown-->
                    const startIndex = tempStr.search(labelArr[i]);
                    const item = new LabelRecord(id++,spliceCharLength+startIndex,spliceCharLength + startIndex+labelArr[i].length -1,LabelType.notShown,false);
                    //记录标签的起点和长度
                    labelRecords.push(item);
                    
                    tempStr = tempStr.slice(startIndex+labelArr[i].length,tempStr.length);
                    spliceCharLength += startIndex+labelArr[i].length;
                    
                }else{
                    //处理下嵌套标签
                    //当前处理的标签

                    const startIndex = tempStr.search(labelArr[i]);
                    const label = tempStr.slice(startIndex,startIndex+labelArr[i].length);
                    //获取栈顶标签
                    const topLabel = labelStack[labelStack.length-1];
                    if(labelStack[labelStack.length-1])
                    {
                        //注意有前后顺序，栈中的是起始标签
                        if(this.labelMatch(topLabel.type,this.getLabelType(label)))
                        {
                            //栈顶标签和当前标签匹配，出栈
                            const startLabel = labelStack.pop();
                            const endLabel = new LabelRecord(startLabel.id,spliceCharLength+startIndex,spliceCharLength + startIndex+labelArr[i].length-1,startLabel.type,true);
                            startLabel.isPair = true;
                            labelRecords.push(startLabel);
                            labelRecords.push(endLabel);
                        }
                        else
                        {
                            //不匹配，入栈
                            const labelItem = new LabelRecord(id++,spliceCharLength+startIndex,spliceCharLength + startIndex+labelArr[i].length -1,this.getLabelType(label),false);
                            labelStack.push(labelItem);
                        }
                    }else{
                        //栈中没有标签，直接入栈
                        const labelItem = new LabelRecord(id++,spliceCharLength+startIndex,spliceCharLength + startIndex+labelArr[i].length -1,this.getLabelType(label),false);
                        labelStack.push(labelItem);
                    }
                  
                    spliceCharLength += startIndex+labelArr[i].length;
                    tempStr = tempStr.slice(startIndex+labelArr[i].length,tempStr.length);
                    
                }   
            }
        }
    
        //得到了标签和对应的index   
        const showText = [];
        let insertIndex = 0;
        
        for(let i = 0; i < str.length; i++)
        {
            //判断i走没走到记录里的标签下标
            //遍历记录
            
            if(this.isStartIndexInLabelRecords(i,labelRecords).result)
            {
                //判断这个结束标签是否已经被插入结果字符串
                
                const index = this.isStartIndexInLabelRecords(i,labelRecords).index;
                if(labelRecords[index].inserted)
                {
                    //i和insertindex往后走
                    insertIndex = labelRecords[index].endIndex+1;
                    i = labelRecords[index].endIndex;
                }
                else if( labelRecords[index+1] && labelRecords[index].isPair)//走到了，判断是不是成对的标签
                {
                    //说明是成对的标签
                    //要判断下标签是不是第一个字符
                    let tempStr ='';
                    if(showText.length > 0)
                    {
                        //不是第一个字符
                        tempStr += showText[showText.length-1];
                    }
                    const recordId = [];
                    //先把第一个标签的起始标签加进去
                    tempStr =this.insertStr(tempStr,insertIndex,str.slice(labelRecords[index].startIndex,labelRecords[index].endIndex+1));
                    insertIndex+=labelRecords[index].endIndex+1-labelRecords[index].startIndex;
                    
                    //记录下插入的起始标签的id
                    recordId.push(labelRecords[index].id);
                    
                    //判断是不是嵌套的标签,找到第一个字
                    //找起始标签后的第一个下标
                    let findIndex = labelRecords[index].endIndex+1;

                    //把这个起始标签移除
                    labelRecords.splice(index,1);

                    while(this.isStartIndexInLabelRecords(findIndex,labelRecords).result)
                    {
                        const tempIndex = this.isStartIndexInLabelRecords(findIndex,labelRecords).index;
                        //找到了一个连续嵌套的标签，加入字符串
                        tempStr =this.insertStr(tempStr,insertIndex,str.slice(labelRecords[tempIndex].startIndex,labelRecords[tempIndex].endIndex+1));
                        insertIndex+=labelRecords[tempIndex].endIndex+1-labelRecords[tempIndex].startIndex;
                        //记录一下
                        //如果不是单独标签，入栈
                        if(labelRecords[tempIndex].isPair)
                        {
                            recordId.push(labelRecords[tempIndex].id);
                        }
                        //再找还有无嵌套标签
                        findIndex = labelRecords[tempIndex].endIndex+1;
                        //把这个起始标签移除
                        labelRecords.splice(tempIndex,1);
                        
                    }
                    //没有嵌套标签了，且没超出范围，说明找到了第一个字
                    if(findIndex < str.length)
                    {
                        //把这个字加进去
                        tempStr = this.insertStr(tempStr,insertIndex,str[findIndex]);
                        insertIndex++;
                        //按栈顺序加入结束标签
                        let labelTempStr = '';
                        for(let i = recordId.length-1; i >= 0; i--)
                        {
                            const record = this.getLabelRecordById(recordId[i],labelRecords);
                            if(record)
                            {
                                //不是单独标签，应该按insertindex往后插入
                                labelTempStr += str.slice(record.startIndex,record.endIndex+1);                                
                                
                                //记录标签已经被插入，用来遍历时跳过插入过的标签
                                record.inserted = true;
                            }
                        }
                        tempStr =this.insertStr(tempStr,insertIndex,labelTempStr);                               
                    }
                    showText.push(tempStr);
                    //计算下一个插入的下标
                    i = insertIndex-1;
                }
                else
                {
                    //是单独标签
                    let tempStr ='';
                    if(showText.length > 0)
                    {
                        tempStr = this.insertStr(showText[showText.length-1],insertIndex,str.slice(labelRecords[index].startIndex,labelRecords[index].endIndex+1));
                    }else
                    {
                        tempStr = str.slice(labelRecords[index].startIndex,labelRecords[index].endIndex+1);
                    }
                    
                    showText.push(tempStr);
                    i = labelRecords[index].endIndex;
                    insertIndex = labelRecords[index].endIndex+1;
                }
            }else{
                //遍历到的是字符
                if(showText.length > 0)
                {   
                    const tempStr = this.insertStr(showText[showText.length-1],insertIndex,str[i]);
                    showText.push(tempStr);
                }else
                {
                    //是第一次push且没有标签
                    showText.push(str[i]);
                }
                insertIndex++;
            }
        }
        return showText;            
    }

    /** 
     * @description: 插入字符串
     * @return {*}
     */    
    private insertStr(str,index,insertStr): string
    {
        return str.slice(0,index) + insertStr + str.slice(index,str.length);
    }

    
    /** 
     * @description: 判断标签是否匹配
     * @return {*}
     */    
    protected labelMatch(label1: LabelType, label2: LabelType): boolean
    {
        if(label1 === LabelType.color && label2 === LabelType.color_end)
        {
            return true;
        }else if(label1 === LabelType.u && label2 === LabelType.u_end)
        {
            return true;
        }else if(label1 === LabelType.b && label2 === LabelType.b_end)
        {
            return true;
        }else if(label1 === LabelType.i && label2 === LabelType.i_end)
        {
            return true;
        }else if(label1 === LabelType.size && label2 === LabelType.size_end)
        {
            return true;
        }else if(label1 === LabelType.s && label2 === LabelType.s_end)
        {
            return true;
        }else
        {
            return false;
        }
    }

    /** 
     * @description: 获取标签的类型
     * @param {string} str
     * @return {*}
     */    
    protected getLabelType(str: string): LabelType {
        const type = str.slice(1, 3);
        switch (type) {
            case 'co':
                return LabelType.color;
            case 'u>':
                return LabelType.u;
            case 'b>':
                return LabelType.b;
            case 'i>':
                return LabelType.i;
            case 's>':
                return LabelType.s;
            case 'si':
                return LabelType.size;
            case '!-':
                return LabelType.notShown;
            case '/c':
                return LabelType.color_end;
            case '/u':
                return LabelType.u_end;
            case '/b':
                return LabelType.b_end;
            case '/i':
                return LabelType.i_end;
            case '/s':
                {
                    if(str[3] === 'i') return LabelType.size_end;
                    else if(str[3] === '>') return LabelType.s_end;
                }
            default:
                return LabelType.unknown;
        }
    }  
    
    /** 
     * @description: 判断下标在不在记录的标签数组里
     * @param {number} index
     * @param {LabelRecord} labelRecords
     * @return {*}
     */    
    protected isStartIndexInLabelRecords(index: number,labelRecords: LabelRecord[]): {result: boolean,index: number}
    {
        for(let i = 0; i < labelRecords.length; i++)
        {
            //是不是起始位置
            if(index === labelRecords[i].startIndex)
            {
                return {result:true,index:i};
            }
        }
        return {result:false,index:-1};
    }

    /** 
     * @description: 根据id获取标签记录
     * @return {*}
     */    
    protected getLabelRecordById(id: number,labelRecords: LabelRecord[]): LabelRecord
    {
        for(let i = 0; i < labelRecords.length; i++)
        {
            if(id === labelRecords[i].id)
            {
                return labelRecords[i];
            }
        }   
        return null;
    }
}