#!/usr/bin/env python

# Copyright (c) 2017, NORDUnet A/S.
# See LICENSE for licensing information.

import argparse
import sys
import readconfig
import re
import base64
import shutil
from datetime import datetime
from orderedtree import TreeNode

def level_is_list(schema):
    if len(schema.keys()) != 1:
        return False
    return schema.keys()[0] == "[]"

def traverse_schema_part(schema):
    tree = TreeNode()
    for k in sorted(schema.keys()):
        schema_part = schema.get(k)
        result = None
        if isinstance(schema_part, tuple):
            (lowleveldatatype, highleveldatatype) = schema_part
            if isinstance(highleveldatatype, list):
                formatted_datatype = "|".join(["**"+t+"**" for t in highleveldatatype])
            else:
                formatted_datatype = "__" + highleveldatatype.replace(" ", "-") + "__"
            if k == "[]":
                result = "list of " + formatted_datatype
            else:
                result = "**" + k + "**: " + formatted_datatype

            tree.add(k, (result, []))

        elif isinstance(schema_part, dict):
            if k == "[]":
                result = "list of items"
            else:
                if level_is_list(schema_part):
                    formatted_datatype = "(list of items)"
                    schema_part = schema_part["[]"]
                else:
                    formatted_datatype = ""
                result = "**"+k+"**: " + formatted_datatype
            subtree = traverse_schema_part(schema_part)
            tree.add(k, (result, []), subtree=subtree)
        else:
            print >>sys.stderr, "unknown type", type(schema_part)
            sys.exit(1)
    return tree

def traverse_schema(schema):
    transformed_schema = readconfig.transform_schema(schema)
    tree = traverse_schema_part(transformed_schema)
    return tree

def is_adoc_header(row):
    return set(row.rstrip()) == set("=")

def is_adoc_section(row):
    return set(row.rstrip()) == set("-")

def parse_manpage(filename):
    f = open(filename)
    header = []
    for row in f:
        if is_adoc_header(row):
            break
        header.append(row.rstrip("\n"))
    section_name = None
    section = []
    sections = []
    for row in f:
        if is_adoc_section(row):
            if section_name:
                sections.append((section_name, section[:-1]))
            section_name = section[-1]
            section = []
        else:
            section.append(row.rstrip("\n"))
    if section_name:
        sections.append((section_name, section))
    return (header, sections)

def is_manpage_option(row):
    return row.endswith("::")

def extract_option_name(row):
    if row == None:
        return (None, None)
    (name_part, _, _) = row.lstrip().partition(":")
    depth = len(row) - len(row.rstrip(":")) - 2
    return (name_part.replace("*", ""), depth)

def parse_manpage_options(option_rows):
    option_name_row = None
    options = []
    option = []
    for row in option_rows:
        if is_manpage_option(row):
            options.append((option_name_row, option))
            option_name_row = row
            option = []
        else:
            option.append(row)
    options.append((option_name_row, option))
    return options

def build_tree(l, key):
    tree = TreeNode()
    curpath = []
    for e in l:
        (k, depth) = key(e)
        if depth > len(curpath):
            print >>sys.stderr, "depth", depth, "from", e, "greater than length of curpath", curpath
            sys.exit(1)
        curpath = curpath[:depth]
        tree.walk(curpath).add(k, e)
        curpath.append(k)
    return tree

def transfer_tree(current, wanted):
    for name in wanted.iterkeys():
        if name in current and name != None:
            transfer_tree(current[name], wanted[name])
    if wanted.entry:
        wanted.entry = (wanted.entry[0], current.entry[1])

def print_tree(f, tree, depth=0):
    if tree.entry:
        (section, rows) = tree.entry
        print >>f, "   " * depth + section + (depth+1) * ":"
        has_content = False
        for row in rows:
            if row.strip():
                has_content = True
            print >>f, row
        if not has_content:
            print >>f, "// " + "   " * depth + "write description here"
            print >>f, ""
    for name in tree.iterkeys():
        print_tree(f, tree[name], depth=depth+1)

def rewrite_options(f, schema, options):
    wanted = traverse_schema(schema)
    current = build_tree(options, lambda e: extract_option_name(e[0]))
    transfer_tree(current, wanted)
    print_tree(f, wanted)

def rewrite_manpage(filename, schema, man_source, man_manual, title, name):
    try:
        (header, sections) = parse_manpage(filename)
    except IOError:
        sections = []
    sections_dict = dict(sections)
    section_names = [e for e, _ in sections]
    options = parse_manpage_options(sections_dict.get("OPTIONS", []))
    sections_dict["NAME"] = [name]
    if "NAME" not in section_names:
        section_names.append("NAME")
    if "OPTIONS" not in section_names:
        section_names.append("OPTIONS")
    f = open(filename + ".new", "w")
    print >>f, ":man source:   " + man_source
    print >>f, ":man manual:   " + man_manual
    print >>f, title
    print >>f, len(title) * "="
    print >>f, ""
    for section_name in section_names:
        print >>f, section_name
        print >>f, len(section_name) * "-"
        if section_name == "OPTIONS":
            rewrite_options(f, schema, options)
            continue
        for row in sections_dict[section_name]:
            print >>f, row
        print >>f, ""
    f.close()
    shutil.move(filename + ".new", filename)