//A Ball Machine
//Version: 20240914
//Author: DarkRanger <darkranger.no-ip.org>
//License: MIT License
const version = "20240914";
const hasTouchscreen = "ontouchend" in document;
const defaultWidth = 350;
const defaultHeight = defaultWidth * 1.4;
const defaultColor = "white";
const aggressiveColor = "#f2464c";
const hitColor = "#c4c730";
const trophySize = 10;
const maxBullets = 1;
const maxTrophies = 2;
const trophyColors = [
    "#c91a98",
    "#b5610d",
    "#f2f224",
    "#0db53a",
    "#f2f224",
    "#7970db"
];

var width = defaultWidth;
var height = defaultHeight;
var centerX = width / 2;
var centerY = height / 2;
var plateWidth = width * 0.2;
var debug = false;
var moveLeft = false;
var moveRight = false;
var score = 0;
var gamepadEnabled = false;
var gamepadMovement = 0;
var direction = Math.floor(Math.random() * 2);
var Engine = Matter.Engine,
    Render = Matter.Render,
    Mouse = Matter.Mouse,
    MouseConstraint = Matter.MouseConstraint,
    Runner = Matter.Runner,
    Body = Matter.Body,
    Bodies = Matter.Bodies,
    Composite = Matter.Composite;
    Events = Matter.Events;
var engine = Engine.create();
var render = Render.create({
    element: document.body,
    engine: engine,
    options: {
        width: width,
        height: height
    }
});
var canvasMouse = Mouse.create(document.querySelector("canvas"));
var mConstraint = MouseConstraint.create(engine, {mouse: canvasMouse});
var leftBorder = Bodies.rectangle(0, height / 2, 10, height, {isStatic: true});
var rightBorder = Bodies.rectangle(width, height / 2, 10, height, {isStatic: true});
var manualPlate = Bodies.rectangle(centerX , height * 0.9, plateWidth, 10, {isStatic: true});
var autoPlate = Bodies.rectangle(centerX , height * 0.1, plateWidth, 10, {isStatic: true});
var trophies = [];
var blocks = [];
var bullets = [];
var runner = Runner.create();

for (let i = 0; i < maxTrophies; i++) {
    trophies.push(Bodies.circle(0, 0, trophySize));
    blocks.push(Bodies.rectangle(0, 0, trophySize * 1.5, trophySize, {isStatic: true}));
}

for (let i = 0; i < maxBullets; i++) {
    if (i == 0){
        bullets.push(Bodies.circle(0, 0, trophySize * 1.2));
    }
    else {
        bullets.push(Bodies.circle(0, 0, trophySize));
    }
    
    bullets[i].render.fillStyle = defaultColor;
}

placeTrophies();
placeBullets();
engine.gravity.y = 0.25;
render.options.wireframes = false;
manualPlate.render.fillStyle = defaultColor;
autoPlate.render.fillStyle = defaultColor;
//autoPlate.isSensor = true;
Composite.add(engine.world, [leftBorder, rightBorder, manualPlate, autoPlate]);
Composite.add(engine.world, trophies);
Composite.add(engine.world, blocks);
Composite.add(engine.world, bullets);
Render.run(render);
Runner.run(runner, engine);

function placeTrophies(id) {
    for (let i = 0; i < trophies.length; i++) {
        if (typeof id !== "undefined" && id != i) {
            continue;
        }

        let newX = Math.floor(Math.random() * (width * 0.8)) + (width * 0.1)
        let newY = Math.floor(Math.random() * (height * 0.7 - height * 0.3)) + (height * 0.3)

        Body.setPosition(trophies[i], {x: newX, y: newY});
        Body.setPosition(blocks[i], {x: newX, y: newY + trophySize});
        Body.setAngularVelocity(trophies[i], 0);
        Body.setVelocity(trophies[i], {x: 0, y: 0});
        trophies[i].render.fillStyle = trophyColors[Math.floor(Math.random() * trophyColors.length)];
        blocks[i].render.fillStyle = defaultColor;
    }
}

