// prevent error messages to player
window.onerror=new Function("return true");

// run characteristics
var speed;
var freq;
var demo;
var solo         = "";
var lazy         = "";
var test         = "";
var gravity      = 0;
var losingScore  = 15;
var level;
var game;
var choices;

// general control variables
var increment    = 2;
var busy         = 0;
var pause        = 0;
var reversal     = 0;
var timerId      = "";

// game variables
var playerScore  = 0;
var machineScore = 0;
var lossCycles   = 0;
var testCounter  = 0;
var visible      = "";
var served;
var topOrBottom;
var machineCycles;
var bounceWait;

// board position variables
var boardWidth;
var boardHeight;
var boardTop;
var boardBottom;
var boardLeft;
var boardRight;

// ball position variables
var ballLeft;
var ballBottom;
var ballTop;
var ballRight;
var ballDiameter;
var dx;
var dy;

// paddle position variables
var playerWidth;
var playerHeight;
var playerTop;
var playerBottom;
var playerLeft;
var playerRight;
var machineWidth;
var machineHeight;
var machineTop;
var machineBottom;
var machineLeft;
var machineRight;

// ******************************************************************************
// run when the page is re-freshed

function startUp(gm, dm)
{

    // in case this is a refresh
    cancelTimer();

    // save window location information
    var locWrk = window.location;
    document.hidn.locn.value = locWrk;
    var locate = document.hidn.locn.value;
    choices    = locate.substring(0, (locate.lastIndexOf("/") + 1));
    level      = locate.substring((locate.lastIndexOf("=") + 1), locate.length);

    // setup main game options
    demo = dm;
    if (demo == "d")
        level = "50";

    // for testing
    // lazy = "l";
    // test = "t";

    // setup run parameters for difficulty level
    switch (level)
    {
    case "10":                // beginner
         speed = 60;
         freq  = 2;
         break;
    case "30":                // novice
         speed = 40;
         freq  = 2;
         break;
    case "50":                // intermediate
         speed = 35;
         freq  = 3;
         break;
    case "70":                // experienced
         speed = 30;
         freq  = 4;
         break;
    case "90":                // advanced
         speed = 25;
         freq  = 5;
         break;
    default:                  // catchall
         level = 50;
         speed = 35;
         freq  = 3;
    }

    // setup run parameters for game style
    game  = gm;
    switch (game)
    {
    case "r":                 // racquetball
         choices += "racquetball";
         freq    += 1;
         break;
    case "h":                 // handball
         choices += "handball";
         freq    += 1;
         gravity = 0.05;
         break;
    case "p":                 // ping pong
         choices += "pingPong";
         break;
    default:                  // catchall
         game = "";
    }
    choices += "Intro.html";

    // sanity checks
    if (speed     > 100)
        speed     = 35;
    if (increment < 1)
        increment = 2;
    if (losingScore < 1)
        losingScore = 15;

    // setup board coordinates
    boardWidth    = board.style.posWidth;
    boardHeight   = board.style.posHeight;
    boardTop      = board.style.posTop;
    boardBottom   = boardTop + boardHeight - 1;
    boardLeft     = board.style.posLeft;
    boardRight    = boardLeft + boardWidth - 1;

    // setup paddle coordinates
    playerWidth   = player.style.posWidth;
    playerHeight  = player.style.posHeight;
    playerLeft    = player.style.posLeft;
    playerRight   = playerLeft + playerWidth - 1;
    machineWidth  = machine.style.posWidth;
    machineHeight = machine.style.posHeight;
    machineLeft   = machine.style.posLeft;
    machineRight  = machineLeft + machineWidth - 1;
    if (solo == "s")
        machine.style.visibility = "hidden";

    // setup other
    ballDiameter  = ball.style.posHeight;

    // start demo or complete initialization
    if (demo == "d")
        serve();
    else
        initNonDemo();

}


// ******************************************************************************
// initializations for other than demo run

function initNonDemo()
{

    // setup run parameters for difficulty level
    switch (level)
    {
    case "10":                // beginner
          title10.style.visibility = "visible";
         break;
    case "30":                // novice
         title30.style.visibility = "visible";
         break;
    case "50":                // intermediate
         title50.style.visibility = "visible";
         break;
    case "70":                // experienced
         title70.style.visibility = "visible";
         break;
    case "90":                // advanced
         title90.style.visibility = "visible";
         break;
    default:                  // catchall
         title50.style.visibility = "visible";
    }

    // clear scores in case this is a refresh
    gameDisp.machineBox.value = " ";
    gameDisp.playerBox.value  = " ";
    gameDisp.reverse.value    = " ";
    goal.style.visibility     = "visible";
    win.style.visibility      = "hidden";
    lose.style.visibility     = "hidden";
    over.style.visibility     = "hidden";

}


