using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using FooEditEngine;

namespace FooEditor
{
    sealed class CLangFoldingGenerator : IFoldingStrategy
    {
        struct TextLevelInfo
        {
            public int Index;
            public int Level;
            public TextLevelInfo(int index, int level)
            {
                this.Index = index;
                this.Level = level;
            }
        }

        Regex BeginFolding, EndFolding;
        char BeginBracket, EndBracket;
        public CLangFoldingGenerator(string begin, string end, char beginbracket, char endbracket)
        {
            if (string.IsNullOrEmpty(begin) || string.IsNullOrEmpty(end))
                throw new ArgumentNullException();
            this.BeginFolding = new Regex(begin, RegexOptions.IgnoreCase);
            this.EndFolding = new Regex(end, RegexOptions.IgnoreCase);
            this.BeginBracket = beginbracket;
            this.EndBracket = endbracket;
        }

        public IEnumerable<FoldingItem> AnalyzeDocument(Document doc, int start, int end)
        {
            if (this.BeginFolding == null || this.EndFolding == null)
                yield break;
            Stack<TextLevelInfo> beginIndexs = new Stack<TextLevelInfo>();
            int lineHeadIndex = start;
            int level = 0;
            foreach (string lineStr in doc.GetLines(start, end))
            {
                Match m = this.BeginFolding.Match(lineStr);
                if (m.Success)
                    beginIndexs.Push(new TextLevelInfo(lineHeadIndex + m.Index, level));

                foreach (char c in lineStr)
                {
                    if (this.BeginBracket == c)
                        level++;
                    else if (this.EndBracket == c)
                        level--;
                }

                if (beginIndexs.Count == 0)
                    goto loopend;

                TextLevelInfo begin = beginIndexs.Peek();

                if (begin.Level == level)
                {
                    m = this.EndFolding.Match(lineStr);
                    if (m.Success)
                    {
                        beginIndexs.Pop();
                        int endIndex = lineHeadIndex + m.Index + m.Length - 1;
                        if (begin.Index < endIndex)
                            yield return new OutlineItem(begin.Index, endIndex,level);
                    }
                }
            loopend:
                lineHeadIndex += lineStr.Length;
            }
        }
    }
}