function placeBullets(id) {
    for (let i = 0; i < bullets.length; i++) {
        if (typeof id !== "undefined" && id != i) {
            continue;
        }

        let newX = Math.floor(Math.random() * width);
        let newY = 50;

        Body.setPosition(bullets[i], {x: newX, y: newY});
    }
}

function movementReset() {
    moveLeft = false;
    moveRight = false;
}

function movePlateLeft() {
    if (manualPlate.position.x > 0) {
        Body.setPosition(manualPlate, {x: manualPlate.position.x -5, y: manualPlate.position.y});
    }
}

function movePlateRight() {
    if (manualPlate.position.x < width) {
        Body.setPosition(manualPlate, {x: manualPlate.position.x +5, y: manualPlate.position.y});
    }
}

function rotatePlateLeft() {
    let rotation = -Math.abs(Math.PI / 6);
    Body.rotate(manualPlate, rotation);
}

function rotatePlateRight() {
    let rotation = Math.PI / 6;
    Body.rotate(manualPlate, rotation);
}

function buttonDown(direction) {
    if (direction == "left") {
        moveLeft = true;
        moveRight = false;
    }
    else if (direction == "right") {
        moveRight = true;
        moveLeft = false;
    }
}

function buttonUp(direction) {
    movementReset();

    if (direction == "left") {
        rotatePlateLeft();
    }
    else if (direction == "right") {
        rotatePlateRight();
    }
}

Events.on(runner, "beforeUpdate", function (event) {
    if (gamepadEnabled) {
        let gamepads = navigator.getGamepads();

        for (let i = 0; i < gamepads.length; i++) {
            if (!gamepads[i]) {
                continue;
            }

            let axisValue = Math.round(gamepads[i].axes[0]);

            if (axisValue == 0 && gamepadMovement != 0) {
                movementReset();

                if (gamepadMovement < 1) {
                    rotatePlateLeft();
                }
                if (gamepadMovement >= 1) {
                    rotatePlateRight();
                }
            }
            if (axisValue < 0) {
                moveLeft = true;
                moveRight = false;
            }
            if (axisValue > 0) {
                moveRight = true;
                moveLeft = false;
            }

            gamepadMovement = axisValue;
        }
    }

    if (moveLeft) {
        movePlateLeft();
    }
    if (moveRight) {
        movePlateRight();
    }

    for (let i = 0; i < trophies.length; i++) {
        if (Matter.Collision.collides(manualPlate, trophies[i]) != null) {
            trophies[i].render.fillStyle = aggressiveColor;
        }
        if (trophies[i].position.y > height) {
            let bonus = 1;

            if (trophies[i].position.x < 0 || trophies[i].position.x > width) {
                bonus = bonus * 10;
            }
            if (trophies[i].render.fillStyle == aggressiveColor) {
                bonus = bonus * 2;
            }
            if (autoPlate.render.fillStyle == hitColor) {
                autoPlate.render.fillStyle = defaultColor;
                bonus = bonus + 3;
            }

            score = score + bonus;
            $("#score").html(`Score: ${score}`);
            placeTrophies(i);
        }
    }

    for (let i = 0; i < bullets.length; i++) {
        for (let j = 0; j < trophies.length; j++) {
            if (Matter.Collision.collides(trophies[j], bullets[i]) != null) {
                Body.setAngularVelocity(bullets[i], 0);
            }
        }

        if (Matter.Collision.collides(manualPlate, bullets[i]) != null) {
            Body.setAngularVelocity(bullets[i], 5);
            bullets[i].render.fillStyle = aggressiveColor;
        }

        if (Matter.Collision.collides(autoPlate, bullets[i]) != null && bullets[i].render.fillStyle == aggressiveColor) {
            autoPlate.render.fillStyle = hitColor;
        }

        if (bullets[i].position.x < 0 || bullets[i].position.x > width) {
            Body.setPosition(bullets[i], {x: centerX, y: bullets[i].position.y});
            Body.setAngularVelocity(bullets[i], 0);
        }

        if (bullets[i].position.y > height) {
            bullets[i].render.fillStyle = defaultColor;
            Body.setPosition(bullets[i], {x: bullets[i].position.x, y: 0});
            Body.setAngularVelocity(bullets[i], 0);
        }
        else if (bullets[i].position.y < -100) {
            Body.setPosition(bullets[i], {x: bullets[i].position.x, y: 0});
            Body.setAngularVelocity(bullets[i], 0);
        }
    }

    if (direction == 0) {
        if (autoPlate.position.x > 0) {
            Body.setPosition(autoPlate, {x: autoPlate.position.x -5, y: autoPlate.position.y});
        }
        else {
            direction = 1;
        }
    }
    else if (direction == 1) {
        if (autoPlate.position.x < width) {
            Body.setPosition(autoPlate, {x: autoPlate.position.x +5, y: autoPlate.position.y});
        }
        else {
            direction = 0;
        }
    }
});

