#!/usr/bin/env python3

"""
Create a collection of UNC-1/4-20 bolts for attaching cameras to tripods.

Copyright 2023
Leon Matthews
https://lost.co.nz/

This work is licensed under a Creative Commons (4.0 International License)
Attribution-ShareAlike.
"""

from pathlib import Path
import subprocess
import sys


HEADS = (
    ('hex', 'none'),
    ('socket', 'hex'),
)

LENGTHS = (
    ('1/4'),
    ('3/8'),
    ('1/2'),
    ('5/8'),
    ('3/4'),
    ('7/8'),
    ('1'),
    ('1 1/4'),
    ('1 3/8'),
    ('1 1/2'),
    ('1 3/4'),
    ('2'),
    ('2 1/2'),
    ('3'),
    ('3 1/2'),
    ('4'),
)

SCAD_SCRIPT = 'camera-tripod-bolt.scad'


def generate_filename(index: int, length: str, head: str) -> str:
    """
    Build decent filename without using colons or forward slashes.
    """
    length = length.replace(' ', '-')
    length = length.replace('/', '[')
    return f'{index:0>2}. {length} inch {head}.stl'


def prepare_folder(folder: str, filename: str) -> None:
    """
    Create folders and remove existing file.
    """
    output_folder = Path.cwd() / folder
    if not output_folder.exists():
        output_folder.mkdir()

    output_path = output_folder / filename
    if output_path.exists():
        output_path.unlink()


def run_openscad(path: str, size: str, head: str, drive: str) -> None:
    """
    Have OpenSCAD create an STL export for our bolt.
    """
    args = [
        'openscad',
        '--quiet',
        '-o', path,
        SCAD_SCRIPT,
        '-D', f'drive="{drive}"',
        '-D', f'head="{head}"',
        '-D', f'size="{size}"',
    ]
    try:
        subprocess.run(args, capture_output=True, check=True, text=True)
    except subprocess.CalledProcessError as e:
        first_line = e.stderr.splitlines()[0]
        raise RuntimeError(f"Error running OpenSCAD: {first_line}")


def main() -> int:
    """
    Create STL files for both head types and in every length.
    """
    for head, drive in HEADS:
        for index, length in enumerate(LENGTHS, 1):
            filename = generate_filename(index, length, head)
            prepare_folder(head, filename)
            size = f"1/4-20,{length}"
            path = f"{head}/{filename}"
            print(
                f'Run OpenSCAD on {head.title()} {length}" -> {path}',
                file=sys.stderr,
            )
            run_openscad(path, size=size, head=head, drive=drive)

    return 0


if __name__ == '__main__':
    sys.exit(main())