// ******************************************************************************
// reset for a new game

function newGame()
{

    cancelTimer();
    history.go(0);

}


// ******************************************************************************
// serve and start the ball rolling

function serve()
{

    // if game is wrong...
    if (game == "")
        return;

    // if game ended, do not serve
    if ((playerScore >= losingScore) || (machineScore >= losingScore))
        return;

    // do not allow multiple serves simultaneously
    if ((busy == 1) || (pause == 1))
        return;

    // reset
    bounceWait    = 99;
    machineCycles = 0;
    testCounter   = 0;
    pause         = 0;
    served        = "p";
    lossCycles    = Math.round(20 * Math.random()) + 10;
    topOrBottom   = Math.round(Math.random());
    dx            = increment;
    dy            = increment;
    if (topOrBottom > 0)
        dy = increment * -1;

    // setup initial ball position, except first time
    if ((playerScore != 0) || (machineScore != 0))
    {
        ball.style.posTop  = Math.round((boardHeight - ballDiameter) * Math.random())
                           + boardTop - 1;
        var ofst = Math.round(50 * Math.random());
        if ((game == "r") || (game == "h"))
            ball.style.posLeft = machineLeft - ofst - ballDiameter;
        else
            ball.style.posLeft = machineRight + ofst;
    }
    if ((game == "r") || (game == "h"))
        dx = dx * -1;

    // go
    startTimer();

}


// ******************************************************************************
// go back to games menu

function gameChoices()
{

    // this function does not apply to demos
    if (demo == "d")
        return;

    window.location = choices;

}


// ******************************************************************************
// self starting function to increment the ball, move paddle, etc.

function timerFunction()
{

    // do not allow to continue if game is over or restarted
    if (busy == 0)
        return;

    // get ball position
    ballTop    = ball.style.posTop;
    ballBottom = ballTop + ball.style.posHeight - 1;
    ballLeft   = ball.style.posLeft;
    ballRight  = ballLeft + ball.style.posWidth - 1;

    // get machine paddle positions -- no movements until ball has moved
    if (solo == "s")
    {
        machineTop    = player.style.posTop;
        machineBottom = playerTop + playerHeight - 1;
    }
    else
    {
        machineTop    = machine.style.posTop;
        machineBottom = machineTop + machineHeight - 1;
    }

    // move ball
    for (var i=0; i<=freq; i++)
         moveBall();

    // increment ball
    ball.style.posTop  = ballTop;
    ball.style.posLeft = ballLeft;

    // move machine's paddle with ball
    if (topOrBottom > 0)
        machineTop = ballTop - 6;
    else
        machineTop = ballBottom + 6 - machineHeight + 1;

    // after a while, make its movements inneffective so player wins
    if ((machineCycles > lossCycles) && (demo != "d") && (test != "t"))
    {
        var errorMargin = 2 * ballDiameter * (machineCycles / lossCycles);
        if (topOrBottom > 0)
            machineTop += errorMargin;
        else
            machineTop -= errorMargin;
    }

    // keep paddle from going off the board
    if (machineTop < boardTop)
        machineTop = boardTop;
    machineBottom = machineTop + machineHeight - 1;
    if (machineBottom > boardBottom)
        machineTop = boardBottom - machineHeight + 1;

    // position the paddle
    if (solo != "s")
        machine.style.posTop = machineTop;
    if ((demo == "d") || (lazy == "l"))
        player.style.posTop = machineTop;

}


// ******************************************************************************
// move ball one increment

function moveBall()
{

    // do not allow to continue if game is over
    if (busy == 0)
        return;

    // increment ball
    ballTop    += dy;
    ballBottom += dy;
    ballLeft   += dx;
    ballRight  += dx;

    // bounce ball if it hit the sides of board (fail safe)
    if ((ballTop <= boardTop) && (dy < 0))
        dy = dy * -1;
    if ((ballBottom >= boardBottom) && (dy > 0))
        dy = dy * -1;

    // add gravity effect
    dy += gravity;

    // if missed paddle, someone lost
    if (ballRight >= boardRight)
    {
        if (((game == "r") || (game == "h")) && (served == "m"))
            gameWin();
        else
            gameLose();
        return;
    }
    if (ballLeft <= boardLeft)
    {
        if ((solo != 's') && (game != "r") && (game != "h"))
        {
            gameWin();
            return;
        }
        dx = dx * -1;
        bounceWait = 0;
        if (solo == 's')
            machineCycles += 1;
        return;
    }

    // if just bounced off paddle, wait until far enough from paddle
    bounceWait += 1;
    if (bounceWait < 25)
        return;

    // bring one paddle or other forwards
    if (((game == "r") || (game == "h")) && (visible != served))
    {
        visible = served;
        if (served == "m")
        {
            machine.style.zIndex = 4;
            player.style.zIndex  = 3;
        }
        else
        {
            machine.style.zIndex = 3;
            player.style.zIndex  = 4;
        }
    }

    // if paddles hit, bounce
    if (served == "p")
        servedPlayer();
    else
    if (served == "m")
        servedMachine();

}


