#!/usr/bin/env python3
"""
e4_code_format.py — Генератор HTML-таблицы с подсветкой кода 1С
в стиле встроенной справки 1С:Предприятие

Результат копируется в буфер обмена и сохраняется в файл.
"""

# ═══════════════════════════════════════════════════════════════
#  ВВЕДИТЕ КОД 1С ЗДЕСЬ:
# ═══════════════════════════════════════════════════════════════

CODE_1C = """\
// Пример чтения JSON
&НаСервере
Процедура ЗагрузкаНаСервере(Путь)
  Чтение = Новый ЧтениеJSON;
  Чтение.ОткрытьФайл(Путь);
  Данные = ПрочитатьJSON(Чтение);
  Чтение.Закрыть(); Количество = 0;
  Для Каждого Товар Из Данные Цикл
    Ссылка = Справочники.ЗагрузкаТоваров.НайтиПоКоду(Товар.id);
    Элемент = ?(Ссылка.Пустая(), Справочники.ЗагрузкаТоваров.СоздатьЭлемент(), Ссылка.ПолучитьОбъект());
    Элемент.Код = Товар.article;
    Элемент.Наименование = Товар.name;
    Элемент.Цена = Товар.price;
	Элемент.Цвет = Товар.color;
    Элемент.Записать(); Количество = Количество + 1;
  КонецЦикла;
  Сообщить("Загружено " + Количество);
КонецПроцедуры

&НаКлиенте
Асинх Процедура Загрузка(Команда)
	Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
	Диалог.Фильтр = "ДжейсонСтетхэм (*.json) | *.json";
	Если Ждать Диалог.ВыбратьАсинх() Тогда
		ЗагрузкаНаСервере(Диалог.ПолноеИмяФайла);
	КонецЕсли;
КонецПроцедуры
"""

# ═══════════════════════════════════════════════════════════════
#  Словари ключевых слов
# ═══════════════════════════════════════════════════════════════

KEYWORDS = {
    # Русские
    "Если",
    "Тогда",
    "ИначеЕсли",
    "Иначе",
    "КонецЕсли",
    "Для",
    "Каждого",
    "Из",
    "По",
    "Цикл",
    "КонецЦикла",
    "Пока",
    "Процедура",
    "КонецПроцедуры",
    "Функция",
    "КонецФункции",
    "Перем",
    "Возврат",
    "Продолжить",
    "Прервать",
    "И",
    "Или",
    "Не",
    "Попытка",
    "Исключение",
    "КонецПопытки",
    "ВызватьИсключение",
    "Новый",
    "Выполнить",
    "Знач",
    "Экспорт",
    "Истина",
    "Ложь",
    "Неопределено",
    "NULL",
    # Английские
    "If",
    "Then",
    "ElsIf",
    "Else",
    "EndIf",
    "For",
    "Each",
    "In",
    "To",
    "Do",
    "EndDo",
    "While",
    "Procedure",
    "EndProcedure",
    "Function",
    "EndFunction",
    "Var",
    "Return",
    "Continue",
    "Break",
    "And",
    "Or",
    "Not",
    "Try",
    "Except",
    "EndTry",
    "Raise",
    "New",
    "Execute",
    "Val",
    "Export",
    "True",
    "False",
    "Undefined",
}

CONTEXT_DIRECTIVES = {
    "&НаКлиенте",
    "&НаСервере",
    "&НаКлиентеНаСервере",
    "&НаСервереБезКонтекста",
    "&AtClient",
    "&AtServer",
    "&AtClientAtServer",
    "&AtServerNoContext",
}

COLORS = {
    "keyword": "#ff0000",
    "string": "#000000",
    "comment": "#008000",
    "operator": "#ff0000",
    "identifier": "#0000ff",
    "number": "#000000",
    "directive": "#ff0000",
    "context": "#884422",
}

OPERATORS = set("=+-*/<>().,;[]%?")

# ═══════════════════════════════════════════════════════════════
#  Лексер
# ═══════════════════════════════════════════════════════════════


