<?php
namespace Veno\QrCdr\Lib;

/**
 * QR Code Frame Filler (Private Fork for Veno QrCdr)
 *
 * Coordinates the placement of data bits into the QR matrix,
 * skipping function patterns (finder, timing, alignment) using
 * the standard zig-zag pattern.
 *
 * @package   QrCdr
 * @version   1.1.4-patched
 */

if ( ! defined( 'ABSPATH' ) && ! defined( 'QRCDR_OPEN_ACCESS' ) ) {
	exit;
}

class QrcdrFrameFiller {

	/**
	 * Frame width.
	 * @var int
	 */
	public $width;

	/**
	 * Frame data (reference).
	 * @var array
	 */
	public $frame;

	/**
	 * Current X coordinate.
	 * @var int
	 */
	public $x;

	/**
	 * Current Y coordinate.
	 * @var int
	 */
	public $y;

	/**
	 * Vertical direction (-1 up, 1 down).
	 * @var int
	 */
	public $dir;

	/**
	 * Current bit index in the zig-zag.
	 * @var int
	 */
	public $bit;

	/**
	 * Constructor.
	 *
	 * @param int   $width Frame width.
	 * @param array $frame Frame data (passed by reference).
	 */
	public function __construct( $width, &$frame ) {
		$this->width = $width;
		$this->frame = &$frame;
		$this->x     = $width - 1;
		$this->y     = $width - 1;
		$this->dir   = -1;
		$this->bit   = -1;
	}

	/**
	 * Set frame bit at specific coordinates.
	 *
	 * @param array $location Coordinates ['x', 'y'].
	 * @param int   $value    Value to set.
	 */
	public function setFrameAt( $location, $value ) {
		$this->frame[ $location['y'] ][ $location['x'] ] = chr( $value );
	}

	/**
	 * Get frame bit at specific coordinates.
	 *
	 * @param array $location Coordinates ['x', 'y'].
	 * @return int Value.
	 */
	public function getFrameAt( $location ) {
		return ord( $this->frame[ $location['y'] ][ $location['x'] ] );
	}

	/**
	 * Get next available coordinate for data placement.
	 *
	 * @return array|null Coordinates ['x', 'y'] or null if finished.
	 */
	public function next() {
		do {
			// Start: bottom-right corner
			if ( -1 === $this->bit ) {
				$this->bit = 0;
				return array( 'x' => $this->x, 'y' => $this->y );
			}

			$current_x = $this->x;
			$current_y = $this->y;
			$width     = $this->width;

			// Move in zig-zag
			if ( 0 === $this->bit ) {
				$current_x--; // Left
				$this->bit++;
			} else {
				$current_x++; // Right
				$current_y += $this->dir; // Up or Down
				$this->bit--;
			}

			// Boundary checks and direction flip
			if ( 0 > $this->dir ) {
				// Moving Up
				if ( 0 > $current_y ) {
					$current_y = 0;
					$current_x -= 2;
					$this->dir = 1; // Flip to Down
					
					// Skip vertical timing pattern column
					if ( 6 === $current_x ) {
						$current_x--;
						$current_y = 9;
					}
				}
			} else {
				// Moving Down
				if ( $width === $current_y ) {
					$current_y = $width - 1;
					$current_x -= 2;
					$this->dir = -1; // Flip to Up
					
					// Skip vertical timing pattern column
					if ( 6 === $current_x ) {
						$current_x--;
						$current_y -= 8;
					}
				}
			}

			// Out of bounds check
			if ( 0 > $current_x || 0 > $current_y ) {
				return null;
			}

			$this->x = $current_x;
			$this->y = $current_y;

			// Skip occupied modules (MSB set)
		} while ( ord( $this->frame[ $this->y ][ $this->x ] ) & 0x80 );

		return array( 'x' => $this->x, 'y' => $this->y );
	}
}
