/*
File: p5jsTemplate1Sketch.js
Date: 2026-04-20
Author: klp
Workspace: 
Purpose: Shell template for p5js app development.

*/

// ── Canvas / DOM ──────────────────────────────────────────────────────────────
let myCanvas;
const CANVAS_SCALE_FACTOR = 0.97;
const CANVAS_MAX = 600;
let currentWidth;
let myWidth, myHeight;

const canvasSizeSpan   = document.getElementById("canvasSizeSpan");
const gridScaleSpan    = document.getElementById("gridScaleSpan");
const contentDiv       = document.getElementById("content");
const loadingPara      = document.getElementById("loadingPara");
const resultsPara      = document.getElementById("resultsPara");
const infoDiv          = document.getElementById("infoDiv");
const rightPanel       = document.getElementById("rightPanel");
const canvasActionsDiv = document.getElementById("canvasActions");

window.addEventListener('resize', myResizeCanvas, false);

// ── Background ────────────────────────────────────────────────────────────────
let bgCurrentColor = null;
const DEFAULT_BG_HEX = '#d1d1d4';
const DEFAULT_BG_OPACITY = 100;
let bgHex    = DEFAULT_BG_HEX;
let bgOpacity = DEFAULT_BG_OPACITY;
// fr (frame rate) is declared in myAppSketch.js

// ── Grid ──────────────────────────────────────────────────────────────────────
// Grid bounds (ULx, ULy, LRx, LRy, stepX, stepY) are declared in myAppSketch.js
let aspectRatio = Math.abs((ULx - LRx) / (ULy - LRy));  
let grid;
const DEFAULT_SHOW_GRID = true;
let showGrid = DEFAULT_SHOW_GRID;   // ON by default (G key toggles)
let GRID_COLS, GRID_ROWS;
let missingDrawMyDesignWarned = false;

// ── App state ─────────────────────────────────────────────────────────────────
let running = false;   // true while the sketch animation is active

// ── Control panel DOM refs (assigned in wireControls) ────────────────────────
let bgColorPicker, bgAlphaSlider, bgAlphaVal;
let showGridCheck;
let startPauseBtn, resetBtn, saveImageBtn;

// -- Color Theme --- (declared and initialized in myAppSketch.js)

// ── Setup ─────────────────────────────────────────────────────────────────────
function setup() {
    console.log("...setup...");

    colorMode(HSB, 360, 100, 100, 100);
    initializeSWColors(); //from SWColors.js - sets up named colors and SWColor.fromHex
    if (typeof initThemeColor === 'function') initThemeColor();
    applyThemeColor();

    establishCanvas();

    bgCurrentColor = SWColor.fromHex(DEFAULT_BG_HEX, DEFAULT_BG_OPACITY);
    background(bgCurrentColor.col);

    frameRate(fr);

    grid = new SWGrid({
        UL: new SWPoint(ULx, ULy),
        LR: new SWPoint(LRx, LRy),
        gridColor: new SWColor(0, 0, 60, 100, "gridGray"),
        axisColor: new SWColor(0, 0, 0, 100, "axisBlack"),
        xStep: stepX,
        yStep: stepY
    });
    grid.shouldShowOrigin = false;
    grid.showAxes  = true;
    grid.showGrid  = showGrid;

    GRID_COLS = Math.round((grid.LR.x - grid.UL.x) / grid.xStep);  
    GRID_ROWS = Math.round((grid.UL.y - grid.LR.y) / grid.yStep);

    if (loadingPara)      loadingPara.classList.add('d-none');
    if (infoDiv)          infoDiv.classList.remove('d-none');
    if (resultsPara)      resultsPara.classList.remove('visually-hidden');
    if (rightPanel)       rightPanel.classList.remove('d-none');
    if (canvasActionsDiv) canvasActionsDiv.classList.remove('d-none');

    wireControls();
    updateGridScaleSpan();

    // Start in paused mode until user presses Start.
    noLoop();

}//end setup

// ── Draw ─────────────────────────────────────────────────────────────────────
function draw() {
    console.log("...draw...");
    background(bgCurrentColor.col);

    grid.updateScreenBounds();
    grid.showGrid = showGrid;
    if (showGrid) grid.draw();

    runUserDesign();

}//end draw

