#!/usr/bin/env python3

# The Picamera2 Library supports multiple cameras.
# This wrapper forwards the given commands to all cameras.

# Picamera2 Manual:
# https://datasheets.raspberrypi.com/camera/picamera2-manual.pdf

__author__ = "Gernot Walzl"
__date__ = "2025-12-21"

import argparse
import time
import libcamera
from picamera2 import Picamera2
from picamera2.encoders import H264Encoder, Quality


class MultiPicam2:

    def __init__(self):
        """Picamera2 Manual - 8.7. Multiple Cameras"""
        self._picams = []
        for cam_info in Picamera2.global_camera_info():
            self._picams.append(Picamera2(cam_info['Num']))

    def configure_still(self):
        for idx, picam2 in enumerate(self._picams):
            flip = idx % 2
            capture_config = picam2.create_still_configuration(
                transform=libcamera.Transform(hflip=flip, vflip=flip)
            )
            picam2.configure(capture_config)

    def start(self):
        for picam2 in self._picams:
            picam2.start()

    def stop(self):
        for picam2 in self._picams:
            picam2.stop()

    def autofocus(self):
        """Picamera2 Manual - 5.3.4. Triggering an Autofocus Cycle"""
        success = True
        af_jobs = []
        for picam2 in self._picams:
            af_jobs.append(picam2.autofocus_cycle(wait=False))
        for idx, picam2 in enumerate(self._picams):
            success &= picam2.wait(af_jobs[idx])
        return success

    def capture_files(self, filename="img_{:03d}_{:01d}.jpg",
                      num_files=10, delay=0.5):
        for idx_file in range(num_files):
            time_started = time.time()
            for idx_cam, picam2 in enumerate(self._picams):
                picam2.capture_file(filename.format(idx_file, idx_cam))
            sleep_secs = delay - (time.time() - time_started)
            if sleep_secs > 0.0:
                time.sleep(sleep_secs)

    def start_and_capture_files(self, filename="img_{:03d}_{:01d}.jpg",
                                initial_delay=1.0,
                                num_files=10, delay=0.5):
        """Picamera2 Manual - 2.4. Picamera2′s high-level API"""
        self.configure_still()
        self.start()
        time.sleep(initial_delay)
        self.autofocus()
        self.capture_files(filename, num_files, delay)
        self.stop()

    def configure_video(self):
        for idx, picam2 in enumerate(self._picams):
            flip = idx % 2
            capture_config = picam2.create_video_configuration(
                transform=libcamera.Transform(hflip=flip, vflip=flip)
            )
            picam2.configure(capture_config)

    def start_recording(self, filename="vid_{:01d}.h264"):
        for idx_cam, picam2 in enumerate(self._picams):
            encoder = H264Encoder()
            picam2.start_recording(
                encoder, filename.format(idx_cam), quality=Quality.HIGH)

    def stop_recording(self):
        for picam2 in self._picams:
            picam2.stop_recording()

    def start_and_record_videos(self, filename="vid_{:01d}.h264",
                                initial_delay=1.0, duration=10.0):
        """Picamera2 Manual - 2.4. Picamera2′s high-level API"""
        self.configure_video()
        time.sleep(initial_delay)
        self.start_recording(filename)
        time.sleep(duration)
        self.stop_recording()


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '-o', '--output', type=str, default="img_{:03d}_{:01d}.jpg")
    parser.add_argument(
        '--initial-delay', type=float, default=1.0)
    parser.add_argument(
        '--num-files', type=int, default=10)
    parser.add_argument(
        '--delay', type=float, default=0.5)

    args = parser.parse_args()
    multipicam2 = MultiPicam2()
    multipicam2.start_and_capture_files(
        args.output, args.initial_delay, args.num_files, args.delay)