# imports

import os.path
import re
import sys
import shutil
import uuid
import markdown
import subprocess
from bs4 import BeautifulSoup
from slugify import slugify

# global vars

article_name = ""
output_programs = ""
index_hrefs = []
output_soup = ""
output_html = ""

# functions

def reformater_html(code_html):
    soup = BeautifulSoup(code_html, 'html.parser')
    return soup.prettify()

def find_programs_get_program_param(program_param, lines, i):
    program_start = i + 1
    j = 0
    while j < len(program_param):
        for key_param in program_param:
            if lines[program_start + j].startswith(key_param):
                valeur = lines[program_start + j][len(key_param):].strip()
                if valeur != '':
                    program_param[key_param] = valeur
        j += 1
    return(program_start + j)

def find_programs_convert_inline_code(program_param, lines, program_end):
    html_code = ''
    code = ''
    code_debut = program_end
    j = 0
    while True:

        try:
            if not lines[code_debut + j]: break
        except IndexError:
            html_code = "error : end of inline program not found..."
            break
        
        if '<!-- program>' in lines[code_debut + j]:
            html_code = "error : other start of inline program found..."
            break

        if '<program -->' in lines[code_debut + j]:
            break

        if lines[code_debut + j] != '':
            code += lines[code_debut + j]

        j += 1

    if html_code == "":

        echo_command = ["echo", code]
        
        if program_param['number:'] == '0':                        
            option_number = f"full,style={program_param['theme:']}"                        
        else:                        
            option_number = f"full,style={program_param['theme:']},linenos=1"

        pygmentize_command = [
            "pygmentize",
            "-f",
            "html",
            "-l",
            f"{program_param['language:']}",
            "-O",
            f"{option_number}"
        ]
        with subprocess.Popen(echo_command, stdout=subprocess.PIPE) as echo_proc:
            with subprocess.Popen(pygmentize_command, stdin=echo_proc.stdout, stdout=subprocess.PIPE) as pygmentize_proc:
                subprocess_output, _ = pygmentize_proc.communicate()

        return(subprocess_output.decode("utf-8"))

def find_programs_convert_file_code(program_param):
    html = f"{article_name}/{program_param['code:']}"
    check_file = os.path.isfile(html)

    if check_file:

        if program_param['number:'] == '0':
            option_number = f"full,style={program_param['theme:']}"
        else:
            option_number = f"full,style={program_param['theme:']},linenos=1"

        pygmentize_command =\
            "pygmentize "+\
            "-f "+\
            "html "+\
            "-l "+\
            f"{program_param['language:']} "+\
            "-O "+\
            f"{option_number} "+\
            f"{article_name}/{program_param['code:']}"

        return(subprocess.getoutput(pygmentize_command))
    
    else:
        
        return(f"error : , {article_name}/{program_param['code:']} no exist")

def find_programs_format_html_code(program_param, html_code):
    div_highlight_style =\
        "overflow: auto;"+\
        f"height: {program_param['box-height:']};"+\
        f"border-radius: {program_param['box-border-radius:']};"+\
        f"width: {program_param['box-width:']};"+\
        "margin: auto;"+\
        f"border: {program_param['box-border:']};"+\
        f"background: {program_param['box-background:']};"+\
        f"box-shadow: {program_param['box-shadow:']};"

    td_linenos_style = "td.linenos .normal {"+\
                        f"color: {program_param['number-color:']};"+\
                        f"background-color: {program_param['number-background-color:']};"+\
                        f"border: {program_param['number-border:']};"+\
                        f"border-radius: {program_param['number-border-radius:']};"+\
                        f"padding-left: {program_param['number-padding-left-right:']};"+\
                        f"padding-right: {program_param['number-padding-left-right:']};"+\
                        f"margin-left: {program_param['number-margin-left:']};"+\
                        f"margin-right: {program_param['number-margin-right:']};"+\
                        f"font-weight: {program_param['number-font-weight:']};"+\
                        "}"

    html_lignes = html_code.splitlines()

    for i, ligne in enumerate(html_lignes):
        if ligne.startswith('pre {'):
            del html_lignes[:i]
            break

    # html_lignes[0] = "<style id='css-style'>"
    html_lignes[0] = "<style>"
    
    html_lignes[1] = td_linenos_style
    html_code = "\n".join(html_lignes)
    
    soup = BeautifulSoup(html_code, 'html.parser')
    
    highlight_div = soup.find('div', attrs={'class': 'highlight'})

    if highlight_div:
        highlight_div['style'] = div_highlight_style

    html_code = soup.prettify()
    
    soup = BeautifulSoup(html_code, 'html.parser')
    
    balises_pre = soup.find_all('pre')

    for balise in balises_pre:

        balise['style'] = f"line-height: {program_param['box-line-height:']};"+\
                            f"margin-top: {program_param['box-margin-top:']};"+\
                            f"margin-bottom: {program_param['box-margin-bottom:']};"+\
                            f"margin-left: {program_param['box-margin-left:']};"+\
                            f"margin-right: {program_param['box-margin-right:']};"+\
                            f"font-family: {program_param['box-font-family:']};"+\
                            f"font-size: {program_param['box-font-size:']};"+\
                            "padding: 0;"

        if program_param['number:'] == '1':
            balise['style'] += "width: max-content;"

    html_code = soup.prettify()
    
    return(html_code)