function runUserDesign() {
    if (typeof window.drawMyDesign !== 'function') {
        if (!missingDrawMyDesignWarned) {
            console.warn("drawMyDesign(ctx) was not found. Add it in sketches/myAppSketch.js.");
            missingDrawMyDesignWarned = true;
        }
        return;
    }

    const ctx = {
        grid,
        showGrid,
        running,
        themeColor,
        bgCurrentColor,
        bgHex,
        bgOpacity,
        canvasWidth: width,
        canvasHeight: height,
        frameRate: fr
    };
    window.drawMyDesign(ctx);
}//end runUserDesign

// ── Theme helpers ────────────────────────────────────────────────────────────
function applyThemeColor() {
    const mastheadIcon = document.getElementById('mastheadIcon');
    if (!themeColor) return;

    const themeHex = themeColor.getHexStr();

    const heroDiv = document.getElementById('heroDiv');
    if (heroDiv) {
        // Build a gradient from the same theme color used for icon/text.
        const c = themeColor.col;
        const r = Math.round(red(c));
        const g = Math.round(green(c));
        const b = Math.round(blue(c));

        heroDiv.style.backgroundImage =
            `linear-gradient(135deg, rgba(${r}, ${g}, ${b}, 0.26) 0%, rgba(${r}, ${g}, ${b}, 0.16) 100%), ` +
            `url("images/lightGrayStarsPattern.png")`;

        const heroHeadings = heroDiv.querySelectorAll('h1, p');
        heroHeadings.forEach(el => { el.style.color = themeHex; });
    }

    if (!mastheadIcon) return;

    const source = mastheadIcon.dataset.originalSrc || mastheadIcon.src;
    mastheadIcon.dataset.originalSrc = source;

    const srcImg = new Image();
    srcImg.onload = () => {
        const offscreen = document.createElement('canvas');
        offscreen.width = srcImg.naturalWidth || srcImg.width;
        offscreen.height = srcImg.naturalHeight || srcImg.height;

        const ctx = offscreen.getContext('2d');
        if (!ctx) return;

        ctx.clearRect(0, 0, offscreen.width, offscreen.height);
        ctx.drawImage(srcImg, 0, 0);
        ctx.globalCompositeOperation = 'source-atop';
        ctx.fillStyle = themeHex;
        ctx.fillRect(0, 0, offscreen.width, offscreen.height);
        ctx.globalCompositeOperation = 'source-over';

        mastheadIcon.src = offscreen.toDataURL('image/png');
    };
    srcImg.src = source;
}//end applyThemeColor

// ── Refresh helper ───────────────────────────────────────────────────────────
function refreshCanvasImmediate() {
    // In paused mode (noLoop), force a single-frame repaint so UI changes are visible.
    if (typeof isLooping === 'function' && !isLooping()) {
        redraw();
    }
}//end refreshCanvasImmediate

// ── Wire controls ─────────────────────────────────────────────────────────────
function wireControls() {

    // Buttons
    startPauseBtn = document.getElementById('startPauseBtn');
    resetBtn      = document.getElementById('resetBtn');
    saveImageBtn  = document.getElementById('saveImageBtn');

    // Environment
    bgColorPicker = document.getElementById('bgColorPicker');
    bgAlphaSlider = document.getElementById('bgAlphaSlider');
    bgAlphaVal    = document.getElementById('bgAlphaVal');
    showGridCheck = document.getElementById('showGridCheck');

    // ── Background ────────────────────────────────────────────────────────
    function syncBg() {
        const alpha = bgAlphaSlider ? parseFloat(bgAlphaSlider.value) : DEFAULT_BG_OPACITY;
        if (bgAlphaVal) bgAlphaVal.textContent = Math.round(alpha);
        const hex = bgColorPicker ? bgColorPicker.value : DEFAULT_BG_HEX;
        bgHex          = hex;
        bgOpacity      = alpha;
        bgCurrentColor = SWColor.fromHex(hex, alpha);
        refreshCanvasImmediate();
    }
    [bgColorPicker, bgAlphaSlider].forEach(el => {
        if (el) { el.addEventListener('input', syncBg); el.addEventListener('change', syncBg); }
    });

    // ── Grid toggle ───────────────────────────────────────────────────────
    if (showGridCheck) {
        showGridCheck.checked = showGrid;
        showGridCheck.addEventListener('change', () => {
            showGrid = showGridCheck.checked;
            refreshCanvasImmediate();
        });
    }

    // ── Start / Pause toggle ───────────────────────────────────────────────
    function syncStartPauseBtn() {
        if (!startPauseBtn) return;
        if (running) {
            startPauseBtn.textContent = '⏸ Pause';
            startPauseBtn.classList.replace('btn-success', 'btn-warning');
            loop();
        } else {
            startPauseBtn.textContent = '▶ Start';
            startPauseBtn.classList.replace('btn-warning', 'btn-success');
            noLoop();
        }
        if (resetBtn) resetBtn.disabled = false;  // available once ever started
    }

    if (startPauseBtn) {
        startPauseBtn.addEventListener('click', () => {
            running = !running;
            syncStartPauseBtn();
            console.log(running ? "Start pressed." : "Pause pressed.");
            // TODO: replace with real start / pause logic
        });
    }

    // ── Reset ─────────────────────────────────────────────────────────────
    if (resetBtn) {
        resetBtn.addEventListener('click', () => {
            running = false;

            // Restore control panel defaults.
            showGrid = DEFAULT_SHOW_GRID;
            if (showGridCheck) showGridCheck.checked = DEFAULT_SHOW_GRID;

            bgHex = DEFAULT_BG_HEX;
            bgOpacity = DEFAULT_BG_OPACITY;
            if (bgColorPicker) bgColorPicker.value = DEFAULT_BG_HEX;
            if (bgAlphaSlider) bgAlphaSlider.value = String(DEFAULT_BG_OPACITY);
            if (bgAlphaVal) bgAlphaVal.textContent = String(DEFAULT_BG_OPACITY);
            bgCurrentColor = SWColor.fromHex(DEFAULT_BG_HEX, DEFAULT_BG_OPACITY);

            syncStartPauseBtn();
            if (resetBtn) resetBtn.disabled = true;  // back to pristine idle state
            redraw();
            console.log("Reset pressed.");
            // TODO: replace with real reset logic
        });
    }

    if (saveImageBtn) saveImageBtn.addEventListener('click', saveCanvasImage);

    syncBg();

}//end wireControls

