#!/usr/bin/env python

# ************************************************************************
# * Copyright (c) 2022 Yorik van Havre <yorik@uncreated.net>             *
# *                                                                      *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL)   *
# * as published by the Free Software Foundation; either version 2 of    *
# * the License, or (at your option) any later version.                  *
# * for detail see the LICENCE text file.                                *
# *                                                                      *
# * This program is distributed in the hope that it will be useful,      *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
# * GNU Library General Public License for more details.                 *
# *                                                                      *
# * You should have received a copy of the GNU Library General Public    *
# * License along with this program; if not, write to the Free Software  *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 *
# * USA                                                                  *
# *                                                                      *
# ************************************************************************

"""This script produces an index.html file and an images/ folder which
shows and allows to download the contents of the library"""

import os
import zipfile
import hashlib
import urllib.request
import urllib.parse

# path definitions
homefolder = os.path.abspath(os.curdir)
imagefolder = "thumbnails"
htmlfile = os.path.join(homefolder, "index.html")
baseurl = "https://github.com/FreeCAD/FreeCAD-library/blob/master/"
excludelist = ["thumbnails"]

# icons
defaulticon = os.path.join(imagefolder, "freecad-document.svg")
gridicon = os.path.join(imagefolder, "icon-grid.svg")
listicon = os.path.join(imagefolder, "icon-list.svg")
stepicon = os.path.join(imagefolder, "icon-grey.svg")
brepicon = os.path.join(imagefolder, "icon-blue.svg")
stlicon = os.path.join(imagefolder, "icon-green.svg")
collapseicon = os.path.join(imagefolder, "icon-right.svg")
expandicon = os.path.join(imagefolder, "icon-down.svg")

# html template
template = """<html>
    <head>
        <title>FreeCAD Library</title>
        <style>
body {
    font-family: Arial,sans;
    color: black;
    background: white;
}
a:link, a:visited {
    color: black;
    text-decoration: none;
}
img {
    width: 16px;
}
h1, h2, h3, h4, h5, h6, .h7, .h8, .h9 {
    clear: both;
    margin: 0;
    cursor: pointer;
    font-size: 1em;
}
.collapsable {
    border-left: 1px solid grey;
    padding-left: 8px;
    margin-left: 5px;
}
.cards {
    margin: 0;
}
.card {
    float:left;
    width: 128px;
    margin: 4px;
}
.icon {
    width: 128px;
}
.hicon {
    width: 12px;
    margin-right: 4px;
}
.name {
    clear: left;
    float: left;
    overflow-wrap: break-word;
    width: 128px;
}
.links {
    float: left;
}
.fullwidth {
    width: 100% !important;
}
.smallicon {
    width: 16px !important;
    margin-right: 8px;
    float: left !important;
}
.largetext {
    clear: none !important;
    width: auto !important;
    margin-right: 8px;
}
.hidden {
    display: none;
}
.iconselected {
    border: 2px solid black;
}
        </style>
        <script>
function seticon() {
    collection = document.getElementsByClassName("card");
    for (let i = 0; i < collection.length; i++) {
        collection[i].classList.remove("fullwidth")
    }
    collection = document.getElementsByClassName("icon");
    for (let i = 0; i < collection.length; i++) {
        collection[i].classList.remove("smallicon")
    }
    collection = document.getElementsByClassName("name");
    for (let i = 0; i < collection.length; i++) {
        collection[i].classList.remove("largetext")
    }
    icon_icon = document.getElementById("icon_icon");
    icon_icon.classList.add("iconselected")
    icon_grid = document.getElementById("icon_grid");
    icon_grid.classList.remove("iconselected")
}
function setgrid() {
    collection = document.getElementsByClassName("card");
    for (let i = 0; i < collection.length; i++) {
      collection[i].classList.add("fullwidth")
    }
    collection = document.getElementsByClassName("icon");
    for (let i = 0; i < collection.length; i++) {
        collection[i].classList.add("smallicon")
    }
    collection = document.getElementsByClassName("name");
    for (let i = 0; i < collection.length; i++) {
        collection[i].classList.add("largetext")
    }
    icon_icon = document.getElementById("icon_icon");
    icon_icon.classList.remove("iconselected")
    icon_grid = document.getElementById("icon_grid");
    icon_grid.classList.add("iconselected")
}
function collapse(elt) {
    ndiv = elt.parentElement.nextSibling.nextSibling;
    if (ndiv.classList.contains("hidden")) {
        elt.src = "<!--expandicon-->";
        ndiv.classList.remove("hidden");
    } else {
        elt.src = "<!--collapseicon-->";
        ndiv.classList.add("hidden");
    }
}
        </script>
    </head>
    <body>
        <div class="nav">
            <a id="icon_icon" class="navicon iconselected" href="#" title="icon view" onclick="seticon()">
                <img src="<!--gridicon-->"/>
            </a>
            <a id="icon_grid" class="navicon" href="#" title="list view" onclick="setgrid()">
                <img src="<!--listicon-->"/>
            </a>
        </div>
<!--contents-->
    </body>
</html>"""


