namespace HaWeb.HTMLParser;
using HaXMLReader.Interfaces;
using HaXMLReader.EvArgs;
using System.Text;
using System.Collections.Generic;
using System;
public class XMLHelper where T : IState
{
    protected IReader _in;
    protected StringBuilder _target;
    protected List<(Func, bool>, Action>)>? _OTag_Funcs;
    protected List<(Func, bool>, Action>)>? _STag_Funcs;
    protected List<(Func, bool>, Action>)>? _CTag_Funcs;
    protected List<(Func, bool>, Action>)>? _Text_Funcs;
    protected List<(Func, bool>, Action>)>? _WS_Funcs;
    public T State;
    public Stack OpenTags;
    public Dictionary> LastSingleTags;
    public StringBuilder LastText;
    public XMLHelper(
        T state,
        IReader input,
        StringBuilder target,
        List<(Func, bool>, Action>)>? OTag_Funcs = null,
        List<(Func, bool>, Action>)>? STag_Funcs = null,
        List<(Func, bool>, Action>)>? CTag_Funcs = null,
        List<(Func, bool>, Action>)>? Text_Funcs = null,
        List<(Func, bool>, Action>)>? WS_Funcs = null
    )
    {
        if (input == null || target == null || state == null) throw new ArgumentNullException();
        State = state;
        _in = input;
        _target = target;
        _OTag_Funcs = OTag_Funcs;
        _STag_Funcs = STag_Funcs;
        _CTag_Funcs = CTag_Funcs;
        _Text_Funcs = Text_Funcs;
        _WS_Funcs = WS_Funcs;
        
        OpenTags = new Stack();
        LastSingleTags = new Dictionary>();
        LastText = new StringBuilder();
        if (_OTag_Funcs != null)
            _in.OpenTag += OnOTag;
        if (_STag_Funcs != null)
            _in.SingleTag += OnSTag;
        if (_CTag_Funcs != null)
            _in.CloseTag += OnCTag;
        if (_Text_Funcs != null)
            _in.Text += OnText;
        if (_WS_Funcs != null)
            _in.Whitespace += OnWS;
    }
    protected virtual void OnOTag(object? _, Tag tag)
    {
        OpenTags.Push(tag);
        if (_OTag_Funcs != null)
            foreach (var entry in _OTag_Funcs)
                if (entry.Item1(tag, this)) entry.Item2(_target, tag, this);
    }
    protected virtual void OnText(object? _, Text text)
    {
        LastText.Append(text.Value);
        if (_Text_Funcs != null)
            foreach (var entry in _Text_Funcs)
                if (entry.Item1(text, this)) entry.Item2(_target, text, this);
    }
    protected virtual void OnSTag(object? _, Tag tag)
    {
        if (!LastSingleTags.ContainsKey(tag.Name))
            LastSingleTags.Add(tag.Name, new List());
        LastSingleTags[tag.Name].Add(tag);
        if (_STag_Funcs != null)
            foreach (var entry in _STag_Funcs)
                if (entry.Item1(tag, this)) entry.Item2(_target, tag, this);
    }
    protected virtual void OnCTag(object? _, Tag tag)
    {
        OpenTags.Pop();
        if(_CTag_Funcs != null)
            foreach (var entry in _CTag_Funcs)
                if (entry.Item1(tag, this)) entry.Item2(_target, tag, this);
    }
    protected virtual void OnWS(object? _, Whitespace ws)
    {
        LastText.Append(ws.Value);
        if (_WS_Funcs != null)
            foreach (var entry in _WS_Funcs)
                if (entry.Item1(ws, this)) entry.Item2(_target, ws, this);
    }
    internal void Dispose()
    {
        OpenTags.Clear();
        LastSingleTags.Clear();
        LastText.Clear();
        if (_in != null)
        {
            if (_OTag_Funcs != null)
                _in.OpenTag -= OnOTag;
            if (_STag_Funcs != null)
                _in.SingleTag -= OnSTag;
            if (_CTag_Funcs != null)
                _in.CloseTag -= OnCTag;
            if (_Text_Funcs != null)
                _in.Text -= OnText;
            if (_WS_Funcs != null)
                _in.Whitespace -= OnWS;
        }
    }
    ~XMLHelper()
    {
        Dispose();
    }
}