// ******************************************************************************

function servedPlayer()

{

    if ((ballRight < playerLeft) || (ballRight > playerRight))
        return;

    playerTop    = player.style.posTop;
    playerBottom = playerTop + playerHeight - 1;

    if ((ballBottom < playerTop) || (ballTop > playerBottom))
        if ((demo != "d") && (lazy != "l"))
            return;

    // bounce ball
    bounceBall();
    served = "m";

}


// ******************************************************************************

function servedMachine()

{

    if (solo == 's')
        return;

    if ((game == "r") || (game == "h"))
    {
        if ((ballRight < machineLeft) || (ballRight > machineRight))
            return;
    }
    else
    {
        if ((ballLeft > machineRight) || (ballLeft < machineLeft))
            return;
    }

    if ((ballBottom < machineTop) || (ballTop > machineBottom))
        if (demo != "d")
            return;

    // bounce ball
    bounceBall();
    served = "p";

    // show speed
    if (test == "t")
    {
        testCounter += 1;
        gameDisp.playerBox.value = " " + testCounter + " ";
    }

}


// ******************************************************************************

function bounceBall()

{

    // bounce ball
    dx = dx * -1;
    bounceWait = 0;
    machineCycles += 1;

    // if no gravity, there is no more work
    if (gravity == 0)
        return;

    // restore vertical momentum lost by gravity
    var chg;
    if (dy > 0)
        chg = increment;
    else
        chg = increment * -1;
    dy = dy - ((dy - chg) * 0.5);

    // if lost momentum almost completely, fix it
    if ((dy < 0.001) && (dy > -0.001))
    {   var mid = (boardBottom - boardTop) / 2;
        if (ballTop < mid)
           dy = increment;
        else
           dy = increment * -1;
    }

}


// ******************************************************************************

function movePaddle()
{

    if ((demo == "d") || (lazy == "l"))
        return;

    var ypos = window.event.y;
    if (ypos < boardTop)
        ypos = boardTop;

    playerBottom = ypos + playerHeight - 1;
    if (playerBottom > boardBottom)
        ypos = boardBottom - playerHeight + 1;

    player.style.posTop = ypos;

}


// ******************************************************************************
// lost the ball

function gameLose()
{

    // this function does not apply to demos
    if (demo == "d")
        return;

    machineScore += 1;
    gameDisp.machineBox.value = " " + machineScore + " ";

    if (machineScore >= losingScore)
    {
        if (solo == "s")
            over.style.visibility = "visible";
        else
            lose.style.visibility = "visible";
    }

    cancelTimer();

}


// ******************************************************************************
// won the ball

function gameWin()
{

    // this function does not apply to demos
    if (demo == "d")
        return;

    playerScore += 1;
    gameDisp.playerBox.value = " " + playerScore + " ";

    if (playerScore >= losingScore)
        win.style.visibility = "visible";

    cancelTimer();

}


// ******************************************************************************
// start timer - do in parts so the motion is not choppy

function startTimer()
{

    timerId = window.setInterval("timerFunction()", speed, "JavaScript");
    busy = 1;

}


// ******************************************************************************
// cancel timer

function cancelTimer()
{

    window.clearInterval(timerId);
    timerId = "";
    busy = 0;

}


// ******************************************************************************
// check for k/b input

function keyPress()
{

    // no keys during demo
    if (demo == "d")
        return;

    // toggle pause
    if ((window.event.keyCode == 80) || (window.event.keyCode == 112))
    {
        if (pause == 0)
        {
            if (busy == 0)
                return;
            cancelTimer();
            pause = 1;
        }
        else
        {
            startTimer();
            pause = 0;
        }
    }

    // reverse function as a result of hitting "h" or "v"
    if (reversal <= 9)
    {
        if ((window.event.keyCode == 86) || (window.event.keyCode == 118))
        {
            dy = dy * -1;
            reversal += 1;
            gameDisp.reverse.value = reversal;
        }
        if ((window.event.keyCode == 72) || (window.event.keyCode == 104))
        {
            dx = dx * -1;
            reversal += 1;
            gameDisp.reverse.value = reversal;
        }
    }
}