def build_html(dirpath, level=1):

    """walks a directory and builds cards from its contents"""

    html = ""
    if os.path.isdir(dirpath):
        html += build_title(dirpath, level)
        if level > 1:
            offset = 5 + (level - 2) * 2
            html += '<div class="collapsable hidden">\n'
        nodes = os.listdir(dirpath)
        nodes = [node for node in nodes if node[0] != "."]
        nodes = [node for node in nodes if node not in excludelist]
        nodes = [os.path.join(dirpath, node) for node in nodes]
        dirs = [node for node in nodes if os.path.isdir(node)]
        dirs = sorted(dirs)
        files = [node for node in nodes if node.lower().endswith(".fcstd")]
        files = sorted(files)
        for fpath in dirs:
            html += build_html(fpath, level+1)
        if files:
            html += '<div class="cards">\n'
            for fpath in files:
                html += build_card(fpath)
            html += '</div>\n'
        if level > 1:
            html += '</div>\n'
    return html


def build_title(dirpath, level):

    """builds an html title from a path"""

    if level == 1:
        # do not print the first-level title
        return ""
    sl = str(level)
    sn = '<img class="hicon" src="'+collapseicon+'"/>'
    sn += os.path.basename(dirpath)
    if level < 7:
        title = '<h' + sl + ' onclick="collapse(this.children[0])">'
        title += sn + '</h' + sl + '>\n'
    else:
        title = '<div class="h' + sl + '" onclick="collapse(this.children[0])">'
        title += sn + '</div>\n'
    return title


def build_card(filepath):

    """builds an HTML card for a given file"""

    print("Building card for", filepath)
    html = ""
    if os.path.exists(filepath):
        basename = os.path.splitext(filepath)[0]
        name = os.path.basename(basename)
        iconpath = get_icon(filepath)
        raw = "?raw=true"
        fileurl = baseurl + clean_path(filepath) + raw
        html += '<div class="card">'
        html += '<a title="FCSTD version" href="' + fileurl + '">'
        html += '<img class="icon" src="' + clean_path(iconpath) + '"/>'
        html += '<div class="name">' + name + '</div>'
        html += '</a>'
        html += '<div class="links">'
        exts = {'STEP': (".stp", ".step", ".STP", ".STEP"),
                'BREP': (".brp", ".brep", ".BRP", ".BREP"),
                'STL':  (".stl", ".STL")}
        icons = {'STEP': stepicon,
                 'BREP': brepicon,
                 'STL': stlicon}
        for name, exts in exts.items():
            for ext in exts:
                if os.path.exists(basename + ext):
                    exturl = baseurl + clean_path(basename + ext) + raw
                    html += ' <a href="' + exturl
                    html += '" title="' + name + ' version">'
                    html += '<img src="' + icons[name] + '"/>'
                    html += '</a>'
                    break
        html += '</div>'  # links
        html += '</div>\n'  # card
    return html


def get_icon(filepath):

    """returns a thumbnail image path for a given file path"""

    iconname = get_hashname(filepath)
    iconurl = os.path.join(imagefolder, iconname)
    iconpath = os.path.join(homefolder, iconurl)
    try:
        zfile = zipfile.ZipFile(filepath)
    except Exception:
        return defaulticon
    if "thumbnails/Thumbnail.png" in zfile.namelist():
        data = zfile.read("thumbnails/Thumbnail.png")
        thumb = open(iconpath, "wb")
        thumb.write(data)
        thumb.close()
    else:
        return defaulticon
    if not os.path.exists(iconpath):
        return defaulticon
    return iconurl


def get_hashname(filepath):

    """creates a png filename for a given file path"""

    filepath = clean_path(filepath)
    return hashlib.md5(filepath.encode()).hexdigest()+".png"


def clean_path(filepath):

    """cleans a file path into subfolder/subfolder/file form"""

    if filepath.startswith(homefolder):
        # strip local part od the path
        filepath = filepath[len(homefolder):]
    filepath = filepath.replace("\\", "/")
    if filepath.startswith("/"):
        filepath = filepath[1:]
    filepath = urllib.parse.quote(filepath)
    return filepath


if __name__ == "__main__":
    html = build_html(homefolder)
    html = template.replace("<!--contents-->", html)
    html = html.replace("<!--listicon-->", listicon)
    html = html.replace("<!--gridicon-->", gridicon)
    html = html.replace("<!--collapseicon-->", collapseicon)
    html = html.replace("<!--expandicon-->", expandicon)
    with open(htmlfile, "w") as index:
        index.write(html)
    print("Saving", htmlfile, "... All done!")