#!/usr/bin/python3
"""
Create a zip archive with all files in specified formats from given directory.
"""
import argparse
import os
import sys
import time
from xml.etree import ElementTree, cElementTree
from zipfile import ZipFile, ZIP_DEFLATED

def file_paths(input_path, zip_formats):
    """Collect all files with paths in specified formats from given directory.

    :param str input_path: path to directory from which files are to be collected
    :param list zip_formats: a list containing accepted documentation formats
        example: ["pdf", "epub", "single-html"]
    :return: a generator of matching file paths
    """
    for rootdir, subdirs, files in os.walk(input_path):
        for filename in files:
            filepath = os.path.join(rootdir, filename)
            for format in zip_formats:
                format_relative_path = os.path.join(input_path, format)
                if rootdir.startswith(format_relative_path):
                    yield filepath
                    break

def create_zip_archive(input_path, output_path, zip_formats):
    """Create zip archive with all files in specified formats from given directory.

    :param str input_path: path to directory from which files are to be archived
    :param str zip_formats: a string containing accepted documentation formats,
        which are also the names of directories to be archived
        example: "pdf,epub,single-html"
    :param str output_path:  archive name including path where to be saved
    """
    zip_formats = zip_formats.split(",")
    # writing files to a zipfile
    with ZipFile(output_path, 'w', ZIP_DEFLATED) as zip:
        # writing each file one by one
        for filepath in file_paths(input_path, zip_formats):
            filename = filepath.replace(input_path, "")
            zip.write(filepath, filename)


def write_archive_cache(cache_path, relative_path, product, docset, language):
    """
    Create an XML file that contains information about the ZIP
    including its path. This is required for the
    'docserv-build-navigation' command.
    """
    root = cElementTree.Element("archive",
                                lang=language,
                                productid=product,
                                setid=docset,
                                cachedate=str(time.time()))
    cElementTree.SubElement(
        root, "path", format='zip').text = relative_path

    full_cache_path = os.path.join(cache_path, language, product, docset, 'zip')
    os.makedirs(full_cache_path, exist_ok = True)
    tree = cElementTree.ElementTree(root)
    tree.write(os.path.join(full_cache_path, 'product-zip.xml'))


def parse_cli(cliargs=None):
    """Parse CLI with :class:`argparse.ArgumentParser` and return parsed result.

    :param list cliargs: Arguments to parse or None (=use sys.argv)
    :return: parsed CLI result
    :rtype: :class:`argparse.Namespace`
    """
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("-i", "--input-path",
                        dest="input_path",
                        help="Path to directory from which files are to be archived.",
                        )
    parser.add_argument("-o", "--output-path",
                        dest="output_path",
                        help="Path to directory where the archive is to be saved.",
                        )
    parser.add_argument("-f", "--zip-formats",
                        dest="zip_formats",
                        help="Documentation formats to save in the archive.",
                        )
    parser.add_argument("-c", "--cache-path",
                        dest="cache_path",
                        help="Path to metadata cache directory.",
                        )
    parser.add_argument("-r", "--relative-output-path",
                        dest="relative_output_path",
                        help="Path to directory where the archive is to be saved, relative to to top=level Docserv2 output dir.",
                        )
    parser.add_argument("-p", "--product",
                        dest="product",
                        help="Product that was built.",
                        )
    parser.add_argument("-d", "--docset",
                        dest="docset",
                        help="Docset that was built.",
                        )
    parser.add_argument("-l", "--language",
                        dest="language",
                        help="Language that was built.",
                        )
    args = parser.parse_args(args=cliargs)

    return args

if __name__ == "__main__":
    args = parse_cli()
    create_zip_archive(args.input_path, args.output_path, args.zip_formats)
    write_archive_cache(args.cache_path, args.relative_output_path, args.product, args.docset, args.language)
    sys.exit(0)