def tokenize(code):
    tokens = []
    i = 0
    n = len(code)

    while i < n:
        ch = code[i]

        # Перенос строки
        if ch == "\r":
            tokens.append(("newline", "\n"))
            i += 2 if i + 1 < n and code[i + 1] == "\n" else 1
            continue
        if ch == "\n":
            tokens.append(("newline", "\n"))
            i += 1
            continue

        # Пробелы
        if ch in " \t":
            j = i
            while j < n and code[j] in " \t":
                j += 1
            tokens.append(("space", code[i:j]))
            i = j
            continue

        # Комментарий //
        if ch == "/" and i + 1 < n and code[i + 1] == "/":
            j = i
            while j < n and code[j] != "\n":
                j += 1
            tokens.append(("comment", code[i:j]))
            i = j
            continue

        # Строка "..."
        if ch == '"':
            j = i + 1
            while j < n:
                if code[j] == '"':
                    if j + 1 < n and code[j + 1] == '"':
                        j += 2
                    else:
                        j += 1
                        break
                else:
                    j += 1
            tokens.append(("string", code[i:j]))
            i = j
            continue

        # Число
        if ch.isdigit():
            j = i
            while j < n and (code[j].isdigit() or code[j] == "."):
                j += 1
            tokens.append(("number", code[i:j]))
            i = j
            continue

        # Операторы
        if ch in OPERATORS:
            if ch == "<" and i + 1 < n and code[i + 1] == ">":
                tokens.append(("operator", "<>"))
                i += 2
                continue
            if ch in "<>" and i + 1 < n and code[i + 1] == "=":
                tokens.append(("operator", code[i : i + 2]))
                i += 2
                continue
            tokens.append(("operator", ch))
            i += 1
            continue

        # Контекстная директива &НаКлиенте
        if ch == "&":
            j = i
            while j < n and (
                code[j].isalnum() or code[j] in {"_", "&"} or ord(code[j]) > 127
            ):
                j += 1
            word = code[i:j]
            if word in CONTEXT_DIRECTIVES:
                tokens.append(("context", word))
            else:
                tokens.append(("identifier", word))
            i = j
            continue

        # Директива #
        if ch == "#":
            j = i
            while j < n and code[j] not in "\r\n":
                j += 1
            tokens.append(("directive", code[i:j]))
            i = j
            continue

        # Идентификатор / ключевое слово
        if ch.isalpha() or ch == "_" or ord(ch) > 127:
            j = i
            while j < n and (code[j].isalnum() or code[j] == "_" or ord(code[j]) > 127):
                j += 1
            word = code[i:j]
            tokens.append(("keyword" if word in KEYWORDS else "identifier", word))
            i = j
            continue

        tokens.append(("other", ch))
        i += 1

    return tokens


# ═══════════════════════════════════════════════════════════════
#  Генератор HTML
# ═══════════════════════════════════════════════════════════════


def escape(text):
    return text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")


def nbsp(text):
    return text.replace(" ", "&nbsp;")


def token_html(typ, text):
    if typ == "newline":
        return "<br>"
    if typ == "space":
        return nbsp(escape(text))
    e = nbsp(escape(text))
    color = COLORS.get(typ)
    return f'<font color="{color}">{e}</font>' if color else e


def generate(code):
    tokens = tokenize(code)
    inner = "".join(token_html(t, v) for t, v in tokens)
    return (
        f'<p class="V8SH_chapter">Пример:</p>'
        f'<table width="100%" bgcolor="#f7f7f7">'
        f"<tbody><tr><td>"
        f'<font face="Courier New"> {inner}</font><br>'
        f"</td></tr></tbody></table>"
    )


# ═══════════════════════════════════════════════════════════════
#  Запуск
# ═══════════════════════════════════════════════════════════════

if __name__ == "__main__":
    code = CODE_1C.strip()
    result = generate(code)

    # Сохраняем результат
    with open("result_code.html", "w", encoding="utf-8") as f:
        f.write(result)

    # Сохраняем предпросмотр
    preview = (
        '<!DOCTYPE html><html><head><meta charset="utf-8">'
        "<title>Предпросмотр</title></head><body>"
        f"<h3>Предпросмотр:</h3>{result}"
        f'<h3>HTML:</h3><textarea style="width:100%;height:300px">'
        f"{escape(result)}</textarea></body></html>"
    )
    with open("preview_code.html", "w", encoding="utf-8") as f:
        f.write(preview)

    # Копируем в буфер обмена
    try:
        import subprocess

        subprocess.run("clip", input=result.encode("utf-8"), check=True, shell=True)
        print("HTML скопирован в буфер обмена!")
    except Exception:
        pass

    print(f"Сохранено: result_code.html")
    print(f"Предпросмотр: preview_code.html")
    print(f"\nHTML ({len(result)} символов):")
    print(result[:200] + "...")