def find_programs():

    global article_name
    global output_programs

    print(f"md2html.py : find_programs() : fichier markdown {article_name}/article.md")
    
    # on charge le fichier markdown dans la variable lines
    with open(f"{article_name}/article.md", 'r') as f:
        lines = f.readlines()

    cpt_program = 0
    
    # on boucle sur le fichier markdown
    for i, line in enumerate(lines):

        # on a trouvé une balise <program>
        if line.startswith('<!-- program>'):

            cpt_program += 1
            
            program_param = {
                'number:':'',
                'number-color:':'',
                'number-background-color:':'',
                'number-border:':'',
                'number-border-radius:':'',
                'number-padding-left-right:':'',
                'number-margin-left:':'',
                'number-margin-right:':'',
                'number-font-weight:':'',
                'box-background:':'',
                'box-border:':'',                 
                'box-border-radius:':'',
                'box-shadow:':'',
                'box-font-size:':'',
                'box-font-family:':'',
                'box-line-height:':'',
                'box-width:':'',
                'box-height:':'',
                'box-margin-top:':'',
                'box-margin-bottom:':'',
                'box-margin-left:':'',
                'box-margin-right:':'',
                'language:':'',
                'theme:':'',
                'code:':''
            }

            # on récupère la dernière ligne des paramètres de la balise <program>
            program_end = find_programs_get_program_param(program_param, lines, i)

            # code en ligne si pas de fichier
            if program_param['code:'] == "":
                             
                # on récupère le code en ligne et on le pygmentize vers du HTML
                html_code = find_programs_convert_inline_code(program_param, lines, program_end)
                                        
            else:

                # on récupère le fichier contenant le code et on le pygmentize vers du HTML
                html_code = find_programs_convert_file_code(program_param)

            if not html_code.startswith('error'):

                # on modifie les style de la boite contenant le code
                html_code = find_programs_format_html_code(program_param, html_code)
                
                html_code = html_code.replace('<body>', '')
                html_code = html_code.replace('</body>', '')
                html_code = html_code.replace('</html>', '')
                html_code = html_code.replace('</head>', '')

                identifiant_unique = uuid.uuid4()
                
                html_code = re.sub(r'^body', f".highlight-{identifiant_unique}", html_code, flags=re.MULTILINE)

                html_code = html_code.replace('class="highlight"', f'class="highlight-{identifiant_unique}"')
                html_code = html_code.replace('.normal', f".normal-{identifiant_unique}")
                html_code = html_code.replace('class="normal"', f'class="normal-{identifiant_unique}"')

            output_programs += html_code

        output_programs += line

    print(f"md2html.py : find_programs() : nombre de balise <program> trouvé : {cpt_program}")

