// File: swGrid.js
// Author: klp
// Purpose: SWGrid class for scalable, resizable grid system in p5.js
// Dependencies: p5.js, SWPoint, SWColor

console.log("[swGrid.js] SWGrid class loaded.");

class SWGrid {
    /**
     * @param {Object} config - Configuration object
     * @param {SWPoint} config.UL - Upper left user coordinate (e.g., new SWPoint(-10, 10))
     * @param {SWPoint} config.LR - Lower right user coordinate (e.g., new SWPoint(10, -10))
     * @param {boolean} [config.showGrid=true] - Show grid lines
     * @param {boolean} [config.showAxes=true] - Show axes
     * @param {number} [config.xStep=1] - Grid step for x axis
     * @param {number} [config.yStep=1] - Grid step for y axis
     * @param {SWColor} [config.gridColor] - Color for grid lines
     * @param {SWColor} [config.axisColor] - Color for axes
     */
    constructor({UL, LR, showGrid=true, showAxes=true, xStep=1, yStep=1, gridColor, axisColor}) {
        this.UL = UL;
        this.LR = LR;
        this.showGrid = showGrid;
        this.showAxes = showAxes;
        this.xStep = xStep;
        this.yStep = yStep;
        this.gridColor = gridColor || new SWColor(0, 0, 85, 100, "gridGray");
        this.axisColor = axisColor || new SWColor(0, 0, 0, 100, "axisBlack");
        this.updateScreenBounds();
        this.shouldShowOrigin = false;
    }//end constructor

    // Call this in windowResized or after canvas resize
    updateScreenBounds() {
        this.screenW = width;
        this.screenH = height;
        this.xScale = this.screenW / (this.LR.x - this.UL.x);
        this.yScale = this.screenH / (this.UL.y - this.LR.y);
    }//end updateScreenBounds

    // Convert user (x, y) to screen (px, py)
    userToScreen(x, y) {
        const px = (x - this.UL.x) * this.xScale;
        const py = (this.UL.y - y) * this.yScale;
        return {x: px, y: py};
    }//end userToScreen

    // Convert screen (px, py) to user (x, y)
    screenToUser(px, py) {
        const x = px / this.xScale + this.UL.x;
        const y = this.UL.y - py / this.yScale;
        return {x, y};
    }//end screenToUser

    // Draw the grid, axes, and origin
    draw() {
        // Draw grid lines
        if (this.showGrid) {
            stroke(this.gridColor.col);
            strokeWeight(1);
            // Vertical grid lines
            for (let x = Math.ceil(this.UL.x/this.xStep)*this.xStep; x <= this.LR.x; x += this.xStep) {
                const {x: px1, y: py1} = this.userToScreen(x, this.UL.y);
                const {x: px2, y: py2} = this.userToScreen(x, this.LR.y);
                line(px1, py1, px2, py2);
            }
            // Horizontal grid lines
            for (let y = Math.floor(this.LR.y/this.yStep)*this.yStep; y <= this.UL.y; y += this.yStep) {
                const {x: px1, y: py1} = this.userToScreen(this.UL.x, y);
                const {x: px2, y: py2} = this.userToScreen(this.LR.x, y);
                line(px1, py1, px2, py2);
            }
        }
        // Draw axes
        if (this.showAxes) {
            stroke(this.axisColor.col);
            strokeWeight(2);
            // y-axis (x=0)
            if (this.UL.x < 0 && this.LR.x > 0) {
                const {x: px1, y: py1} = this.userToScreen(0, this.UL.y);
                const {x: px2, y: py2} = this.userToScreen(0, this.LR.y);
                line(px1, py1, px2, py2);
            }
            // x-axis (y=0)
            if (this.LR.y < 0 && this.UL.y > 0) {
                const {x: px1, y: py1} = this.userToScreen(this.UL.x, 0);
                const {x: px2, y: py2} = this.userToScreen(this.LR.x, 0);
                line(px1, py1, px2, py2);
            }

            if(this.shouldShowOrigin) {
                this.drawOrigin();
            }
            
        }
    }//end draw

    drawOrigin() {
        // Draw origin if in bounds
        if (this.UL.x < 0 && this.LR.x > 0 && this.LR.y < 0 && this.UL.y > 0) {
            const {x: px, y: py} = this.userToScreen(0, 0);
            fill(this.axisColor.col);
            noStroke();
            ellipse(px, py, 6, 6);
        }
    }//end drawOrigin

    // Toggle grid visibility
    toggleGrid() {
        this.showGrid = !this.showGrid;
    }//end toggleGrid

    // Toggle axes visibility
    toggleAxes() {
        this.showAxes = !this.showAxes;
    }//end toggleAxes

    // Set new user bounds
    setBounds(UL, LR) {
        this.UL = UL;
        this.LR = LR;
        this.updateScreenBounds();
    }//end setBounds
}//end SWGrid class

// Usage example (in your sketch):
// let grid;
// function setup() {
//   createCanvas(400, 400);
//   grid = new SWGrid({UL: new SWPoint(-10, 10), LR: new SWPoint(10, -10)});
// }
// function draw() {
//   background(240);
//   grid.updateScreenBounds();
//   grid.draw();
// }
