#!/usr/bin/env python3
"""Validate the IP-XACT components against the official IEEE 1685-2014 schema.

usage: validate_ipxact.py SCHEMA_DIR LOG
SCHEMA_DIR holds index.xsd and the files it includes, downloaded unchanged from
http://www.accellera.org/XMLSchema/IPXACT/1685-2014/ . The log records the sha256
of every schema file, the xmllint version, the result for each component and a
negative control (a deliberately malformed copy that must fail).
"""
import hashlib
import pathlib
import subprocess
import sys
import tempfile

REPO = pathlib.Path(__file__).resolve().parents[2]
FILES = ["integration/ipxact/cv_x1_pro_axi.xml", "integration/ipxact/cv_gemv_axi.xml",
         "integration/ipxact/public/cv_gemv_axi.xml"]


def lint(schema, path):
    p = subprocess.run(["xmllint", "--noout", "--schema", str(schema / "index.xsd"), str(path)],
                       capture_output=True, text=True)
    return p.returncode, (p.stdout + p.stderr).replace(str(path), path.name).strip()


def main():
    schema, log = pathlib.Path(sys.argv[1]).resolve(), pathlib.Path(sys.argv[2])
    ver = subprocess.run(["xmllint", "--version"], capture_output=True, text=True)
    lines = ["IP-XACT validation (IEEE 1685-2014)",
             "schema source: http://www.accellera.org/XMLSchema/IPXACT/1685-2014/index.xsd and its includes",
             "validator: " + (ver.stdout + ver.stderr).splitlines()[0], "", "schema files (sha256):"]
    for f in sorted(schema.glob("*.xsd")):
        lines.append(f"  {hashlib.sha256(f.read_bytes()).hexdigest()}  {f.name}")
    lines.append("")
    ok = True
    for rel in FILES:
        path = REPO / rel
        rc, out = lint(schema, path)
        ok &= rc == 0
        lines.append(f"{rel}  sha256 {hashlib.sha256(path.read_bytes()).hexdigest()}")
        lines.append(f"  xmllint --noout --schema index.xsd {path.name}: exit {rc}: {out}")
    with tempfile.TemporaryDirectory() as td:
        bad = pathlib.Path(td) / "negative_control.xml"
        bad.write_text((REPO / FILES[0]).read_text().replace("<ipxact:addressOffset>", "<ipxact:addrOffset>", 1)
                       .replace("</ipxact:addressOffset>", "</ipxact:addrOffset>", 1))
        rc, out = lint(schema, bad)
        lines += ["", "negative control (first addressOffset renamed to addrOffset): exit "
                  f"{rc} (expected non-zero)", "  " + out.splitlines()[-1]]
        ok &= rc != 0
    lines += ["", "RESULT: " + ("PASS" if ok else "FAIL")]
    log.write_text("\n".join(lines) + "\n")
    print("\n".join(lines[-3:]))
    sys.exit(0 if ok else 1)


if __name__ == "__main__":
    main()