def find_hrefs():

    global output_soup
    global article_name
    global output_html

    output_soup = BeautifulSoup(output_html, 'html.parser')
    print("md2html.py : find_hrefs() : conversion des tags <h3> vers <a href>")

    for h3 in output_soup.find_all("h3"):

        balise_section = output_soup.new_tag("section")
        balise_section.string = h3.string
        slugify_title = slugify(h3.string)
        balise_section.attrs['id'] = slugify_title
        h3.replace_with(balise_section)
        ahref = f"<a href='{article_name}/article.html#{slugify_title}' target='iframe_main_content' class='custom-link-list-index' onclick='click_index()'>{h3.string}</a>"
        index_hrefs.append(ahref)

    print("md2html.py : find_hrefs() : conversion des liens internes en index commençant par le caractère '-'")
    print("md2html.py : find_hrefs() : modification des liens externes pour s'ouvrir dans un nouvel onglet")

    for a in output_soup.find_all("a", href=True):

        try:
            
            if a.string.startswith('-'):

                index_hrefs.append(f"<a href='{article_name}/{a['href']}' target='iframe_main_content'  class='custom-link-list-index' onclick='click_index()'>{a.string.lstrip('-')}</a>")
                new_tag = output_soup.new_tag('span')
                new_tag.string = a.string.lstrip("-")
                a.replace_with(new_tag)

            href = a.get('href')
            if href.startswith('http'):
                if 'https' in href:
                    a['target'] = '_blank'
                    
        except AttributeError:
            
            print("md2html.py : AttributeError : 'NoneType' object has no attribute 'startswith'")
            print("md2html.py : AttributeError : => if a.string.startswith('-'):")

def update_md_file(arg_md_file):

    global article_name
    md_file = f"markdown/{arg_md_file}"
    check_file = os.path.isfile(md_file)
    if check_file == False:        
        return(True)
    path, extension = os.path.splitext(arg_md_file)
    if '-' in path:
        path = f"{path.split('-')[0]}/{path.split('-')[1]}"
    shutil.copy(md_file, f"{path}/article.md")
    print(f"md2html.py : update_md_file() : fichier source {md_file}")
    print(f"md2html.py : update_md_file() : fichier destination {path}/article.md")
    article_name = path
    print(f"md2html.py : update_md_file() : nom de l'article {article_name}")

# main

if len( sys.argv ) > 1:
    print("md2html.py : mettre à jour le fichier markdown vers son dossier")
    if update_md_file(sys.argv[1]):
        print("md2html.py : le fichier markdown n'existe pas")
        exit(1)
else:
    print("md2html.py : il manque le fichier markdown")
    exit(1)

print("md2html.py : recherche de sections de code <program>")
find_programs()

print("md2html.py : conversion du markdown vers html")
output_html = markdown.markdown(output_programs, extensions=['fenced_code', 'codehilite'])

print("md2html.py : création et recherche de liens pour la création d'un index<a>")
find_hrefs()

print("md2html.py : sauvegarde de l'index section.html")
file1 = open(f"{article_name}/sections.html", "w")
for i in index_hrefs:
    file1.write(i + '\n')
file1.close()

print("md2html.py : chargement du fichier md2html.css")
with open('md2html.css', 'r') as fichier:
    style_html = fichier.read()

print("md2html.py : chargement du fichier markdown.css")
with open('markdown.css', 'r') as fichier:
    style_markdown = fichier.read()

javascript = "<script>\n"+\
    "window.addEventListener('DOMContentLoaded', function() {\n"+\
        "var links = document.getElementsByTagName('a');\n"+\
        "for (var i = 0; i < links.length; i++) {\n"+\
            "links[i].addEventListener('click', function(event) {\n"+\
                "var link = event.target.href;\n"+\
                "if (link.includes('#')) {\n"+\
                    "event.preventDefault();\n"+\
                    "window.parent.postMessage({type: 'linkClicked', link: link}, '*');\n"+\
                "}\n"+\
            "});\n"+\
        "}\n"+\
    "});\n"+\
    "</script>\n"
    # "window.addEventListener('scroll', function() {\n"+\
    #     "if (window.scrollY > 200) {\n"+\
    #         "window.parent.postMessage('hide', '*');\n"+\
    #     "}\n"+\
    #     "else {\n"+\
    #         "window.parent.postMessage('show', '*');\n"+\
    #     "}\n"+\
    # "});\n"+\

print("md2html.py : création du fichier html")
fichier_html =  "<!DOCTYPE html>"+\
    "<html lang='fr'>"+\
        "<head>"+\
            "<meta charset='UTF-8' />"+\
            "<meta name='viewport' content='width=device-width'>"+\
            "<style>"+\
                f"{style_html}{style_markdown}"+\
            "</style>"+\
        "</head>"+\
        "<body>"+\
            f"{output_soup.prettify()}"+\
        "</body>"+\
        f"{javascript}"+\
    "</html>"

print("md2html.py : sauvegarde du fichier html article.html")
file1 = open(f"{article_name}/article.html", "w")
file1.write(reformater_html(fichier_html))
file1.close()

print("md2html.py : fin")
exit(0)