"""
Created on Fri Jun 26 19:10:58 2015

@author: pietro
"""

import argparse
import os
import sys

from urllib.request import urlopen

from build_html import (
    header1_tmpl,
    grass_version,
    headerpso_tmpl,
    write_html_footer,
)


def parse_options(lines, startswith="Opt"):
    def split_in_groups(lines):
        def count_par_diff(line):
            open_par = line.count("(")
            close_par = line.count(")")
            return open_par - close_par

        res = None
        diff = 0
        for line in lines:
            if line.startswith("case"):
                optname = line.split()[1][:-1]
                res = []
            #                if optname == 'G_OPT_R_BASENAME_INPUT':
            #                    import ipdb; ipdb.set_trace()
            elif line == "break;":
                diff = 0
                yield optname, res
            elif line.startswith("G_"):
                diff = count_par_diff(line)
            elif diff > 0:
                diff -= count_par_diff(line)
            else:
                res.append(line) if res is not None else None

    def split_opt_line(line):
        index = line.index("=")
        key = line[:index].strip()
        default = line[index + 1 :].strip()
        if default.startswith("_("):
            default = default[2:]
        return key, default

    def parse_glines(glines):
        res = {}
        key = None
        dynamic_answer = False
        for line in glines:
            if line.strip() == "/* start dynamic answer */":
                dynamic_answer = True
            if line.strip() == "/* end dynamic answer */":
                dynamic_answer = False
            if dynamic_answer or line.startswith("/*"):
                continue
            if line.startswith("/*"):
                continue
            if line.startswith(startswith) and line.endswith(";"):
                key, default = (w.strip() for w in split_opt_line(line[5:]))
                res[key] = default
            elif line.startswith(startswith):
                key, default = split_opt_line(line[5:])
                res[key] = [
                    default,
                ]
            else:
                if key is not None:
                    if key not in res:
                        res[key] = []
                    start, end = 0, -1
                    if line.startswith("_("):
                        start = 2
                    if line.endswith(");"):
                        end = -3
                    elif line.endswith(";"):
                        end = -2
                    res[key].append(line[start:end])
        # pprint(glines)
        # pprint(res)
        return res

    def clean_value(val):
        if isinstance(val, list):
            val = " ".join(val)
        return (
            (val.replace('"', "").replace("'", "'").strip().strip(";"))
            .strip()
            .strip("_(")
            .strip()
            .strip(")")
            .strip()
        )

    # with open(optionfile, mode='r') as optfile:
    lines = [line.strip() for line in lines]
    result = []
    for optname, glines in split_in_groups(lines):
        if glines:
            res = parse_glines(glines)
            if res:
                for key, val in res.items():
                    res[key] = clean_value(val)
                result.append((optname, res))
    return result


class OptTable:
    def __init__(self, list_of_dict):
        self.options = list_of_dict
        self.columns = sorted(set([key for _, d in self.options for key in d.keys()]))

    def csv(self, delimiter=";", endline="\n"):
        """Return a CSV string with the options"""
        csv = []
        csv.append(delimiter.join(self.columns))
        for optname, options in self.options:
            opts = [options.get(col, "") for col in self.columns]
            csv.append(
                delimiter.join(
                    [
                        optname,
                    ]
                    + opts
                )
            )
        return endline.join(csv)

    def html(self, endline="\n", indent="  ", toptions="border=1"):
        """Return a HTML table with the options"""
        html = ["<table{0}>".format(" " + toptions if toptions else "")]
        # write headers
        html.append(indent + "<thead>")
        html.append(indent + "<tr>")
        html.append(indent * 2 + "<th>{0}</th>".format("option"))
        for col in self.columns:
            html.append(indent * 2 + "<th>{0}</th>".format(col))
        html.append(indent + "</tr>")
        html.append(indent + "</thead>")
        html.append(indent + "<tbody>")
        for optname, options in self.options:
            html.append(indent + "<tr>")
            html.append(indent * 2 + "<td>{0}</td>".format(optname))
            for col in self.columns:
                html.append(indent * 2 + "<td>{0}</td>".format(options.get(col, "")))
            html.append(indent + "</tr>")
        html.append(indent + "</tbody>")
        html.append("</table>")
        return endline.join(html)

    def _repr_html_(self):
        """Method used by IPython notebook"""
        return self.html()


if __name__ == "__main__":
    URL = (
        "https://trac.osgeo.org/grass/browser/grass/"
        "trunk/lib/gis/parser_standard_options.c?format=txt"
    )
    parser = argparse.ArgumentParser(
        description="Extract GRASS default " "options from link."
    )
    parser.add_argument(
        "-f",
        "--format",
        default="html",
        dest="format",
        choices=["html", "csv", "grass"],
        help="Define the output format",
    )
    parser.add_argument(
        "-l",
        "--link",
        default=URL,
        dest="url",
        type=str,
        help="Provide the url with the file to parse",
    )
    parser.add_argument(
        "-t",
        "--text",
        dest="text",
        type=argparse.FileType("r"),
        help="Provide the file to parse",
    )
    parser.add_argument(
        "-o",
        "--output",
        default=sys.stdout,
        dest="output",
        type=argparse.FileType("w"),
        help="Provide the url with the file to parse",
    )
    parser.add_argument(
        "-s",
        "--starts-with",
        default="Opt",
        dest="startswith",
        type=str,
        help="Extract only the options that starts with this",
    )
    parser.add_argument(
        "-p",
        "--html_params",
        default="border=1",
        type=str,
        dest="htmlparmas",
        help="Options for the HTML table",
    )
    args = parser.parse_args()

    cfile = args.text if args.text else urlopen(args.url, proxies=None)

    options = OptTable(parse_options(cfile.readlines(), startswith=args.startswith))
    outform = args.format
    if outform in ["csv", "html"]:
        print(getattr(options, outform)(), file=args.output)
        args.output.close()
    else:
        year = os.getenv("VERSION_DATE")
        name = args.output.name
        args.output.close()
        topicsfile = open(name, "w")
        topicsfile.write(
            header1_tmpl.substitute(
                title="GRASS GIS "
                "%s Reference Manual: Parser standard options index" % grass_version
            )
        )
        topicsfile.write(headerpso_tmpl)
        topicsfile.write(options.html(toptions=args.htmlparmas))
        write_html_footer(topicsfile, "index.html", year)
        topicsfile.close()
