#!/usr/bin/env python3

"""Outputs differences between two iXBRL documents.  Specifically, the
only differences reported are where two facts have different values.
Facts which only occur in one of the inputs are not reported - only where
a fact occurs in both inputs but with different values.  The differencing
is context-aware, so that two facts are considered the same only if they
have the same contexts.
"""

import datetime
from lxml import etree as ET
import sys
import argparse
import csv

from ixbrl_parse.ixbrl import parse, Entity, Period, Instant, Dimension

maxwidth=40

parser = argparse.ArgumentParser(
    description=__doc__
)
parser.add_argument('input', metavar='input', nargs=2,
                    help='Input files to compare')
parser.add_argument('--format', '-f',
                    default="text",
                    help="Output format, one of 'text', 'csv' (default: text)")

# Parse arguments
args = parser.parse_args(sys.argv[1:])

tree1 = ET.parse(args.input[0])
tree2 = ET.parse(args.input[1])

i1 = parse(tree1)
i2 = parse(tree2)

indexes = {}

def compare(a, b, path=[], csv=False):

    ret = []

    b_map = {k.localname: v for k, v in b.values.items()}

    for name, value in a.values.items():

        if name.localname in b_map:
            vala = str(value.to_value().get_value())[:50]
            valb = str(b_map[name.localname].to_value().get_value())[:50]
            if vala != valb:

                ret.append({
                    "path": path,
                    "name": name.localname,
                    "a": vala,
                    "b": valb,
                })

    for rel, ctxt in a.children.items():
        if rel in b.children:
            ret.extend(compare(a.children[rel], b.children[rel], path + [rel]))

    return ret

diffs = compare(i1.root, i2.root, [], args.format == "csv")

if args.format == "csv":

    fields = ["entity", "scheme", "start", "end", "instant", "name", "a", "b"]
    fieldset = set(fields)

    for diff in diffs:
        for p in diff["path"]:
            if isinstance(p, Dimension):
                if p.dimension.localname not in fieldset:
                    fields.append(p.dimension.localname)
                    fieldset.add(p.dimension.localname)

    writer = csv.DictWriter(sys.stdout, fields)
    writer.writeheader()

    for diff in diffs:
        row = {
            "name": diff["name"],
            "a": diff["a"],
            "b": diff["b"]
        }
        for p in diff["path"]:
            if isinstance(p, Entity):
                row["entity"] = p.id
            if isinstance(p, Period):
                row["start"] = str(p.start)
                row["end"] = str(p.end)
            if isinstance(p, Instant):
                row["instant"] = str(p.instant)
            if isinstance(p, Dimension):
                row[p.dimension.localname] = p.value.localname
        writer.writerow(row)

else:

    for diff in diffs:
        print("At:")

        for p in diff["path"]:
            if isinstance(p, Entity):
                print("  Entity %s (%s)" % (p.id, p.scheme))
            elif isinstance(p, Period):
                print("  Period %s - %s" % (p.start, p.end))
            elif isinstance(p, Instant):
                print("  Instant %s" % p.instant)
            elif isinstance(p, Dimension):
                print("  Dimension %s: %s" % (p.dimension, p.value))
        print("Fact %s:" % diff["name"])
        print("  A: %s" % diff["a"])
        print("  B: %s" % diff["b"])
        print()

