//Easy Whiteboard
//Version: 20230729
//Author: DarkRanger <darkranger.no-ip.org>
//License: MIT License
const version = "20230729";

class SimpleElem {
    constructor() {
        this.empty();
    }

    empty() {
        this.body = "";
    }

    append(content) {
        this.body = this.body + content;
    }

    build() {
        return this.body;
    }
}

class WhiteBoard {
    constructor () {
        this.init();
    }

    init() {
        this.x = 0;
        this.y = 0;
        this.recordX = 0;
        this.recordY = 0;
        this.color = "black";
        this.start = false;
        this.canvas = document.createElement("canvas");
        this.ctx = this.canvas.getContext("2d");
        this.mouseClicked = false;
        this.mouseMovement = false;

        let elem = new SimpleElem();
        elem.append(`<div class="row px-2">`);
        elem.append(`<button id="chisel-mode" class="col-2 btn btn-light btn-sm mt-2 ms-2" onclick="switchMode('chisel')">Chisel</button>`);
        elem.append(`<button id="bullet-mode" class="col-2 btn btn-light btn-sm mt-2 ms-2" onclick="switchMode('bullet')">Bullet</button>`);
        elem.append(`<button id="text-mode" class="col-2 btn btn-light btn-sm mt-2 ms-2" onclick="switchMode('text')">Text</button>`);
        elem.append(`<button id="save-file" class="col-2 btn btn-primary btn-sm mt-2 ms-2" onclick="saveFile()">Save</button>`);
        elem.append(`<button id="open-file" class="col-2 btn btn-warning btn-sm mt-2 ms-2" onclick="openFile()">Open</button>`);
        elem.append(`</div>`);
        elem.append(`<div class="row px-2">`);
        elem.append(`<select id="input-size" class="col-2 btn btn-secondary btn-sm mt-2 ms-2" onchange="switchSize()">`);
        elem.append(`</select>`);
        elem.append(`<select id="input-color" class="col-3 btn btn-light btn-sm mt-2 ms-2" onchange="switchColor()">`);
        elem.append(`<option selected="selected" value="black">Black</option>`);
        elem.append(`<option value="blue">Blue</option>`);
        elem.append(`<option value="red">Red</option>`);
        elem.append(`<option value="green">Green</option>`);
        elem.append(`<option value="orange">Orange</option>`);
        elem.append(`<option value="white">White</option>`);
        elem.append(`</select>`);
        elem.append(`<button id="reset" class="col-2 btn btn-danger btn-sm mt-2 ms-2" onclick="reset()">Reset</button>`);
        elem.append(`<button id="version" class="col-3 btn btn-light btn-sm mt-2 ms-2" disabled>v${version}</button>`);
        elem.append(`</div>`);
    
        $("#content").append(elem.build());
        $("#content").append(this.canvas);

        this.switchMode("chisel");
        this.switchColor();
        this.resetCanvas();
    }

    resetCanvas() {
        this.canvas.width = window.innerWidth;
        this.canvas.height = window.innerHeight * 0.8;
        this.size = Math.round(this.canvas.width * 0.005);

        $("#input-size").empty();

        let elem = new SimpleElem();
        let size = this.size;

        for (let i = 0; i < 8; i++) {
            elem.append(`<option value="${size}">${size}</option>`);
            size = size * 2;
        }
    
        $("#input-size").html(elem.build());

        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.ctx.fillStyle = "white";
        this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
    }

    numberPadding(number) {
        return number.toString().padStart(2, "0");
    }

    getCurrentTime() {
        let today = new Date();
        return `${today.getFullYear()}-${this.numberPadding(today.getMonth()+1)}${this.numberPadding(today.getDate())}-${this.numberPadding(today.getHours())}${this.numberPadding(today.getMinutes())}${this.numberPadding(today.getSeconds())}`;
    }

    saveFile() {
        this.canvas.toBlob((blob) => {
            let a = document.createElement("a");
            a.href = URL.createObjectURL(blob, {type:"image/png}"});
            a.download = `${this.getCurrentTime()}-export.png`;
            a.click();
        });
    }

    openFile() {
        let input = document.createElement("input");
        input.type = "file";
        input.accept = ".png";
    
        input.onchange = event => { 
            let file = event.target.files[0];

            if (!file) {
                return false;
            }

            let reader = new FileReader();

            reader.onload = () => {
                let img = new Image();

                img.onload = () => {
                    this.ctx.drawImage(img, 0, 0, img.width, img.height);
                };

                img.src = reader.result;
            };

            reader.readAsDataURL(file);
        }

        input.click();
    }

    switchMode(mode) {
        this.mode = mode;

        $("button").each(function(index, elem) {
            let id = $(elem).attr("id");
    
            if (!id.endsWith("-mode")) {
                return false;
            }
    
            if (id == `${mode}-mode`) {
                $(elem).removeClass("btn-light");
                $(elem).addClass("btn-info");
            }
            else {
                $(elem).removeClass("btn-info");
                $(elem).addClass("btn-light");
            }
        });
    }

    switchSize() {
        this.size = parseInt($("#input-size").val());
    }

