package ctbrec.docs;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AbstractDocServlet extends HttpServlet {

    private static final transient Logger LOG = LoggerFactory.getLogger(AbstractDocServlet.class);

    String loadFile(String resource) throws IOException {
        InputStream resourceAsStream = getClass().getResourceAsStream(resource);
        if(resourceAsStream == null) {
            throw new FileNotFoundException();
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int length = 0;
        byte[] buffer = new byte[1024];
        while( (length = resourceAsStream.read(buffer)) >= 0 ) {
            out.write(buffer, 0, length);
        }
        return new String(out.toByteArray(), "utf-8");
    }

    String getHeader() throws IOException {
        return loadFile("/html/docs/header.html");
    }

    String getFooter() throws IOException {
        return loadFile("/html/docs/footer.html");
    }

    List<String> getPages() throws IOException {
        List<String> pages = new ArrayList<>();
        URL resource = getClass().getResource("/html/docs");
        if(Objects.equals(resource.getProtocol(), "file")) {
            LOG.debug("FILE {}", resource);
            indexDirectory(resource, pages);
        } else if(Objects.equals(resource.getProtocol(), "jar")) {
            LOG.debug("JAR {}", resource);
            indexJar(resource, pages);
        }
        pages.add("index.md");
        Collections.sort(pages, (a, b) -> a.compareToIgnoreCase(b));
        return pages;
    }

    private void indexJar(URL resource, List<String> pages) throws IOException {
        String fileUrl = resource.getFile();
        fileUrl = URLDecoder.decode(fileUrl, StandardCharsets.UTF_8);
        int colon = fileUrl.indexOf(':');
        int exclamation = fileUrl.indexOf('!');
        String jar = fileUrl.substring(colon + 1, exclamation);
        String internalFile = fileUrl.substring(exclamation + 2);
        try (JarFile jarFile = new JarFile(jar)) {
            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry jarEntry = entries.nextElement();
                String name = jarEntry.getName();
                if (name.startsWith(internalFile) && name.toLowerCase().endsWith(".md")) {
                    pages.add(name.substring(name.lastIndexOf('/') + 1));
                }
            }
        }
    }

    private void indexDirectory(URL resource, List<String> pages) {
        File docs = new File(resource.getFile());
        String[] files = docs.list((dir, name) -> name.toLowerCase().endsWith(".md"));
        pages.addAll(Arrays.asList(files));
    }

    String loadMarkdown(String path) throws IOException {
        String resource = "/html" + path;
        return loadFile(resource);
    }

    protected void error(HttpServletResponse resp, int status, String message) throws IOException {
        resp.setStatus(status);
        resp.getWriter().println(getHeader());
        String html = loadFile("/html/docs/" + status + ".html");
        if(message == null || message.trim().isEmpty()) {
            message = "";
        }
        html = html.replace("{message}", message);
        resp.getWriter().println(html);
        resp.getWriter().println(getFooter());
    }
}