Events.on(mConstraint, "mousedown", function(event) {
    if (event.mouse.mousedownPosition.x < centerX) {
        moveLeft = true;
        moveRight = false;
    }
    else if (event.mouse.mousedownPosition.x > centerX) {
        moveRight = true;
        moveLeft = false;
    }
});

Events.on(mConstraint, "mouseup", function(event) {
    movementReset();

    if (event.mouse.mousedownPosition.x < centerX) {
        rotatePlateLeft();
    }
    else if (event.mouse.mousedownPosition.x > centerX) {
        rotatePlateRight();
    }
});

document.addEventListener("keydown", function (event) {
    if (event.code === "KeyA" || event.code === "ArrowLeft") {
        event.preventDefault();
        moveLeft = true;
        moveRight = false;
    }
    if (event.code === "KeyD" || event.code === "ArrowRight") {
        event.preventDefault();
        moveRight = true;
        moveLeft = false;
    }
}, false);

document.addEventListener("keyup", function (event) {
    if (event.code === "KeyA" || event.code === "ArrowLeft") {
        event.preventDefault();
        movementReset();
        rotatePlateLeft();
    }
    if (event.code === "KeyD" || event.code === "ArrowRight") {
        event.preventDefault();
        movementReset();
        rotatePlateRight();
    }
    if (event.code === "KeyB") {
        debug = !debug;
        render.options.showDebug = !render.options.showDebug;
    }

    //console.log(event.code);
}, false);

window.addEventListener("gamepadconnected", function (event) {
    gamepadEnabled = true;
    console.log("Gamepad enabled.");
}, false);

window.addEventListener("gamepaddisconnected", function (event) {
    gamepadEnabled = false;
    console.log("Gamepad disabled.");
}, false);

$(document).ready(function() {
    $("#score").html(`Score: ${score}`);
    $("#version").text(`Ver: ${version}`);

    if (hasTouchscreen) {
        $("#left-button").attr("ontouchstart", "buttonDown('left')");
        $("#left-button").attr("ontouchend", "buttonUp('left')");
        $("#right-button").attr("ontouchstart", "buttonDown('right')");
        $("#right-button").attr("ontouchend", "buttonUp('right')");
    }
    else {
        $("#left-button").attr("onmousedown", "buttonDown('left')");
        $("#left-button").attr("onmouseup", "buttonUp('left')");
        $("#right-button").attr("onmousedown", "buttonDown('right')");
        $("#right-button").attr("onmouseup", "buttonUp('right')");
    }

    setInterval(function() {
        for (let i = 0; i < bullets.length; i++) {
            if (debug) {
                console.log(`Bullet ${i}: ${Body.getSpeed(bullets[i])}`);
            }
            if (Body.getSpeed(bullets[i]) == 0) {
                placeBullets(i);
            }
        }
    }, 5 * 1000);

    setInterval(function() {
        for (let i = 0; i < trophies.length; i++) {
            if (debug) {
                console.log(`Trophy ${i}: ${Body.getSpeed(trophies[i])}`);
            }
            if (Body.getSpeed(trophies[i]) < 6) {
                placeTrophies(i);
            }
        }
    }, 60 * 1000);
});