#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# For more information, please refer to <http://unlicense.org/>

"""
Parses sitemap.xml and turns it into Makefile rules.

Usage:

    ./create-html-download-rules-from-sitemap.py GENERATED-FILE.mk
"""

import sys
from urllib.parse import urlparse
from contextlib import redirect_stdout
from io import StringIO
from pathlib import Path

from lxml import etree

# Using exit codes defined in sysexits.h:
# https://www.freebsd.org/cgi/man.cgi?query=sysexits&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html
EXIT_USAGE = 64
EXIT_DATAERR = 65

try:
    output_file = Path(sys.argv[1])
except IndexError:
    print("You forgot to suppy the output path!", file=sys.stderr)
    sys.exit(EXIT_USAGE)

try:
    tree = etree.parse('sitemap.xml')
except FileNotFoundError:
    print("sitemap.xml does not exist. Please download it first (use make!)",
          file=sys.stdout)
    sys.exit(EXIT_DATAERR)

# The root element.
urlset_elem = tree.getroot()

# We're going to capture ALL OF THE PRINTs in a variable, and write it out
# all at once "atomically", so that, if this script crashes, make(1)
# doesn't believe the erroneous file is the most up-to-date version.
output_accumulator = StringIO()
with redirect_stdout(output_accumulator):
    print("# Autogenerated file. DO NOT MODIFY")
    print()
    print("# Generic rule to download a file.")
    print("CURL.html = curl --fail $(CURLOPTIONS) -o $@")
    print()

    posts = set()

    # Iterate over each <url> element. Almost every <url> is a post.
    for url_elem in urlset_elem.iter('{*}url'):
        # Get the text of the <loc> element within the <url>
        # This is the URL to the post.
        url = urlparse(url_elem.find('{*}loc').text)
        # I'm not expecting any of these:
        assert not url.query
        assert not url.params
        assert not url.fragment

        # Recombine the URL to "normalize" it.
        raw_url = url.geturl()

        # Break down a path like '/2018/06/13/grace-hopper-disclosure/'
        # into its components.
        try:
            year, month, day, title = url.path.strip('/').split('/')
        except ValueError:
            print(f"Skipping: {url.geturl()}. It doesn't seem important "
                    "anyway.", file=sys.stderr)
            continue

        # Jekyll wants posts in this format: YEAR-MONTH-DAY-title.MARKUP
        # See: https://jekyllrb.com/docs/posts/
        slug = '-'.join((year, month, day, title))
        # TODO: do something with posts that have <image:image> elements

        # Create the Makefile rule:
        target = f"_src/{slug}.html"
        print(f"{target}:")
        print(f"\t$(CURL.html) {raw_url}")

        posts.add(target)

    # Create a 'phony' rule to download all the HTML.
    print()
    print("HTML =", *posts)
    print(".PHONY: download-html")
    print("download-html: $(HTML)")

# Write all the accumlated output "atomically" in one go:
# (helps make(1) not use a half-written version of the file).
output_file.write_text(output_accumulator.getvalue(), encoding='UTF-8')
