#!/usr/bin/env python3
# $Id: ppauto_layout 117 2026-09-16 09:00:34Z peter $
#
# ppauto_layout --- the CLI entry point for auto_layout.py's own
# library functions. ADDED 2026-08-26, per Péter's own direct
# preference (no extension on executable files, a project-specific
# "pp" prefix) -- see ppnetlist's own header comment for the full
# real account of why this is a real, separate file rather than a
# direct rename of auto_layout.py itself: that module is genuinely
# BOTH a real CLI tool and a densely cross-imported library
# (kicad_layout.py, render.py, visualize.py, build_instructions.py),
# and Python's own import statement needs a real ".py" extension to
# resolve `import auto_layout`.

import os
import sys
import subprocess
from netlist import load_from_schematic
from auto_layout import layout, TooManyComponentsError


def _version():
    """This project's own current Dewey-decimal version -- CLI-
    specific, so it lives here, not in auto_layout.py's own library
    code. See ppnetlist's own identical helper for the fuller
    reasoning."""
    here = os.path.dirname(os.path.abspath(__file__))
    try:
        with open(os.path.join(here, "VERSION")) as f:
            for line in f:
                line = line.strip()
                if line and not line.startswith("#"):
                    return line
    except OSError:
        pass
    return "unknown"


def main(argv=None):
    """CLI entry point, ADDED 2026-08-19, this project's own FIFTH
    script (after netlist.py, render.py, footprint.py, and
    test_netlist.py) brought up to DevelopmentStandard.org's own real
    "Options and Arguments" bar -- see ppauto_layout.1 (this
    program's own manual page, renamed alongside this file itself).

    MOVED 2026-08-26 from auto_layout.py's own file into this new,
    separate, extensionless CLI entry point -- unchanged otherwise."""
    import argparse

    parser = argparse.ArgumentParser(
        prog="ppauto_layout",
        description="Load a real KiCad schematic, run it through this "
                     "project's own breadboard placement engine "
                     "(classify() + layout()), and print exactly where "
                     "every anchor and passive landed and why -- a plain-"
                     "text diagnostic dump, not a rendered diagram (see "
                     "pprender(1) for that).")
    parser.add_argument("schematic", metavar="SCHEMATIC",
                         help="a real .kicad_sch file (see pprender(1) "
                              "for the same hierarchical-sheet caveat)")
    parser.add_argument("--kicad-cli", metavar="CMD",
                         default=os.environ.get("KICAD_CLI", "kicad-cli"),
                         help="kicad-cli command (default: $KICAD_CLI if "
                              "set, else 'kicad-cli' on PATH)")
    parser.add_argument("--max-components", type=int, metavar="N",
                         help="override this project's own real, default "
                              "component-count limit (breadboard_config."
                              "DEFAULT_MAX_COMPONENTS) -- see that "
                              "constant's own docstring for the real, "
                              "direct rationale (2026-09-15)")
    parser.add_argument("--version", action="version",
                         version=f"%(prog)s {_version()}")
    parser.add_argument("--debug", action="store_true",
                         help="also print every anchor's own real pin-to-"
                              "column mapping (p.anchor_pin_col), not just "
                              "its starting column")
    parser.add_argument("--quiet", action="store_true",
                         help="print only the placement lines themselves "
                              "(one per anchor/passive) and the final "
                              "unplaced summary; suppress the counts "
                              "header and section labels")
    args = parser.parse_args(argv)

    try:
        nl = load_from_schematic(args.schematic, kicad_cli=args.kicad_cli)
    except (OSError, subprocess.CalledProcessError, ValueError) as e:
        print(f"ppauto_layout: {args.schematic}: {e}", file=sys.stderr)
        raise SystemExit(1)

    try:
        p, anchors, passives, rails = layout(nl, max_components=args.max_components)
    except TooManyComponentsError as e:
        print(f"ppauto_layout: {e}", file=sys.stderr)
        raise SystemExit(1)

    if not args.quiet:
        print(f"Anchors ({len(anchors)}): {anchors}")
        print(f"Passives ({len(passives)}): {passives}")
        print(f"Rail nets excluded from placement: {sorted(rails)}")
        print()
        print("Anchor placement:")
    for ref in sorted(anchors):
        print(f"  {ref}: starts at column {p.anchor_col[ref]}")
        if args.debug:
            for (r, pin), c in sorted(p.anchor_pin_col.items()):
                if r == ref:
                    print(f"    pin {pin}: column {c}")
    if not args.quiet:
        print()
        print("Passive placement:")
    for ref in sorted(passives):
        if ref in p.passive_col:
            print(f"  {ref}: column {p.passive_col[ref]} -- {p.reason[ref]}")
        else:
            print(f"  {ref}: UNPLACED")
    if p.unplaced:
        print()
        print(f"{len(p.unplaced)} component(s) the algorithm could not place at all: {p.unplaced}")
    else:
        print()
        print("Every passive was placed.")


if __name__ == "__main__":
    main()
