import os
import re

from .tree import load_json, dump_json


def load_md(p):
    with open(p, 'r', encoding='utf-8') as f:
        return f.read()


def dump_md(p, str):
    with open(p, 'w', encoding='utf-8') as f:
        return f.write(str)


class MathWalker:
    def __init__(self, root) -> None:
        self.root = root

    def walk(self):
        for base, dirs, files in os.walk(self.root):
            config_path = os.path.join(base, 'config.json')
            if os.path.exists(config_path):
                config = load_json(config_path)
                if config.get('export') is not None:
                    self.parse_math(base, config)

    def parse_math(self, base, config):
        for export in config['export']:
            export_path = os.path.join(base, export)
            export_obj = load_json(export_path)

            source_origin = export_obj['source']
            if source_origin.find('.md.md') >= 0:
                source_origin = source_origin[:len(source_origin)-3]
            source_path = os.path.join(base, source_origin)

            md = load_md(source_path)
            new_md = []
            math_ctx = {
                "enter": False,
                "chars": []
            }

            count = len(md)
            i = 0
            has_enter_math = False
            while i < count:
                c = md[i]
                if c == '$':
                    if math_ctx['enter']:
                        j = 0
                        chars = math_ctx['chars']
                        length = len(chars)
                        while j < length:
                            cc = chars[j]
                            if cc == '_':
                                next_c = chars[j+1]
                                if next_c == '{':
                                    subs = []
                                    cursor = 2
                                    next_c = chars[j+cursor]
                                    while next_c != '}':
                                        subs.append(next_c)
                                        cursor += 1
                                        next_c = chars[j+cursor]

                                    sub = ''.join(subs)
                                    new_md.append(f'<sub>{sub}</sub>')
                                    j += cursor
                                else:
                                    new_md.append(f'<sub>{next_c}</sub>')
                                    j += 1
                            elif cc == '^':
                                next_c = chars[j+1]
                                if next_c == '{':
                                    subs = []
                                    cursor = 2
                                    next_c = chars[j+cursor]
                                    while next_c != '}':
                                        subs.append(next_c)
                                        cursor += 1
                                        next_c = chars[j+cursor]

                                    sub = ''.join(subs)
                                    new_md.append(f'<sup>{sub}</sup>')
                                    j += cursor
                                else:
                                    new_md.append(f'<sup>{next_c}</sup>')
                                    j += 1
                            else:
                                new_md.append(cc)
                            j += 1

                        math_ctx['enter'] = False
                        math_ctx['chars'] = []
                    else:
                        math_ctx['enter'] = True
                        math_ctx['chars'] = []
                        has_enter_math = True
                else:
                    if math_ctx['enter']:
                        math_ctx['chars'].append(c)
                    else:
                        new_md.append(c)
                i += 1

            source_new_relative = source_origin+".md"
            source_path_new = os.path.join(base, source_new_relative)
            if has_enter_math:
                dump_md(source_path_new, ''.join(new_md))
                export_obj['source'] = source_new_relative
                dump_json(export_path, export_obj, True, True)
