<?php
@session_start();
class html
{


    function __construct()
    {
        ?>

        <head>
            <link rel="stylesheet" href="https://fuelsupplier.elegantwork.co.za/styles/styles.css?V=<?php echo time(); ?>">
            <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
        </head>

        <?php
    }
}

class select
{
    private $attributes = [];
    private $option = ["" => ""];

    private $value;

    function addAttribute($name, $value)
    {
        $this->attributes[$name] = $value;
    }
    function name($name)
    {
        $this->addAttribute('name', $name);
    }

    function id($id)
    {
        $this->addAttribute('id', $id);
    }

    function add_option($value, $label)
    {
        $this->option[$value] = $label;
    }

    function onchange($onchange)
    {
        $this->addAttribute('onchange', $onchange);
    }
    function onclick($onclick)
    {
        $this->addAttribute('onclick', $onclick);
    }
    function oninput($oninput)
    {
        $this->addAttribute('oninput', $oninput);
    }
    function required()
    {
        $this->addAttribute('required', 'required');
    }
    function disabled()
    {
        $this->addAttribute('disabled', 'disabled');

    }
    function readonly()
    {
        $this->addAttribute('readonly', 'readonly');
    }

    function autofocus()
    {
        $this->addAttribute('autofocus', 'autofocus');
    }

    function style($style)
    {
        $this->addAttribute('style', $style);
    }

    function class($class = "inputs")
    {
        $this->addAttribute('class', $class);
    }

    function fill_from_db($table_name, $column_for_value, $column_for_label, $where_clause = ' 1 ')
    {
        $db = new db();
        $query = "SELECT $column_for_value, $column_for_label FROM $table_name WHERE $where_clause";
        $result = $db->query($table_name, $query);
        while ($row = $result->fetch_assoc()) {
            $this->option[$row[$column_for_value]] = $row[$column_for_label];
        }
    }

    function value_from_db($table_name, $value_column, $where_clause)
    {
        $db = new db();
        $res = $db->query($table_name, "SELECT $value_column FROM $table_name WHERE $where_clause");
        $row = $res->fetch_assoc();
        $this->value = $row[$value_column];

    }
    function add()
    {
        if (!array_key_exists('class', $this->attributes)) {
            $this->class();
        }
        $select = "<select";
        foreach ($this->attributes as $key => $value) {
            $select .= " $key='$value'";
        }
        $select .= ">";

        foreach ($this->option as $value => $label) {
            $select .= "<option value='$value'>$label</option>";
        }

        $select .= "</select>";

        $select .= "<script>document.getElementById('" . $this->attributes['id'] . "').value = '" . $this->value . "';</script>";
        echo $select;
    }

}

class label
{
    private $attributes = [];

    private $value;

    function addAttribute($name, $value)
    {
        $this->attributes[$name] = $value;
    }
    function for($for)
    {
        $this->addAttribute('for', $for);
    }
    function value($text)
    {
        $this->value = $text;
    }
    function class($class = "labels")
    {
        $this->addAttribute('class', $class);
    }
    function add()
    {

        if (!array_key_exists('class', $this->attributes)) {
            $this->class();
        }
        $label = "<label";
        foreach ($this->attributes as $key => $value) {
            $label .= " $key='$value'";
        }
        $label .= ">" . $this->value;
        $label .= "</label>";
        echo $label;
    }

}
class barcodeReader
{
    public $extra_js_function_to_call;

    function add_js_function_to_call($function_name)
    {
        $this->extra_js_function_to_call = $function_name;
    }

    function add_button($barcodeInputId, $index = 0)
    {
        $barcodeInputId = htmlspecialchars($barcodeInputId, ENT_QUOTES, 'UTF-8');
        $uniqueId = 'barcode-scan-area-' . $index;
        $startButtonId = 'barcode-start-button-' . $index;
        $videoAreaId = 'barcode-video-area-' . $index;
        $videoStreamId = 'barcode-video-stream-' . $index;
        $videoCanvasId = 'barcode-video-canvas-' . $index;
        ?>

        <div id="<?php echo $uniqueId; ?>">
            <button id="<?php echo $startButtonId; ?>" class="submit_btn"
                onclick="startBarcodeScanner('<?php echo $barcodeInputId; ?>',<?php echo $index; ?>)" style='font-size: 2em;
    margin: 2vw;
    width: 80vw;
    height: 20vh;'>SCAN
                BARCODE</button>
            <div id="<?php echo $videoAreaId; ?>"
                style="position: relative; overflow: hidden; display: none; width: 100%; max-width: 500px; height: 200px; margin: auto; border: 2px solid #333; border-radius: 8px;">
                <video id="<?php echo $videoStreamId; ?>" playsinline muted autoplay
                    style="width: 100%; height: 100%; object-fit: cover; background: #000;"></video>
                <canvas id="<?php echo $videoCanvasId; ?>"
                    style="display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas>
            </div>
        </div>

        <?php
    }