    switchColor() {
        this.color = $("#input-color").val();

        $("#input-color").removeClass("btn-dark");
        $("#input-color").removeClass("btn-primary");
        $("#input-color").removeClass("btn-danger");
        $("#input-color").removeClass("btn-success");
        $("#input-color").removeClass("btn-warning");
        $("#input-color").removeClass("btn-light");

        switch (this.color) {
            case "black":
                $("#input-color").addClass("btn-dark");
                break;

            case "blue":
                $("#input-color").addClass("btn-primary");
                break;

            case "red":
                $("#input-color").addClass("btn-danger");
                break;

            case "green":
                    $("#input-color").addClass("btn-success");
                    break;

            case "orange":
                        $("#input-color").addClass("btn-warning");
                        break;

            case "white":
                $("#input-color").addClass("btn-light");
                break;
        }
    }

    getMousePos(x, y) {
        let rect = this.canvas.getBoundingClientRect();
        this.x = (x - rect.left) / (rect.right - rect.left) * this.canvas.width;
        this.y = (y - rect.top) / (rect.bottom - rect.top) * this.canvas.height;
    }

    chiselDown() {
        this.ctx.lineWidth = this.size;
        this.ctx.beginPath();
        this.ctx.moveTo(this.x, this.y);
        this.recordX = this.x;
        this.recordY = this.y;
    }

    chiselUp() {
        if (this.recordX == this.x && this.recordY == this.y) {
            this.ctx.lineTo(this.x + this.size, this.y);
        }
        else{
            this.ctx.lineTo(this.x, this.y);
        }
        
        this.ctx.strokeStyle = this.color;
        this.ctx.stroke();
    }

    bulletDown() {
        this.ctx.beginPath();
        this.ctx.arc(this.x, this.y, this.size * 0.5 , 0, 2 * Math.PI, false);
        this.ctx.fillStyle = this.color;
        this.ctx.fill();
        this.ctx.closePath();
    }

    fillText() {
        let text = prompt("Enter the text:");

        if (text) {
            this.ctx.beginPath();
            this.ctx.font = `bold ${this.size}px Arial`;
            this.ctx.fillStyle = this.color;
            this.ctx.fillText(text, this.x, this.y);
            this.ctx.fill();
            this.ctx.closePath();
        }
    }

    action(type) {
        switch (type) {
            case "down":
                switch (this.mode) {
                    case "chisel":
                        this.chiselDown();
                        break;

                    case "bullet":
                        this.bulletDown();
                        break;
                }
                break;

            case "move":
                switch (this.mode) {
                    case "chisel":
                        this.chiselUp();
                        break;

                    case "bullet":
                        this.bulletDown();
                        break;
                }
                break;

            case "up":
                switch (this.mode) {
                    case "chisel":
                        this.chiselUp();
                        break;

                    case "bullet":
                        this.bulletDown();
                        break;

                    case "text":
                        this.fillText();
                        break;
                }
                break;
        }
    }

    mouseDown(event) {
        this.getMousePos(event.clientX, event.clientY);
        this.mouseClicked = true;
        this.action("down");
    }
    
    mouseMove(event) {
        this.getMousePos(event.clientX, event.clientY);
    
        if (this.mouseClicked) {
            this.mouseMovement = true;
            this.action("move");
        }
    }
    
    mouseUp(event) {
        this.mouseMovement = false;
        this.mouseClicked = false;
        this.action("up");
    }
    
    touchStart(event) {
        this.getMousePos(event.touches[0].clientX, event.touches[0].clientY);
        this.action("down");
    }
    
    touchMove(event) {
        this.getMousePos(event.touches[0].clientX, event.touches[0].clientY);
        this.mouseMovement = true;
        this.action("move");
    }
    
    touchEnd(event) {
        this.mouseMovement = false;
        this.mouseClicked = false;
        //this.action("up");
    }
}

var whiteboard = new WhiteBoard();

function preventBehavior(event) {
    event.preventDefault(); 
}

function switchMode(mode) {
    whiteboard.switchMode(mode);
}

function saveFile() {
    whiteboard.saveFile();
}

function openFile() {
    whiteboard.openFile();
}

function reset() {
    if (confirm("Are you sure to reset the whiteboard?")) {
        whiteboard.resetCanvas();
    }
}

function switchSize() {
    whiteboard.switchSize();
}

function switchColor() {
    whiteboard.switchColor();
}

function mouseDown(event) {
    whiteboard.mouseDown(event);
}

function mouseMove(event) {
    whiteboard.mouseMove(event);
}

function mouseUp(event) {
    whiteboard.mouseUp(event);
}

function touchStart(event) {
    whiteboard.touchStart(event);
}

function touchMove(event) {
    whiteboard.touchMove(event);
}

function touchEnd(event) {
    whiteboard.touchEnd(event);
}

whiteboard.canvas.addEventListener("mousedown", mouseDown, false);
whiteboard.canvas.addEventListener("mousemove", mouseMove, false);
whiteboard.canvas.addEventListener("mouseup", mouseUp, false);
whiteboard.canvas.addEventListener("touchstart", touchStart, false);
whiteboard.canvas.addEventListener("touchmove", touchMove, false);
whiteboard.canvas.addEventListener("touchend", touchEnd, false);
//document.addEventListener("touchstart", preventBehavior, {passive: false});
document.addEventListener("touchmove", preventBehavior, {passive: false});
//document.addEventListener("touchend", preventBehavior, {passive: false});