let myWidth = 800, myHeight = 800, offset = 5;
let r, n = 10;

let t = [];
let tl = null
let br = null;

let showCount = false;
let drawRectMode = 0;

let sOutput, wOutput, tlOutput, tOutput, lOutput;


function setup()
{
    createCanvas(myWidth + 2*offset, myHeight + 2*offset);
    r = myWidth / n;
    for (y = 0; y < n; y ++)
    {
        for (x = 0; x < n; x ++)
        {
            t.push(new cTile(x*r + offset, y*r + offset, r));
        }
    }
    sOutput = document.getElementById('subsetOutput');
    wOutput = document.getElementById('wholeOutput');
    tlOutput = document.getElementById('tlOutput');
    tOutput = document.getElementById('tOutput');
    lOutput = document.getElementById('lOutput');

}

function draw()
{
    background(46, 52, 64);
    t.forEach(e => e.show());

    stroke(156,212,228);
    noFill();
    strokeWeight(5);
    if (tl)
    {
        if (!br)
        {
            rect(tl.x, tl.y, tl.w);
        } else {
            rect(tl.x, tl.y, br.x - tl.x + r, br.y - tl.y + r);
            drawRect(drawRectMode);
        }
    }
}

function defineCount(br)
{
    let cols = Math.floor(br.x/ r) + 1;
    let rows = Math.floor(br.y/ r) + 1;
    let c = 0;
    // let index = cols + n * rows;

    for (y = 0; y < rows; y++) {
        for (x = 0; x < cols; x++){
            var i = x + n * y;
            if (t[i].s){
                c++;
            }
        }
    }
    return c;
}

function countSquares(tl, br)
{
    let topLeft, left, top, whole;
    let tlx, tly, brx, bry;

    tlx = Math.floor(tl.x / r);
    tly = Math.floor(tl.y / r);
    brx = Math.floor(br.x / r);
    bry = Math.floor(br.y / r);

    topLeft = t[(tlx-1) + n * (tly-1)].count;
    left    = t[(tlx-1) + n * bry    ].count;
    top     = t[brx     + n * (tly-1)].count;
    whole   = t[brx     + n * bry    ].count;

    var s = whole + topLeft - top - left;
    if (s < 0)
        s = 0;

    return s;
}

function drawRect(n)
{
    strokeWeight(5);
    noFill();

    switch(n)
    {
        case 1:
            //whole
            stroke(180,142,173);
            fill('rgba(180, 142, 173, 0.05)');
            rect(offset, offset, br.x - offset + br.w, br.y - offset + br.w);
            break;
        case 2:
            //topleft
            stroke(208,135,112);
            fill('rgba(208,135,112, 0.05)');
            rect(offset, offset, tl.x - offset, tl.y - offset);
            break;
        case 3:
            //left
            stroke(163,190,140);
            fill('rgba(163,190,140, 0.05)');
            rect(offset, offset, tl.x - offset, br.y - offset + br.w);
            break;
        case 4:
            //top
            stroke(235,203,139);
            fill('rgba(235,203,139, 0.05)');
            rect(offset, offset, br.x - offset + br.w, tl.y - offset);
            break;
        default:
            break;
    }
    
    strokeWeight(1);
}

function showCountToggle(){
    showCount = !showCount;
}

function toggleRectMode(){
    if (tl && br)
    {
        var tlx = Math.floor(tl.x / r);
        var tly = Math.floor(tl.y / r);
        var brx = Math.floor(br.x / r);
        var bry = Math.floor(br.y / r);
    
        var topLeft = t[(tlx-1) + n * (tly-1)].count;
        var left    = t[(tlx-1) + n * bry    ].count;
        var top     = t[brx     + n * (tly-1)].count;
        var whole   = t[brx     + n * bry    ].count;
    
        if (drawRectMode == 0){
            wOutput.innerHTML = whole.toString(10);
            wOutput.style.fontWeight = "bold";
            drawRectMode ++;
        } else if (drawRectMode == 1){
            tlOutput.innerHTML = topLeft.toString(10);
            tlOutput.style.fontWeight = "bold";
            wOutput.style.fontWeight = "normal";
            drawRectMode ++;
        } else if (drawRectMode == 2){
            lOutput.innerHTML = left.toString(10);
            lOutput.style.fontWeight = "bold";
            tlOutput.style.fontWeight = "normal";
            drawRectMode ++;
        } else if (drawRectMode == 3) {
            tOutput.innerHTML = top.toString(10);
            tOutput.style.fontWeight = "bold";
            lOutput.style.fontWeight = "normal";
            drawRectMode ++;
        } else if (drawRectMode == 4) {
            tOutput.style.fontWeight = "normal";
            drawRectMode = 0;
        }
    }
}

function updateSum()
{
    var tlx = Math.floor(tl.x / r);
    var tly = Math.floor(tl.y / r);
    var brx = Math.floor(br.x / r);
    var bry = Math.floor(br.y / r);

    var topLeft = t[(tlx-1) + n * (tly-1)].count;
    var left    = t[(tlx-1) + n * bry    ].count;
    var top     = t[brx     + n * (tly-1)].count;
    var whole   = t[brx     + n * bry    ].count;

    wOutput.innerHTML = whole.toString(10);
    tlOutput.innerHTML = topLeft.toString(10);
    lOutput.innerHTML = left.toString(10);
    tOutput.innerHTML = top.toString(10);
    sOutput.innerHTML = countSquares(tl,br).toString(10);
}

function mouseClicked(event)
{
    if (event.shiftKey)
    {
        if (mouseX > offset && mouseX < myWidth && mouseY > offset && mouseY < myHeight)
        {
            let col = Math.floor(mouseX / r);
            let row = Math.floor(mouseY / r);

            if (tl != null && br != null)
            {
                tl = null;
                br = null;
            }

            if (!tl)
            {
                tl = t[col + n * row];
            } else {
                br = t[col + n * row];
            }

            if (tl != null && br != null)
            {
                updateSum();
            }

        }
    } else {
        if (mouseX > 0 && mouseX < myWidth && mouseY > 0 && mouseY < myHeight)
        {
            let col = Math.floor(mouseX / r);
            let row = Math.floor(mouseY / r);
            t[col + n * row].setState();

            t.forEach(tile => tile.setCount(defineCount(tile)));

            if (tl != null && br != null)
            {
                updateSum();
            }
        }
    }
}

class cTile
{
    constructor(_x, _y, _w)
    {
        this.x = _x;
        this.y = _y;
        this.s = false;
        this.w = _w;
        this.count = 0;
    }

    show()
    {   
        if (this.s)
        {
            fill(191,97,106);
        } else {
            noFill();
        }
        stroke(236,239,244);
        strokeWeight(1);
        rect(this.x, this.y, this.w, this.w);
        if (showCount)
        {
            textSize(18);
            stroke(255);
            fill(255);
            text(this.count.toString(10), this.x + this.w/2 - 3, this.y + this.w/2 + 5);
        }
    }

    setState()
    {
        this.s = !this.s;
    }

    setCount(c)
    {
        this.count = c;
    }
};