    function __destruct()
    {
        ?>

        <script src="https://cdnjs.cloudflare.com/ajax/libs/quagga/0.12.1/quagga.min.js"></script>
        <script>
            function startBarcodeScanner(barcodeInputId, index) {
                event.preventDefault();

                const videoArea = document.getElementById('barcode-video-area-' + index);
                const videoStream = document.getElementById('barcode-video-stream-' + index);
                const videoCanvas = document.getElementById('barcode-video-canvas-' + index);
                const startButton = document.getElementById('barcode-start-button-' + index);
                const targetInputId = barcodeInputId;

                videoArea.style.display = 'block';

                function stopCamera() {
                    Quagga.stop();
                    videoStream.pause();
                    if (videoStream.srcObject) {
                        videoStream.srcObject.getVideoTracks().forEach(track => {
                            track.stop();
                            track.enabled = false;
                        });
                    }
                    videoArea.style.display = 'none';
                    if (typeof executeOnce === 'undefined') {
                        <?php
                        if (strlen($this->extra_js_function_to_call) > 1) {
                            echo $this->extra_js_function_to_call . ";";
                        }
                        ?>
                        var executeOnce = true;
                    }
                }

                navigator.mediaDevices.getUserMedia({
                    audio: false,
                    video: {
                        facingMode: { ideal: 'environment' },
                        width: { ideal: 640 },
                        height: { ideal: 480 },
                        zoom: 3 // try 3x zoom
                    }
                }).then(function (stream) {
                    videoStream.srcObject = stream;
                    videoStream.setAttribute('playsinline', true);
                    videoStream.muted = true;
                    videoStream.autoplay = true;
                    videoStream.play();

                    const track = stream.getVideoTracks()[0];
                    const capabilities = track.getCapabilities();

                    // Apply 3x zoom if supported
                    if (capabilities.zoom) {
                        const maxZoom = capabilities.zoom.max || 3;
                        const zoomToApply = Math.min(3, maxZoom);
                        track.applyConstraints({ advanced: [{ zoom: zoomToApply }] }).catch(e => {
                            console.warn("Zoom apply failed:", e);
                        });
                    }

                    // Try autofocus continuous mode if supported
                    if (capabilities.focusMode && capabilities.focusMode.includes('continuous')) {
                        track.applyConstraints({ advanced: [{ focusMode: "continuous" }] }).catch(() => { });
                    }

                    Quagga.init({
                        inputStream: {
                            name: "Live",
                            type: "LiveStream",
                            target: videoStream,
                            constraints: {
                                facingMode: "environment",
                                width: { min: 300 },
                                height: { min: 300 },
                                aspectRatio: { min: 1 }
                            },
                            area: {
                                top: "25%",    // center horizontal band
                                right: "10%",
                                left: "10%",
                                bottom: "25%"
                            }
                        },
                        decoder: {
                            readers: [
                                "code_128_reader",
                                "ean_reader",
                                "ean_8_reader",
                                "upc_reader"
                            ],
                            multiple: false
                        },
                        locator: {
                            patchSize: "large",
                            halfSample: false
                        },
                        locate: true,
                        numOfWorkers: 4,
                        frequency: 20
                    }, function (err) {
                        if (err) {
                            console.error("Error initializing Quagga: ", err);
                            return;
                        }
                        Quagga.start();
                    });

                    let lastBarcode = null;
                    let matchCount = 0;

                    Quagga.onDetected(function (result) {
                        const codes = result.codeResult.decodedCodes;
                        const errors = codes.filter(c => typeof c.error !== 'undefined').map(c => c.error);
                        const avgError = errors.length ? errors.reduce((a, b) => a + b, 0) / errors.length : 0;

                        if (avgError < 0.25) { // Only accept low-error scans
                            const barcode = result.codeResult.code;

                            if (barcode === lastBarcode) {
                                matchCount++;
                            } else {
                                lastBarcode = barcode;
                                matchCount = 1;
                            }

                            if (matchCount >= 2) { // 2 matches is enough now
                                document.getElementById(targetInputId).value = barcode;
                                stopCamera();
                            }
                        }
                    });

                    Quagga.onProcessed(function (result) {
                        if (result && result.codeResult) {
                            console.log("Processing result: ", result.codeResult.code);
                        }
                    });

                }).catch(function (error) {
                    console.error("Error accessing camera: ", error);
                    alert("Unable to access camera. Please check permissions.");
                    videoArea.style.display = 'none';
                });
            }
        </script>

        <?php
    }
}
class input
{
    private $attributes = [];

    private $value;

    /**
     * Adds an attribute to the input element.
     * This function adds a single attribute to the input element. The attribute is
     * specified by the name and value parameters.
     * @param string $name The name of the attribute.
     * @param string $value The value of the attribute.
     */
    function addAttribute($name, $value)
    {
        $this->attributes[$name] = $value;
    }
    /**
     * Sets the name attribute for the input element.
     *
     * This function assigns a name attribute to the input element, which is used
     * to identify the input when the form is submitted. The name is specified by
     * the $name parameter.
     *
     * @param string $name The name of the input element.
     */