// ── Grid scale span ───────────────────────────────────────────────────────────
function updateGridScaleSpan() {
    if (grid && gridScaleSpan) {
        gridScaleSpan.textContent =
            `x:[${grid.UL.x}, ${grid.LR.x}] step:${grid.xStep}  ` +
            `y:[${grid.LR.y}, ${grid.UL.y}] step:${grid.yStep}`;
    }
}//end updateGridScaleSpan

// ── keyPressed ────────────────────────────────────────────────────────────────
function keyPressed() {
    if (key === 'g' || key === 'G') {
        showGrid = !showGrid;
        if (showGridCheck) showGridCheck.checked = showGrid;
        refreshCanvasImmediate();
    }
}//end keyPressed

// ── Canvas setup / resize ─────────────────────────────────────────────────────
function establishCanvas() {
    console.log("...establishCanvas...");
    currentWidth = window.innerWidth;
    myWidth  = CANVAS_SCALE_FACTOR * contentDiv.clientWidth;
    if (myWidth > CANVAS_MAX) myWidth = CANVAS_MAX;
    myHeight = myWidth / aspectRatio;
    if (currentWidth < 300) { myWidth = 200; myHeight = myWidth / aspectRatio; }

    myCanvas = createCanvas(myWidth, myHeight);
    myCanvas.parent('myCanvas');

    if (canvasSizeSpan) {
        canvasSizeSpan.textContent = `(${Math.round(myWidth)}, ${Math.round(myHeight)})`;
    }
}//end establishCanvas

function myResizeCanvas() {
    if (myCanvas == null) return;
    currentWidth = window.innerWidth;
    myWidth  = CANVAS_SCALE_FACTOR * contentDiv.clientWidth;
    if (myWidth > CANVAS_MAX) myWidth = CANVAS_MAX;
    myHeight = myWidth / aspectRatio;
    myCanvas = createCanvas(myWidth, myHeight);
    myCanvas.parent('myCanvas');
    if (canvasSizeSpan) {
        canvasSizeSpan.textContent = `(${Math.round(myWidth)}, ${Math.round(myHeight)})`;
    }
    redraw();
}//end myResizeCanvas

// ── Save canvas ───────────────────────────────────────────────────────────────
//customize the appImgPrefix variable at the top of 'myAppSketch.js' to change the prefix for saved canvas image filenames (default is "template1")
function saveCanvasImage() {
    const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
    const prefix = (typeof appImgPrefix !== 'undefined' && appImgPrefix) ? appImgPrefix : 'template1';
    saveCanvas(myCanvas, `${prefix}_${ts}`, 'png');
    console.log("Canvas saved.");
}//end saveCanvasImage

// ── Expose to HTML ────────────────────────────────────────────────────────────
window.saveCanvasImage = saveCanvasImage;