    function name($name)
    {
        $this->addAttribute('name', $name);
    }

    function id($id)
    {
        $this->addAttribute('id', $id);
    }

    function onchange($onchange)
    {
        $this->addAttribute('onchange', $onchange);
    }
    function onkeyup($onchange)
    {
        $this->addAttribute('onkeyup', $onchange);
    }
    function onclick($onclick)
    {
        $this->addAttribute('onclick', $onclick);
    }
    function oninput($oninput)
    {
        $this->addAttribute('oninput', $oninput);
    }
    function required()
    {
        $this->addAttribute('required', 'required');
    }
    function disabled()
    {
        $this->addAttribute('disabled', 'disabled');

    }
    function readonly()
    {
        $this->addAttribute('readonly', 'readonly');
    }
    function autofocus()
    {
        $this->addAttribute('autofocus', 'autofocus');
    }
    function min($min)
    {
        $this->addAttribute('min', $min);
    }
    function max($max)
    {
        $this->addAttribute('max', $max);
    }
    function step($step)
    {
        $this->addAttribute('step', $step);
    }
    /**
     * Sets the pattern attribute for the input element.
     *
     * This function assigns a pattern attribute to the input element, which is
     * used to validate the input when the form is submitted. The pattern is
     * specified by the $pattern parameter.
     *
     * @param string $pattern The pattern to be used for validation.
     */
    function pattern($pattern)
    {
        $this->addAttribute('pattern', $pattern);
    }
    function placeholder($placeholder)
    {
        $this->addAttribute('placeholder', $placeholder);
    }

    function value($value)
    {
        $this->value = $value;


    }

    function style($style)
    {
        $this->addAttribute('style', $style);
    }

    function class($class = "inputs")
    {
        $this->addAttribute('class', $class);
    }

    function value_from_db($table_name, $value_column, $where_clause)
    {
        $db = new db();
        $res = $db->query($table_name, "SELECT $value_column FROM $table_name WHERE $where_clause");
        $row = $res->fetch_assoc();

        if (isset($this->attributes['id']) && $this->attributes['id'] == 'password') {
            $auth = new authentication();
            $this->value = $auth->decrypt_password($row[$value_column]);
        } else {
            $this->value = $row[$value_column];
        }

    }
    function type($type = "text")
    {
        $knownTypes = ['text', 'password', 'email', 'number', 'url', 'tel', 'search', 'color', 'date', 'datetime-local', 'month', 'week', 'time', 'checkbox', 'radio', 'file', 'hidden', 'image', 'button', 'reset', 'submit', 'range'];
        if (in_array($type, $knownTypes)) {
            $this->addAttribute('type', $type);
        } else {
            $this->value = "[HTML ERROR] - Unknown type: " . $type . " expected one of: " . implode(", ", $knownTypes);
            ;
        }
    }
    function add()
    {
        if (!array_key_exists('class', $this->attributes)) {
            $this->class();
        }

        $input = "<input";
        foreach ($this->attributes as $key => $value) {
            $input .= " $key='$value'";
        }
        $input .= " value=\"{$this->value}\"/>";
        echo $input;
    }

}


class button
{
    private $attributes = [];

    function addAttribute($name, $value)
    {
        $this->attributes[$name] = $value;
    }
    function name($name)
    {
        $this->addAttribute('name', $name);
    }

    function id($id = 'submit')
    {
        $this->addAttribute('id', $id);
    }

    function onchange($onchange)
    {
        $this->addAttribute('onchange', $onchange);
    }
    function onclick($onclick)
    {
        $this->addAttribute('onclick', $onclick);
    }
    function oninput($oninput)
    {
        $this->addAttribute('oninput', $oninput);
    }
    function required()
    {
        $this->addAttribute('required', 'required');
    }
    function disabled()
    {
        $this->addAttribute('disabled', 'disabled');

    }

    function readonly()
    {
        $this->addAttribute('readonly', 'readonly');
    }

    function autofocus()
    {
        $this->addAttribute('autofocus', 'autofocus');
    }

    function style($style)
    {
        $this->addAttribute('style', "$style");
    }

    function value($value)
    {
        $this->value = $value;
    }

    function class($class = "submit_btn")
    {
        $this->addAttribute('class', $class);
    }

    function add()
    {
        if (!array_key_exists('id', $this->attributes)) {
            $this->id();
        }
        if (!array_key_exists('class', $this->attributes)) {
            $this->class();
        }
        $button = "<button";
        foreach ($this->attributes as $key => $value) {
            $button .= " $key='$value' ";
        }
        $button .= ">" . $this->value . "</button>";
        echo $button;
    }
}
