var WIDTH = 280;
var HEIGHT = 192;

var COLS = 7;
var ROWS = 6;

var STOP = 0
var UP = 1;
var DOWN = 2;
var LEFT = 3;
var RIGHT = 4;

var STARTX = [0,  0,   0,   224, 224, 48, 80, 112, 144, 176, 208];
var STARTY = [48, 112, 176, 80,  144, 0,  0,  0,   0,   0,   0];
var DIAMONDSX = [5 * 16, 9 * 16, 5 * 16, 9 * 16];
var DIAMONDSY = [5 * 16, 5 * 16, 7 * 16, 7 * 16];
var ENEMY_FIRE_OFFSET_X = [0, 5, 5, 0, 16];
var ENEMY_FIRE_OFFSET_Y = [0, 0, 16, 5, 5];
var CONTROLS = {SINGLE: 1, DUAL: 2, KEYBOARD: 3};
var STATES = {DEAD: -1, WAIT: 0, PEEK: 1, SEEK: 2, EXPLODING: 3, ALIVE: 4};
var GAME_STATES = {PLAYING: 0, GET_READY: 1, GAME_OVER: 2, PAUSED: 3, MENU: 4, CREDITS: 5, INSTRUCTIONS: 6, END_SCREEN: 7, HIGH_SCORES: 8, CONTROLS: 9, FADE_IN: 10, OPTIONS: 11};

var ENEMY_SCORES = [10, 20, 40, 80];
var DIAMOND_SCORES = [100, 200, 400, 800];

var player = {
    x: 8*16,
    y: 10*16,
    width: 16,
    height: 16,
    direction: STOP,
    state: STATES.ALIVE,
    level: 5,
    lives: 10, //2,
    hiscore: 0,
    intersects: intersects
};

var ammo = {
    x: 0,
    y: 0,
    width: 16,
    height: 16,
    intersects: intersects,
    supply: 30
};

var statistics = {
    alive: 11,
    dead: 0,
    startTime: 0,
    endTime: 0,
    shots: 0,
    hits: 0
};

var options = {
    autostop: 0,
    scoreSubmit: 1,
    sound: 1
};

var userInfo;
Website.requestWebsiteInfo(function(info) { userInfo = info; });
var optionsStorageItem;
Storage.requestUserItems(function(array) { if(array && array.length > 0) { optionsStorageItem = array[0]; options = array[0].getStoredObject(); }}, "settings");

var enemies = [];
var diamonds = [];
var friendlyBullets = [];
var enemyBullets = [];
var highscores = [
    {name: "thewiirocks", score: 10000},
    {name: "dr. dredle", score: 9000},
    {name: "negativeone", score: 8000},
    {name: "ngpixel", score: 7000},
    {name: "binar-e", score: 6000},
    {name: "john", score: 5000},
    {name: "aaron", score: 4000},
    {name: "dave", score: 3000},
    {name: "mario", score: 2000},
    {name: "luigi", score: 1000}
];
var highScores = new HighScores();

var canvas = document.createElement("canvas");
var font = new Font(GameUtils.getImage("images/font-white.png"));
var fontRed = new Font(GameUtils.getImage("images/font-red.png"));
var fontBlue = new Font(GameUtils.getImage("images/font-blue.png"));
var fontGreen = new Font(GameUtils.getImage("images/font-green.png"));
var fontYellow = new Font(GameUtils.getImage("images/font-yellow.png"));
var fontGrey = new Font(GameUtils.getImage("images/font-grey.png"));
var score = new Score();

var wiicadeImage = new Image();
var playerImage = new Image();
var enemyImages = [new Image(), new Image(), new Image(), new Image()];
var explosionImage = new Image();
var bulletImage = new Image();
var diamondImages = [new Image(), new Image(), new Image(), new Image()];
var blockImage = new Image();
var blockHolderImage = new Image();
var ammoImages = [new Image(), new Image()];
var bonusImages = [new Image(), new Image(), new Image(), new Image()];
var menuImage = new Image();
var endscreen1Image = new Image();
var highscoresImage = new Image();
var wiicadesmallImage = new Image();
var dualcontrolsImage = new Image();
var singlecontrolsImage = new Image();
var keyboardImage = new Image();

var getreadyText = font.createText("Get Ready!");
var gameoverText = font.createText("Game Over");
var pausedText = font.createText("Paused");
var newgameText = font.createText("New Game");
var instructionsText = font.createText("Instructions");
var highscoresText = font.createText("High Scores");
var optionsText = font.createText("Options");
var creditsText = font.createText("Credits");
var exitText = font.createText("Exit");

var autostopText = font.createText("Auto Stop at Intersections: ");
var scoresubmitText = font.createText("Submit High Scores: ");
var doneText = font.createText("Done");
var onText = fontGreen.createText("On");
var offText = fontRed.createText("Off");

var coverfireText = fontYellow.createText("CoverFire");
var presentedByText = fontGrey.createText("Presented By");
var wiicadecomText = font.createText("WiiCade.com");
var programmerText = fontBlue.createText("Programming: Jerason Banes");
var artworkText = fontRed.createText("Artwork: Ari Feldman (SpriteLib)");
var logoText = fontGreen.createText("Title: Aaron Worrall");
var wiicadeText = fontGrey.createText("WiiCade Homepage:");
var wiicadeURLText = font.createText("http://www.wiicade.com");
var spritelibText = fontGrey.createText("SpriteLib Homepage:");
var spritelibURLText = font.createText("http://www.flyingyogi.com/fun/spritelib.html");

var instructions1Text = [fontRed.createText("Shoot these enemies"), fontRed.createText("to save your city!")];
var instructions2Text = [fontGrey.createText("Rescue the treasure"), fontGrey .createText("for bonus points!")];
var instructions3Text = [font.createText("1st Diamond, 100 Points"), font.createText("2nd Diamond, 200 Points"), font.createText("3rd Diamond, 400 Points"), font.createText("4th Diamond, 800 Points")];
var instructions4Text = [fontYellow.createText("Navigate the"), fontYellow.createText("intersections"), fontYellow.createText("and fire in"), fontYellow.createText("four directions!")];
var instructions5Text = [fontGreen.createText("When you see this"), fontGreen.createText("icon, you need to"), fontGreen.createText("replenish your ammo"), fontGreen.createText("by grabbing this"), fontGreen.createText("powerup!")];
var pointsText = font.createText(" Points");
var pointsTextBlue = fontBlue.createText(" Points");
var pressbuttonText = font.createText("Press any button to continue");
var thText = fontBlue.createText('th');
var placementText = [thText, fontBlue.createText('st'), fontBlue.createText('nd'), fontBlue.createText('rd'), thText, thText, thText, thText, thText, thText, thText, thText, thText, thText, thText, thText, thText, thText, thText, thText];


var newhighscoreText = fontYellow.createText("New High Score");
var scoreText = font.createText("Score: ");
var placeText = font.createText("Place: ");
var levelText = font.createText("Level: ");
var playtimeText = font.createText("Play Time: ");
var shotsfiredText = font.createText("Shots: ");
var accuracyText = font.createText("Accuracy: ");
var goodworkText = [fontRed.createText("Good work soldier!"), fontGrey.createText("Your tireless"), fontGrey.createText("devotion to"), fontGrey.createText("duty may have"), fontGrey.createText("saved us all!"),];

var preloadImages = [playerImage, explosionImage, bulletImage, blockImage, blockHolderImage, menuImage, endscreen1Image, highscoresImage, wiicadesmallImage, dualcontrolsImage, singlecontrolsImage, keyboardImage].concat(enemyImages).concat(diamondImages).concat(ammoImages).concat(bonusImages);
var menuText = [newgameText, instructionsText, highscoresText, optionsText, creditsText, exitText];
var optionsText = [autostopText, scoresubmitText, doneText];
var optionsValues = ["autostop", "scoreSubmit"];

var frame = 0;
var delayedFire = STOP;
var executeStop = false;
var diamondout = false;
var selectMenu = 0;
var selectOption = 0
var menuColor = 120;

var maxImage = 0;
var maxFire = 3;
var maxSeekFire = 3;
var gameState = GAME_STATES.MENU;
var requestRedraw = false;
var selectedControls = CONTROLS.DUAL;

var ctx;

//Internet Explorer
if(!canvas.getContext)
{
    window.location = GameUtils.getImage("browser/index.html", true);
}

canvas.width = WIDTH;
canvas.height = HEIGHT;
if(Wii.isWii())
{
    canvas.style.zIndex = 1000;
    canvas.style.width = window.innerWidth;
    canvas.style.height = window.innerHeight;
    canvas.style.position = "absolute";
}
else
{
    canvas.style.position = "absolute";
    canvas.style.left = (window.innerWidth-WIDTH*2.5)/2;
    canvas.style.top = (window.innerHeight-HEIGHT*2.5)/2;
    canvas.style.width = (WIDTH*2.5)+"px";
    canvas.style.height = (HEIGHT*2.5)+"px";
}

document.body.appendChild(canvas);

//Set the A button to map to the spacebar
KeyboardController.setKeyMapping(WiiRemote.BUTTON_A, 32);

wiicadeImage.src = GameUtils.getImage("images/wiicade_logo.png");
playerImage.src = GameUtils.getImage("images/player.png");
enemyImages[0].src = GameUtils.getImage("images/enemy1.png");
enemyImages[1].src = GameUtils.getImage("images/enemy2.png");
enemyImages[2].src = GameUtils.getImage("images/enemy3.png");
enemyImages[3].src = GameUtils.getImage("images/enemy4.png");
explosionImage.src = GameUtils.getImage("images/explode.png");
bulletImage.src = GameUtils.getImage("images/bullet.png");
diamondImages[0].src = GameUtils.getImage("images/diamond-red.png");
diamondImages[1].src = GameUtils.getImage("images/diamond-green.png");
diamondImages[2].src = GameUtils.getImage("images/diamond-white.png");
diamondImages[3].src = GameUtils.getImage("images/diamond-blue.png");
blockImage.src = GameUtils.getImage("images/block.png");
blockHolderImage.src = GameUtils.getImage("images/blockHolder.png");
ammoImages[0].src = GameUtils.getImage("images/ammo.png");
ammoImages[1].src = GameUtils.getImage("images/ammo-dim.png");
bonusImages[0].src = GameUtils.getImage("images/100.png");
bonusImages[1].src = GameUtils.getImage("images/200.png");
bonusImages[2].src = GameUtils.getImage("images/400.png");
bonusImages[3].src = GameUtils.getImage("images/800.png");
menuImage.src = GameUtils.getImage("images/coverfireLogo.png");
endscreen1Image.src = GameUtils.getImage("images/endscreen1.png");
highscoresImage.src = GameUtils.getImage("images/high_scores.png");
wiicadesmallImage.src = GameUtils.getImage("images/wiicade_small.png");
dualcontrolsImage.src = GameUtils.getImage("images/dualcontrols.png");
singlecontrolsImage.src = GameUtils.getImage("images/singlecontrols.png");
keyboardImage.src = GameUtils.getImage("images/keyboard.png");


function initEnemies()
{
    for(var i=0; i<11; i++)
    {
        enemies[i] = {
            x: STARTX[i], 
            y: STARTY[i], 
            width: 16, 
            height: 16, 
            image: 0, 
            state: STATES.WAIT, 
            direction: STOP, 
            intersects: intersects,
            lastFire: 0
        };
    }
    
    if(player.level < 2) maxImage = 0;
    else if(player.level < 3) maxImage = 1;
    else if(player.level < 5) maxImage = 2;
    else maxImage = 3;
    
    if(player.level < 7) maxFire = 4;
    else if(player.level < 12) maxFire = 3;
    else if(player.level < 16) maxFire = 2;
    else if(player.level < 20) maxFire = 1;
    else maxFire = 0;
    
    if(player.level < 5) maxSeekFire = 4;
    else if(player.level < 7) maxSeekFire = 3;
    else if(player.level < 8) maxSeekFire = 2;
    else if(player.level < 9) maxSeekFire = 1;
    else maxSeekFire = 0;
    
    statistics.alive = 11;
    statistics.dead = 0;
}

function resetEnemies()
{
    for(var i=0; i<11; i++)
    {
        enemies[i].x = STARTX[i];
        enemies[i].y = STARTY[i];
        
        if(enemies[i].state != STATES.DEAD) enemies[i].state = STATES.WAIT;
    }
}

function initDiamonds()
{
    player.collected = -1;
    
    for(var i=0; i<DIAMONDSX.length; i++)
    {
        diamonds[i] = {
            x: DIAMONDSX[i]+1,
            y: DIAMONDSY[i]+2,
            width: 14,
            height: 11,
            image: i,
            state: STATES.WAIT,
            intersects: intersects
        };
    }
}

function initPlayer()
{
    ammo.supply = 30;
    ammo.x = Math.floor(Math.random()*11);
    ammo.y = Math.floor(Math.random()*9);
    
    if(ammo.x%2 == 1 && ammo.y%2 == 1) ammo.y--;
    if((ammo.x == 3 || ammo.x == 7) && ammo.y > 3) ammo.y = 0;  

    ammo.x = ammo.x * 16 + 32;
    ammo.y = ammo.y * 16 + 32;
    
    player.x = 8 * 16;
    player.y = 10 * 16;
    player.direction = STOP;
    delayedFire = STOP;
    
    if(player.counter) delete(player.counter);
}

function initScore()
{
    score.reset();
    //score.refresh();
}

function drawBoard()
{
    ctx.fillRect (0, 0, WIDTH, HEIGHT);
    
    for(var y = 0; y<ROWS; y++)
    {
        for(var x=0; x<COLS; x++)
        {
            if((y == 2 || y == 3) && (x == 2 || x == 4))
            {
                ctx.drawImage(blockHolderImage, x*32+16, y*32+16);
            }
            else
            {
                ctx.drawImage(blockImage, x*32+16, y*32+16);
            }
            
        }
    }
}

function drawLives()
{
    var x = WIDTH - 12;
    var y = 64;
    var fontHeight = font.getFontHeight();
    
    ctx.fillRect(x, y, 16, HEIGHT - y);
  
    font.drawLetter(ctx, 4, x, y);
    y += fontHeight;
    font.drawLetter(ctx, 23, x-1, y);
    y += fontHeight;
    font.drawLetter(ctx, 19, x, y);
    y += fontHeight;
    font.drawLetter(ctx, 17, x, y);
    y += fontHeight;
    font.drawLetter(ctx, 0, x, y);
    y += fontHeight;
        
    x -= 20;
    y = 64;
    
    if(player.lives < 6)
    {
        for(var i=0; i<player.lives; i++)
        {
            ctx.drawImage(playerImage, x, y);
            y += 16;
        }
    }
    else
    {
        
        ctx.drawImage(playerImage, x, y);
        y += 16;
        x += 5;
            
        font.drawLetter(ctx, 23, x, y);
        y += fontHeight;
        
        
        if(player.lives > 9)
        {
            x -= 2;
            x += font.drawDigit(ctx, Math.floor(player.lives/10), x, y);
        }
        
        font.drawDigit(ctx, ((player.lives) % 10), x, y);
    }
}

function clearPlayer()
{
    ctx.fillRect(player.x, player.y, 15, 15);
}

function clearEnemy(index)
{
    ctx.fillRect(enemies[index].x, enemies[index].y, 15, 15);
}

function clearDiamond(index)
{
        if(diamonds[index].state == STATES.WAIT) ctx.drawImage(blockHolderImage, diamonds[index].x-1, diamonds[index].y-2);
    else ctx.fillRect(diamonds[index].x, diamonds[index].y - 2 + ((index < 2) ? -16 : 16), 15, 15);
}

function drawPlayer()
{
    if(player.state == STATES.EXPLODING) drawExplosion(ctx, player);
    else ctx.drawImage(playerImage, player.x, player.y);
}

function drawAmmo()
{
    if(ammo.supply > 10) return;
    
    ctx.fillRect(ammo.x, ammo.y, 15, 15);
    ctx.drawImage(ammoImages[frame%2], ammo.x, ammo.y);
}


function drawEnemies()
{
    for(var i=0; i<enemies.length; i++)
    {
        if(enemies[i].state == STATES.DEAD) continue;
        
        if(enemies[i].state == STATES.EXPLODING) drawExplosion(ctx, enemies[i]);
        else ctx.drawImage(enemyImages[enemies[i].image], enemies[i].x, enemies[i].y);
    }
}

function drawDiamonds()
{
    for(var i=0; i<diamonds.length; i++)
    {
        if(diamonds[i].state == STATES.PEEK) 
        {
            ctx.drawImage(diamondImages[diamonds[i].image], diamonds[i].x, diamonds[i].y + ((i < 2) ? -16 : 16));
        }
        else if(diamonds[i].state == STATES.WAIT) 
        {
            ctx.drawImage(diamondImages[diamonds[i].image], diamonds[i].x, diamonds[i].y);
        }
        else if(diamonds[i].state == STATES.EXPLODING)
        {
            if(!diamonds[i].counter) diamonds[i].counter = 0;
            
            diamonds[i].counter++;
            
            if(diamonds[i].counter > 15)
            {
                delete(diamonds[i].counter);
                clearDiamond(i);
                diamonds[i].state = STATES.DEAD;
            }
            else
            {
                ctx.drawImage(bonusImages[player.collected], diamonds[i].x, diamonds[i].y + ((i < 2) ? -16 : 16));
            }
        }
    }
}

function drawExplosion(ctx, object)
{
    if(!object.counter && !object.counter2) 
    {
        object.counter = 0;
        object.counter2 = 0;
    }
    
    ctx.drawImage(explosionImage, object.counter*16+1, 1, 14, 14, object.x+1, object.y+1, 14, 14);
    
    object.counter2++; // = (object.counter2 + 1) % 3;
    
    if(object.counter2 >= 3) 
    {
        object.counter++;
        object.counter2 -= 3;
    }
    
    if(object.counter >= 6)
    {
        delete(object.counter);
        delete(object.counter2);
        
        object.state = STATES.DEAD;
    }
}

function drawBullets()
{
    for(var i=0; i<friendlyBullets.length; i++)
    {
        ctx.drawImage(bulletImage, friendlyBullets[i].x, friendlyBullets[i].y);    
    }
    
    for(var i=0; i<enemyBullets.length; i++)
    {
        ctx.drawImage(bulletImage, enemyBullets[i].x, enemyBullets[i].y);    
    }
}


function getPlacementText(pos)
{
    if(placementText[pos%100]) return placementText[pos%100];
    
    return placementText[pos%10]
}

function drawEndscreen()
{
    var x;
    var y = 45;
    var divisor = 100000;
    var hiscore = score.getScore();
    var digit;
    var flag = false;
    var playtime = statistics.endTime - statistics.startTime;
    var playMinutes = Math.floor(playtime / 60000);
    var playSeconds = Math.floor(playtime / 1000) % 60;
    var accuracy;
    
    if(!player.placement) player.placement = highScores.getPlacement(hiscore);
    
    ctx.fillRect (0, 0, WIDTH, HEIGHT);
    
    ctx.drawImage(endscreen1Image, WIDTH-128-20, (HEIGHT-128)/2);
    
    newhighscoreText(ctx, 28, 30);
    
    x = 20;
    
    x += scoreText(ctx, 20, y);
    
    for(var i=0; i<6; i++)
    {
        digit = Math.floor(hiscore/divisor)%10;
        
        if(digit > 0 || flag || i == 5) 
        {
            x += fontBlue.drawDigit(ctx, digit, x, y);
            flag = true;
        }
        
        divisor /= 10;
    }
    
    pointsTextBlue(ctx, x, y);
    
    x = 20;
    y += 10;
    flag = false;
    divisor = 1000;
    
    x += placeText(ctx, x, y);
    
    for(var i=0; i<4; i++)
    {
        digit = Math.floor(player.placement/divisor)%10;
        
        if(digit > 0 || flag || i == 3) 
        {
            x += fontBlue.drawDigit(ctx, digit, x, y);
            flag = true;
        }
        
        divisor /= 10;
    }

    x += getPlacementText(player.placement)(ctx, x, y);
    
    x = 20;
    y += 10;
    flag = false;
    divisor = 1000;
    
    x += playtimeText(ctx, x, y);
    
    for(var i=0; i<4; i++)
    {
        digit = Math.floor(playMinutes/divisor)%10;
        
        if(digit > 0 || flag || i == 3) 
        {
            x += fontBlue.drawDigit(ctx, digit, x, y);
            flag = true;
        }
        
        divisor /= 10;
    }
    
    x += font.drawLetter(ctx, font.findLetter("m"), x, y);
    x += 4;
    
    flag = false;
    divisor = 1000;
    
    for(var i=0; i<4; i++)
    {
        digit = Math.floor(playSeconds/divisor)%10;
        
        if(digit > 0 || flag || i == 3) 
        {
            x += fontBlue.drawDigit(ctx, digit, x, y);
            flag = true;
        }
        
        divisor /= 10;
    }
    
    x += font.drawLetter(ctx, font.findLetter("s"), x, y);
    
    x = 20;
    y += 10;
    flag = false;
    divisor = 1000;
    
    x += levelText(ctx, x, y);
    
    for(var i=0; i<4; i++)
    {
        digit = Math.floor(player.level/divisor)%10;
        
        if(digit > 0 || flag || i == 3) 
        {
            x += fontBlue.drawDigit(ctx, digit, x, y);
            flag = true;
        }
        
        divisor /= 10;
    }
    
    x = 20;
    y += 10;
    flag = false;
    divisor = 100000000;
    
    x += shotsfiredText(ctx, x, y);
    
    for(var i=0; i<9; i++)
    {
        digit = Math.floor(statistics.shots/divisor)%10;
        
        if(digit > 0 || flag || i == 8) 
        {
            if(flag && i%3 == 0) x += fontBlue.drawLetter(ctx, font.findLetter(","), x, y);
            
            x += fontBlue.drawDigit(ctx, digit, x, y);
            flag = true;
        }
        
        divisor /= 10;
    }
    
    x = 20;
    y += 10;
    flag = false;
    divisor = 100;
    accuracy = Math.floor(statistics.hits / statistics.shots * 100);
    
    x += accuracyText(ctx, x, y);
    
    for(var i=0; i<3; i++)
    {
        digit = Math.floor(accuracy/divisor)%10;
        
        if(digit > 0 || flag || i == 2) 
        {   
            x += fontBlue.drawDigit(ctx, digit, x, y);
            flag = true;
        }
        
        divisor /= 10;
    }
    
    x += font.drawLetter(ctx, fontBlue.findLetter("%"), x, y);
    
    x = 20;
    y += 16;
    
    for(var i=0; i<goodworkText.length; i++)
    {
        goodworkText[i](ctx, x, y);
        y += 10;
    }
}

function drawHighScores()
{
    var x = 30;
    var y = 45;
    var divisor;
    var offset;
    var flag;
    
    var highscores = highScores.getScores();
    
    ctx.fillRect(0, 0, WIDTH, HEIGHT);
    
    if(!player.counter) player.counter = 0;
    if(player.counter - 40 > highscores.length * 10 + 40) player.counter = 0;;
    
    offset = Math.floor(Math.max(0, player.counter - 40));
    
    for(var i=0; i<highscores.length; i++)
    {
        x = 50;
        divisor = 1000;
        flag = false;
        
        if(offset < -10)
        {
            y += 10;
            continue;
        }
        
        if(i % 2 == 1)
        {
            ctx.fillStyle = "rgb(30,30,30)";
            ctx.fillRect(x-1, y - offset - 1, 180, 8)
            ctx.fillStyle = "rgb(0,0,0)";
        }
        
        for(var j=0; j<4; j++)
        {
            digit = Math.floor((i+1)/divisor)%10;
            
            if(digit > 0 || flag)
            {
                x += fontBlue.drawDigit(ctx, digit, x, y - offset);
                flag = true;
            }
            
            divisor /= 10;
        }
        
        x = 70;
        
        for(var j=0; j<highscores[i].name.length && j < 16; j++)
        {
            x += fontRed.drawLetter(ctx, fontRed.findLetter(highscores[i].name.charAt(j)), x, y - offset); 
        }
        
        x = 188;
        divisor = 100000;
        flag = false;
        
        for(var j=0; j<6; j++)
        {
            if(j > 0 && j%3 == 0) x += font.drawLetter(ctx, font.findLetter(","), x, y - offset);
            
            digit = Math.floor(highscores[i].score/divisor)%10;
            
            if(digit > 0 || flag)
            {
                x += font.drawDigit(ctx, digit, x, y - offset);
                flag = true;
            }
            else
            {
                x += 6;
            }
            
            divisor /= 10;
        }
        
        y += 10;
    }
    
    
    ctx.fillStyle = "rgb(10,10,10)";
    ctx.fillRect(0, 0, WIDTH, 36);
    ctx.fillRect(0, HEIGHT-40, WIDTH, 40);
    ctx.fillStyle = "rgb(0,0,0)";
    
    ctx.drawImage(highscoresImage, (WIDTH-highscoresImage.width)/2, (36-highscoresImage.height)/2);
    pressbuttonText(ctx, 60, HEIGHT - (40-8)/2 - 8);
    
    player.counter += (Wii.isWii() ? 1 : 0.5);
}

function drawInstructions()
{
    var amount = 1;
    var y = 20;
    var x;
    
    ctx.fillRect (0, 0, WIDTH, HEIGHT);
    
    for(var i=0; i<instructions1Text.length; i++)
    {
        x = 10;
        x += instructions1Text[i](ctx, x + (i * 2), y);
        y += 8;
    }
    
    y += 2;
    
    for(var i=0; i<enemyImages.length; i++)
    {
        x = 20;
        ctx.drawImage(enemyImages[i], x, y);
        
        x += 20;
        y += 6;
        x += font.drawDigit(ctx, amount, x, y);
        x += font.drawDigit(ctx, 0, x, y);
        x += pointsText(ctx, x, y);
        
        y += 10;
        amount *= 2;
    }
    
    y = 20;
    
    for(var i=0; i<instructions2Text.length; i++)
    {
        x = 150;
        x += instructions2Text[i](ctx, x + (i * 4), y);
        y += 8;
    }
    
    y += 2;
    
    for(var i=0; i<diamondImages.length; i++)
    {
        x = 130;
        ctx.drawImage(diamondImages[i], x, y);
        
        x += 20;
        y += 5;
        instructions3Text[i](ctx, x, y);
        
        y += 10;
        amount *= 2;
    }
    
    x = 20;
    y += 20;
    
    ctx.drawImage(playerImage, x, y);
    
    ctx.drawImage(bulletImage, x + 5, y - 10);
    ctx.drawImage(bulletImage, x + 5, y + 21);
    ctx.drawImage(bulletImage, x - 10, y + 5);
    ctx.drawImage(bulletImage, x + 20, y + 5);
    
    y -= 10;
    
    for(var i=0; i<instructions4Text.length; i++)
    {
        x = 45;
        x += instructions4Text[i](ctx, x + (i * 4), y);
        y += 8;
    }
    
    x = WIDTH - 35;
    y = 110;
    ctx.drawImage(ammoImages[frame%2], x, y);
    
    y += 2;
    for(var i=0; i<instructions5Text.length; i++)
    {
        x = WIDTH - 130;
        x += instructions5Text[i](ctx, x, y);
        y += 8;
    }
    
    pressbuttonText(ctx, 60, HEIGHT-25);
    
    frame++;
}

function drawCredits()
{
    ctx.fillRect (0, 0, WIDTH, HEIGHT);
    
    coverfireText(ctx, 125, 22);
    presentedByText(ctx, 115, 30);
    wiicadecomText(ctx, 120, 38);
    
    programmerText(ctx, 70, 70);
    artworkText(ctx, 60, 85);
    logoText(ctx, 90, 100);
    
    wiicadeText(ctx, 15, HEIGHT - 53);
    wiicadeURLText(ctx, 15, HEIGHT - 45);
    
    spritelibText(ctx, 15, HEIGHT - 28);
    spritelibURLText(ctx, 15, HEIGHT - 20);
}

function drawFadeIn()
{
    var maxcounter = 120;
    
    ctx.globalAlpha = 1.0;
    
    if(!player.counter) 
    {
        player.counter = 0;
        player.wipeSpeed = 2;
    }
    
    ctx.save();
    ctx.beginPath();
    ctx.moveTo(WIDTH/maxcounter * player.counter * 2.2, 0);
    ctx.lineTo(0, 0);
    ctx.lineTo(0, HEIGHT/maxcounter * player.counter * 2.2);
    ctx.closePath();
    ctx.clip();
    
    drawBoard();
    score.refresh();

    drawAmmo();
    drawEnemies();
    drawPlayer();
    drawDiamonds();
    drawBullets();
    drawLives();
    
    player.counter += player.wipeSpeed;
    player.wipeSpeed++;
    
    ctx.restore();
    
    if(player.counter >= maxcounter)
    {
        delete(player.counter);
        delete(player.wipeSpeed);
        ctx.globalAlpha = 1.0;
        gameState = GAME_STATES.GET_READY;
    }
}

function drawControls()
{
    if(!player.counter) player.counter = 0;
    
    ctx.globalAlpha = Math.min(0.2 + Math.max((player.counter - 10) * 0.1, 0), 1.0);
    
    if(!Wii.isWii())
    {
        ctx.drawImage(keyboardImage, 0, 0);
        selectedControls = CONTROLS.KEYBOARD;
    }
    else if(Wii.getRemote(1).isConnected()) 
    {
        if(selectedControls != CONTROLS.DUAL) 
        {
            player.counter = 0;
            ctx.globalAlpha = 0.2
        }
            
        ctx.drawImage(dualcontrolsImage, 0, 0);
        selectedControls = CONTROLS.DUAL;
        Wii.getRemote(0).setRotated(false);
    }
    else 
    {
        if(selectedControls != CONTROLS.SINGLE)
        {
            player.counter = 0;
            ctx.globalAlpha = 0.2
        }
        
        ctx.drawImage(singlecontrolsImage, 0, 0);
        selectedControls = CONTROLS.SINGLE;
        Wii.getRemote(0).setRotated(true);
    }
    
    player.counter++;
}

function drawMenu()
{
    var y = 90;
    var color = Math.abs(menuColor);
    
    Wii.getRemote(0).setRotated(false);
    ctx.fillRect (0, 0, WIDTH, HEIGHT);
    
    ctx.drawImage(menuImage, 0, 10);
    ctx.drawImage(wiicadesmallImage, 142, 142);
    presentedByText(ctx, 165, 143);
    
    for(var i=0; i<menuText.length; i++)
    {
        if(selectMenu == i)
        {
            ctx.fillStyle = "rgb("+color+","+color+","+color+")";
            ctx.fillRect(48, y-2, 100, 10);
            ctx.fillStyle = "rgb(0,0,0)";
            
            menuColor -= 8;
            
            if(menuColor < -120) menuColor += 240;
        }
        
        menuText[i](ctx, 50, y);
        y += 15;
    }
}



function drawOptions()
{
    var y = 120;
    var color = Math.abs(menuColor);
    
    if(player.transition) delete(player.transition);
    
    ctx.fillRect (0, 0, WIDTH, HEIGHT);
    ctx.drawImage(menuImage, 0, 10);
    
    for(var i=0; i<optionsText.length; i++)
    {
        if(selectOption == i)
        {
            ctx.fillStyle = "rgb("+color+","+color+","+color+")";
            ctx.fillRect(30, y-2, 150, 10);
            ctx.fillStyle = "rgb(0,0,0)";
            
            menuColor -= 8;
            
            if(menuColor < -120) menuColor += 240;
        }
        
        x = 200;
        optionsText[i](ctx, 32, y);
        
        if(optionsValues[i]) options[optionsValues[i]] ? onText(ctx, x, y) : offText(ctx, x, y);
        
        y += 15;
    }
}

function update()
{
    Wii.getRemote(1); //Make sure events fire!
    
    if(gameState == GAME_STATES.MENU)
    {
        drawMenu();
        return;
    }
    else if(gameState == GAME_STATES.CREDITS)
    {
        drawCredits();
        return;
    }
    else if(gameState == GAME_STATES.INSTRUCTIONS)
    {
        drawInstructions();
        return;
    }
    else if(gameState == GAME_STATES.END_SCREEN)
    {
        drawEndscreen();
        return;
    }
    else if(gameState == GAME_STATES.HIGH_SCORES)
    {
        drawHighScores();
        return;
    }
    else if(gameState == GAME_STATES.CONTROLS)
    {
        drawControls();
        return;
    }
    else if(gameState == GAME_STATES.FADE_IN)
    {
        drawFadeIn();
        return;
    }
    else if(gameState == GAME_STATES.OPTIONS)
    {
        drawOptions();
        return;
    }
    else if(gameState == GAME_STATES.PAUSED)
    {
        pausedText(ctx, 16 * 7 - 8, (HEIGHT+8)/2);
        return;
    }
    
    if(statistics.alive == 0 && player.state == STATES.ALIVE)
    {
        player.level++;
        
        friendlyBullets = [];
        enemyBullets = [];
        
        initPlayer();
        initDiamonds();
        initEnemies();
        //drawBoard();
        //score.refresh();
        requestRedraw = true;
        
        gameState = GAME_STATES.GET_READY;;
    }
    
    if(player.state == STATES.DEAD && player.lives > 0)
    {
        player.lives--;
        player.state = STATES.ALIVE;
        
        friendlyBullets = [];
        enemyBullets = [];
        
        resetEnemies();
        initPlayer();
        //drawBoard();
        //score.refresh();
        requestRedraw = true;
        
        gameState = GAME_STATES.GET_READY;
        player.state = STATES.ALIVE;
    }
    else if(player.state == STATES.DEAD)
    {
        gameState = GAME_STATES.GAME_OVER;
        
        if(!player.counter) player.counter = 1;
        else player.counter++;
        
        if(player.counter > 70)
        {
            delete(player.counter);
            statistics.endTime = new Date().getTime();
            
            if(score.getScore() <= highScores.getMinimumScore() || !userInfo.getUserName() || !options.scoreSubmit) 
            {
                gameState = GAME_STATES.MENU;
            }
            else 
            {
                gameState = GAME_STATES.END_SCREEN;
                player.hiscore = score.getScore();
                
                highScores.insertHighScore({
                    name: userInfo.getUserName().toLowerCase(), 
                    score: player.hiscore, 
                    shots: statistics.shots, 
                    hits: statistics.hits, 
                    playTime: (statistics.endTime - statistics.startTime),
                    date: new Date().getTime(),
                    wii: Wii.isWii()
                });
            }
        }
    }
    
    if(gameState != GAME_STATES.GET_READY)
    {
        movePlayer();
        moveEnemies();
        moveBullets();
        moveDiamonds();
    }
    else
    {
        delayedFire = STOP;
    }
    
    if(requestRedraw)
    {
        drawBoard();
        score.refresh();
        
        requestRedraw = false;
    }
    
    drawAmmo();
    drawEnemies();
    if(player.state != STATES.DEAD) drawPlayer();
    drawDiamonds();
    drawBullets();
    drawLives();
    
    if(gameState == GAME_STATES.GAME_OVER) gameoverText(ctx, 16 * 7 - 8, (HEIGHT+8)/2);
        
    if(gameState == GAME_STATES.GET_READY) 
    {
        getreadyText(ctx, 16 * 7 - 8, (HEIGHT+8)/2);


        if(!player.counter) player.counter = 1;
        else player.counter++;
        
        if(player.counter > 30)
        {
            delete(player.counter);
            //drawBoard();
            //score.refresh();
            requestRedraw = true;
            gameState = GAME_STATES.PLAYING;
        }
    }
    else 
    {
        frame++;
    }
}

function movePlayer()
{
    var remote1 = Wii.getRemote(0);
    
    clearPlayer();
    
    if(player.state != STATES.ALIVE) return;
    if(remote1.isDown(WiiRemote.BUTTON_A)) executeStop = true;
    
    if((player.x%32) == 0 && (player.y%32) == 0 && (executeStop || selectedControls == CONTROLS.SINGLE || options.autostop))
    {
        player.direction = STOP;
        executeStop = false;
    }
    
    
    if(selectedControls != CONTROLS.SINGLE || (selectedControls == CONTROLS.SINGLE && !remote1.isDown(WiiRemote.BUTTON_1)))
    {
        if(remote1.isDown(WiiRemote.BUTTON_LEFT) && (player.y%32) == 0) player.direction = LEFT;
        if(remote1.isDown(WiiRemote.BUTTON_RIGHT) && (player.y%32) == 0) player.direction = RIGHT;
        if(remote1.isDown(WiiRemote.BUTTON_UP) && (player.x%32) == 0) player.direction = UP;
        if(remote1.isDown(WiiRemote.BUTTON_DOWN) && (player.x%32) == 0) player.direction = DOWN;
    }
    
    if(player.direction == LEFT) player.x -= 4;
    if(player.direction == RIGHT) player.x += 4;
    if(player.direction == UP) player.y -= 4;
    if(player.direction == DOWN) player.y += 4;
    
    if(player.x < 32) player.x = 32;
    if(player.y < 32) player.y = 32;
    if(player.x > 192) player.x = 192;
    if(player.y > 160) player.y = 160;
    
    if(delayedFire != STOP)
    {
        if(delayedFire == LEFT && (player.y%32) == 0) createBullet(LEFT, true, player.x-4, player.y+5);
        if(delayedFire == RIGHT && (player.y%32) == 0) createBullet(RIGHT, true, player.x+16, player.y+5);
        if(delayedFire == UP && (player.x%32) == 0) createBullet(UP, true, player.x+5, player.y-4);
        if(delayedFire == DOWN && (player.x%32) == 0) createBullet(DOWN, true, player.x+5, player.y+16);
    }
    
    if(ammo.supply <= 10 && player.intersects(ammo))
    {
        ammo.supply += 30;
        
        ctx.fillRect(ammo.x, ammo.y, 15, 15);
    }
}

function moveEnemies()
{
    var alive = 0;
    var dead = 0;
    
    for(var i=0; i<enemies.length; i++)
    {
        if(enemies[i].state == STATES.PEEK)
        {
            var distance = (i >= 5) ? STARTX[i] - enemies[i].x : STARTY[i] - enemies[i].y;
            
            if(distance < 16)
            {
                clearEnemy(i);
                if(i >= 5) enemies[i].x -= 2;
                else enemies[i].y -= 2
            }
            else
            {
                var change = (Math.random() * 1000 > 940) || statistics.alive < 5;
                var amount = (Math.random() * 1000);
                
                if(change) 
                {
                    if(amount > 700 || statistics.alive < 5) 
                    {
                        enemies[i].state = STATES.SEEK;
                        enemies[i].direction = (i >= 5) ? DOWN : (i >= 3 ) ? LEFT : RIGHT;
                    }
                    else if(amount > 200 && frame > enemies[i].lastFire+6)
                    {
                        if(i >= 5) createBullet(DOWN, false, enemies[i].x + 5, enemies[i].y + 16);
                        else if(i >= 3) createBullet(LEFT, false, enemies[i].x, enemies[i].y + 5);
                        else createBullet(RIGHT, false, enemies[i].x + 16, enemies[i].y + 5);
                        
                        enemies[i].lastFire = frame;
                    }
                    else 
                    {
                        enemies[i].state = STATES.WAIT;
                    }
                }
            }
            
            alive++;
        }
        else if(enemies[i].state == STATES.WAIT)
        {
            var distance = (i >= 5) ? STARTX[i] - enemies[i].x : STARTY[i] - enemies[i].y;
            var change = (Math.random() * 1000 > 990) || statistics.alive < 5;
            
            if(distance > 0)
            {
                clearEnemy(i);
                if(i >= 5) enemies[i].x += 2;
                else enemies[i].y += 2
            }
            else if(change) 
            {
                enemies[i].state = STATES.PEEK;
            }
            
            alive++;
        }
        else if(enemies[i].state == STATES.SEEK)
        {
            var distx = player.x - enemies[i].x;
            var disty = player.y - enemies[i].y;
            
            clearEnemy(i);
            
            switch(enemies[i].direction)
            {
                case LEFT:
                    enemies[i].x -= 2;
                    break;
                case RIGHT:
                    enemies[i].x += 2;
                    break;
                case UP:
                    enemies[i].y -= 2;
                    break;
                case DOWN:
                    enemies[i].y += 2;
                    break;
            }
            
            if((enemies[i].x%32) == 0 && (enemies[i].y%32) == 0)
            {
                if(Math.abs(disty) > Math.abs(distx))
                {
                    enemies[i].direction = (disty < 0) ? UP : DOWN;
                }
                else
                {
                    enemies[i].direction = (distx < 0) ? LEFT : RIGHT;
                }
            }
            
            if(maxFire <= enemies[i].image || (statistics.alive < 5 && maxSeekFire <= enemies[i].image))
            {
                var fire = (Math.random() * 1000 > 980);
                
                if(fire && frame > enemies[i].lastFire+6)
                {
                    createBullet(enemies[i].direction, false, enemies[i].x + ENEMY_FIRE_OFFSET_X[enemies[i].direction], enemies[i].y +  + ENEMY_FIRE_OFFSET_Y[enemies[i].direction]);
                    
                    enemies[i].lastFire = frame;
                }
            }
            
            intersectEnemy(enemies[i]);
            
            alive++;
        }
        else if(enemies[i].state == STATES.DEAD)
        {
            clearEnemy(i);
            
            if(enemies[i].image >= maxImage) dead++;
            else alive++;
            
            if(enemies[i].image >= maxImage) continue;
            if(!enemies[i].counter) enemies[i].counter = 0;   
            
            enemies[i].counter++;
            
            if(enemies[i].counter > 5)
            {
                delete(enemies[i].counter);
                
                enemies[i].x = STARTX[i];
                enemies[i].y = STARTY[i];
                enemies[i].image++;
                enemies[i].state = STATES.WAIT;
            }
        }
        else
        {
            clearEnemy(i);
         
            if(enemies[i].image >= maxImage) dead++;
            else alive++;
        }
    }
    
    statistics.alive = alive;
    statistics.dead = dead;
}

function moveDiamonds()
{
    var time = Math.min(100 + (player.level * 20), 300);
    
    if(diamondout)
    {
        for(var i=0; i<diamonds.length; i++)
        {
            if(diamonds[i].state != STATES.PEEK) continue;
            
            diamonds[i].y += (i < 2) ? -16 : 16;
                
            if(player.intersects(diamonds[i]))
            {
                
                
                diamonds[i].y -= (i < 2) ? -16 : 16;
                clearDiamond(i);
                player.collected++;
                score.add(DIAMOND_SCORES[player.collected]);
                diamonds[i].state = STATES.EXPLODING;
            }
            else
            {
                diamonds[i].y -= (i < 2) ? -16 : 16;
            }
            
        }
    }
    
    if(frame == 0 || frame%time != 0) return;
    
    if(diamondout)
    {
        for(var i=0; i<diamonds.length; i++)
        {
            if(diamonds[i].state == STATES.PEEK) 
            {
                clearDiamond(i);
                diamonds[i].state = STATES.WAIT;
            }
        }
        
        diamondout = false;
    }
    else
    {
        var index = Math.floor(Math.random() * 1000) % 4;
        var tries = 0;

        //In case the selected diamond has already been used.
        for(var i=0; diamonds[index].state != STATES.WAIT && i<4; i++) index = (index + 1) % 4;
        
        //No diamonds left!
        if(diamonds[index].state != STATES.WAIT) return;
        
        clearDiamond(index);
        diamonds[index].state = STATES.PEEK;
        diamondout = true;
    }
}

function moveBullets()
{   
    for(var i=0; i<friendlyBullets.length; i++)
    {
        ctx.fillRect(friendlyBullets[i].x, friendlyBullets[i].y, friendlyBullets[i].width, friendlyBullets[i].height);
        
        switch(friendlyBullets[i].direction)
        {
            case UP:
                friendlyBullets[i].y -= 6;
                if(friendlyBullets[i].y < 0) friendlyBullets.splice(i--, 1);
                break;
            case DOWN:
                friendlyBullets[i].y += 6;
                if(friendlyBullets[i].y > HEIGHT) friendlyBullets.splice(i--, 1);
                break;
            case LEFT:
                friendlyBullets[i].x -= 6;
                if(friendlyBullets[i].x < 0) friendlyBullets.splice(i--, 1);
                break;
            case RIGHT:
                friendlyBullets[i].x += 6;
                if(friendlyBullets[i].x > WIDTH) friendlyBullets.splice(i--, 1);
                break;
        }
        
        if(i >= 0 && intersectBullet(friendlyBullets[i])) friendlyBullets.splice(i--, 1);
    }
    
    
    for(var i=0; i<enemyBullets.length; i++)
    {
        ctx.fillRect(enemyBullets[i].x, enemyBullets[i].y, enemyBullets[i].width, enemyBullets[i].height);
        
        switch(enemyBullets[i].direction)
        {
            case UP:
                enemyBullets[i].y -= 5;
                if(enemyBullets[i].y < 0) enemyBullets.splice(i--, 1);
                break;
            case DOWN:
                enemyBullets[i].y += 5;
                if(enemyBullets[i].y > HEIGHT) enemyBullets.splice(i--, 1);
                break;
            case LEFT:
                enemyBullets[i].x -= 5;
                if(enemyBullets[i].x < 0) enemyBullets.splice(i--, 1);
                break;
            case RIGHT:
                enemyBullets[i].x += 5;
                if(enemyBullets[i].x > WIDTH) enemyBullets.splice(i--, 1);
                break;
        }
        
        if(i >= 0 && player.intersects(enemyBullets[i]) && player.state == STATES.ALIVE)
        {
            player.state = STATES.EXPLODING;
            enemyBullets.splice(i--, 1);
            return;
        }
    }
}

function intersectEnemy(enemy)
{
    if(player.intersects(enemy) && player.state == STATES.ALIVE)
    {
        player.state = STATES.EXPLODING;
        enemy.state = STATES.EXPLODING;
        return;
    }
    
    for(var i=0; i<enemies.length; i++)
    {
        if(enemies[i].state == STATES.SEEK && enemy !== enemies[i] && enemy.intersects(enemies[i]))
        {
            enemy.state = STATES.EXPLODING;
            enemies[i].state = STATES.EXPLODING;
            return;
        }
    }
}

function intersectBullet(bullet)
{
    for(var i=0; i<enemies.length; i++)
    {
        if(enemies[i].state != STATES.DEAD && enemies[i].state !== STATES.EXPLODING && enemies[i].intersects(bullet))
        {
            enemies[i].state = STATES.EXPLODING;
            score.add(ENEMY_SCORES[enemies[i].image]);
            statistics.hits++;
            return true;
        }
    }

    return false;
}

function intersects(object)
{
    if(object.x+object.width-2 < this.x+2) return false;
    if(object.y+object.height-2 < this.y+2) return false;
    if(this.x+this.width-2 < object.x+2) return false;
    if(this.y+this.height-2 < object.y+2) return false;
    
    return true;
}

function createBullet(direction, friendly, x, y)
{
    var bullet = {direction: direction, x: x, y: y, width: 5, height: 5};
    
    if(friendly) 
    {
        if(ammo.supply < 1) return;
        
        friendlyBullets.push(bullet);
        ammo.supply--;
        statistics.shots++;
    }
    else 
    {
        enemyBullets.push(bullet);
    }
    
    if(friendly) delayedFire = STOP;
}


function init()
{
    var logoelement;
    var fader;
    var fader2;
    
    try
    {
        if(!wiicadeImage.complete)
        {
            setTimeout(init, 250);
            return;
        }
        
        //This is a lousy way to do this, but it's fast and easy to get into
        //the init function. Shoot me later.
        if(!player.counter && !logoelement) 
        {
            document.body.style.backgroundColor = "white";
            
            fader2 = function() {
                var bgcolor = Math.floor(player.counter * 255);
                
                document.body.style.backgroundColor = "rgb("+bgcolor+","+bgcolor+","+bgcolor+")";
                
                player.counter += player.fadeSpeed;
                player.fadeSpeed += player.fadeDirection;
                
                if(player.counter > -10) 
                {
                    if(Wii.isWii()) setTimeout(fader2, 100);
                    else setTimeout(fader2, 50);
                
                    return;
                }
                
                player.counter = 1;
                delete(logoelement);

                setTimeout(init, 50);
            };
            
            (fader = function()
            {
                if(!logoelement) 
                {
                    player.counter = 0;
                    player.fadeDirection = 0.01;
                    player.fadeSpeed = 0.01;
                    
                    logoelement = document.createElement("img");
                    logoelement.src = wiicadeImage.src;
                    logoelement.style.position = "absolute";
                    logoelement.style.left = (window.innerWidth-wiicadeImage.width)/2;
                    logoelement.style.top = (window.innerHeight-wiicadeImage.height)/2;
                    logoelement.style.opacity = 0.0;
                    
                    document.body.appendChild(logoelement);
                }
        
                logoelement.style.opacity = Math.max(0.0, Math.min(player.counter, 1.0));
                
                player.counter += player.fadeSpeed;
                player.fadeSpeed += player.fadeDirection;
                
                if(player.counter >= 15) 
                {
                    player.fadeDirection = -0.01;
                    player.fadeSpeed = -0.001;
                    player.counter = 1.0;
                }
                
                if(player.counter > -10) 
                {
                    if(Wii.isWii()) setTimeout(fader, 40);
                    else setTimeout(fader, 50);
                
                    return;
                }
                
                document.body.removeChild(logoelement);
                
                //delete(logoelement);
                
                player.counter = 1.0;
                player.fadeDirection = -0.01;
                player.fadeSpeed = -0.01;
                
                if(!Wii.isWii()) 
                {
                    setTimeout(fader2, 50);
                    return;
                }
                else
                {
                    delete(logoelement);
                    setTimeout(init, 50);
                }
                
            })();
        }
        
        if(logoelement) return;
        
        for(var i=0; i<preloadImages.length; i++)
        {
            if(!preloadImages[i].complete)
            {
                setTimeout(init, 250);
                return;
            }
        }
        
        delete(wiicadeImage);
        
        delete(player.counter);
        delete(player.fadeDirection);
        delete(player.fadeSpeed);
        
        ctx = canvas.getContext("2d");
        ctx.fillStyle = "rgb(0,0,0)";
        
        
        if(!Wii.isWii()) setInterval(update, 40);
        else  setInterval(update, 30);
    }
    catch(e)
    {
        if(e.message) 
            alert("Error: Could not initialize the game. Message: ["+e.message+"]");
        else
            alert("Error: Could not initialize the game. Message: ["+e+"]");
    }
}

function multipadListener(event)
{
    if(!event.buttonCode) return;
    
    if(gameState == GAME_STATES.CONTROLS)
    {
        gameState = GAME_STATES.FADE_IN;
        
        initPlayer();
        initEnemies();
        initDiamonds();
        //drawBoard();
        //drawPlayer();
        initScore();
        
        return;
    }
    
    if(gameState == GAME_STATES.CREDITS || gameState == GAME_STATES.INSTRUCTIONS || gameState == GAME_STATES.END_SCREEN || gameState == GAME_STATES.HIGH_SCORES) 
    {
        gameState = GAME_STATES.MENU;
        delete(player.counter);
        return;
    }
    
    if(gameState == GAME_STATES.MENU)
    {
        if(event.buttonCode == WiiRemote.BUTTON_DOWN || event.buttonCode == WiiRemote.BUTTON_LEFT) 
        {
            selectMenu = (selectMenu + 1) % menuText.length;
            menuColor = -120;
        }
        else if(event.buttonCode == WiiRemote.BUTTON_UP || event.buttonCode == WiiRemote.BUTTON_RIGHT) 
        {
            selectMenu = (selectMenu - 1);
            if(selectMenu < 0) selectMenu += menuText.length;
            menuColor = -120;
        }
        else if(event.buttonCode == WiiRemote.BUTTON_A || event.buttonCode == WiiRemote.BUTTON_1) 
        {
            if(menuActions[selectMenu] != null) menuActions[selectMenu]();
        }
    }
    
    if(gameState == GAME_STATES.OPTIONS && !player.transition)
    {
        if(event.buttonCode == WiiRemote.BUTTON_DOWN || event.buttonCode == WiiRemote.BUTTON_LEFT) 
        {
            selectOption = (selectOption + 1) % optionsText.length;
            menuColor = -120;
        }
        else if(event.buttonCode == WiiRemote.BUTTON_UP || event.buttonCode == WiiRemote.BUTTON_RIGHT) 
        {
            selectOption = (selectOption - 1);
            if(selectOption < 0) selectOption += optionsText.length;
            menuColor = -120;
        }
        else if(event.buttonCode == WiiRemote.BUTTON_A || event.buttonCode == WiiRemote.BUTTON_1) 
        {
            if(optionsValues[selectOption])
            {
                options[optionsValues[selectOption]]  = !options[optionsValues[selectOption]] ? 1 : 0;
                options.change = true;
            }
            else
            {
                if(options.change)
                {
                    delete(options.change);
                    if(optionsStorageItem) optionsStorageItem.remove();
                    
                    try{ Storage.insert("settings", options, false); } catch(e) {}
                }
            
                gameState = GAME_STATES.MENU;
                return;
            }
        }
    }
    
    if(gameState != GAME_STATES.PLAYING && gameState != GAME_STATES.PAUSED) return;
    
    if(event.buttonCode == WiiRemote.BUTTON_PLUS)
    {
        if(gameState == GAME_STATES.PLAYING) 
        {
            gameState = GAME_STATES.PAUSED;
        }
        else if(gameState == GAME_STATES.PAUSED) 
        {
            //drawBoard();
            //score.refresh();
            requestRedraw = true;
            gameState = GAME_STATES.GET_READY;
        }
    }
    
    if(selectedControls == CONTROLS.SINGLE && Wii.getRemote(0).isDown(WiiRemote.BUTTON_1))
    {
        if(event.buttonCode == WiiRemote.BUTTON_LEFT) delayedFire = LEFT;
        else if(event.buttonCode == WiiRemote.BUTTON_RIGHT) delayedFire = RIGHT;
        else if(event.buttonCode == WiiRemote.BUTTON_UP) delayedFire = UP;
        else if(event.buttonCode == WiiRemote.BUTTON_DOWN) delayedFire = DOWN;
    }
}

if(!Wii.isWii())
{
    KeyboardController.setKeyMapping(WiiRemote.BUTTON_PLUS, 80); 
    KeyboardController.setKeyMapping(WiiRemote.BUTTON_1, 13);
    KeyboardController.setKeyMapping(WiiRemote.BUTTON_2, null);
}

Wii.getRemote(0).addEventListener("buttondown", multipadListener, false);
Wii.getRemote(1).addEventListener("buttondown", multipadListener, false);


Wii.getRemote(1).addEventListener("buttondown", function(event) {
    if(gameState != GAME_STATES.PLAYING || player.state != STATES.ALIVE) return;

    if(event.buttonCode == WiiRemote.BUTTON_LEFT) delayedFire = LEFT;
    else if(event.buttonCode == WiiRemote.BUTTON_RIGHT) delayedFire = RIGHT;
    else if(event.buttonCode == WiiRemote.BUTTON_UP) delayedFire = UP;
    else if(event.buttonCode == WiiRemote.BUTTON_DOWN) delayedFire = DOWN;
    else if(event.buttonCode == WiiRemote.BUTTON_A) executeStop = true;
    else return;
    
    if(delayedFire != STOP)
    {
        executeStop = false;
    }
    
}, false);

document.addEventListener("keydown", function(event) {
    if(!(event.keyCode == 87 || event.keyCode == 83 || event.keyCode == 65 || event.keyCode == 68))
    {
        return;
    }

    if(gameState == GAME_STATES.CONTROLS)
    {
        gameState = GAME_STATES.FADE_IN;
        
        initPlayer();
        initEnemies();
        initDiamonds();
        //drawBoard();
        //drawPlayer();
        initScore();
        
        return;
    }
    
    if(gameState == GAME_STATES.CREDITS || gameState == GAME_STATES.INSTRUCTIONS || gameState == GAME_STATES.END_SCREEN || gameState == GAME_STATES.HIGH_SCORES) 
    {
        gameState = GAME_STATES.MENU;
        delete(player.counter);
        return;
    }
    
    if(gameState == GAME_STATES.OPTIONS && !player.transition) 
    {
        if(optionsValues[selectOption])
        {
            options[optionsValues[selectOption]]  = !options[optionsValues[selectOption]] ? 1 : 0;
            options.change = true;
        }
        else
        {
            if(options.change)
            {
                delete(options.change);
                if(optionsStorageItem) optionsStorageItem.remove();
                
                try{ Storage.insert("settings", options, false); } catch(e) {}
            }
            
            gameState = GAME_STATES.MENU;
            return;
        }
    }
    
    if(gameState == GAME_STATES.MENU)
    {
        if(menuActions[selectMenu] != null) menuActions[selectMenu]();
        return;
    }
        
    if(gameState != GAME_STATES.PLAYING || player.state != STATES.ALIVE) return;

    if(event.keyCode == 65) delayedFire = LEFT;
    else if(event.keyCode == 68) delayedFire = RIGHT;
    else if(event.keyCode == 87) delayedFire = UP;
    else if(event.keyCode == 83) delayedFire = DOWN;
    else return;
    
    if(delayedFire != STOP)
    {
        executeStop = false;
    }
    
}, false);

init();


function Font(file)
{
    var alphabet = "abcdefghijklmnopqrstuvwxyz0123456789!?:.;,\"()[]\\/-%";
    //            a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 ! ? : . ; , " ( ) [ ] \ / - %
    var widths = [6,6,6,6,5,5,6,6,3,6,6,5,7,7,6,6,6,6,6,5,6,7,7,7,7,5,6,5,6,6,6,6,6,6,6,6,3,6,4,4,5,5,6,5,5,5,5,5,5,5,7];
    var positions = [];
    var image = new Image();
    
    var temp = 0;
    
    image.src = file;
    
    for(var i=0; i<alphabet.length; i++)
    {
        positions[i] = temp;
        
        temp += widths[i];
    }
    
    this.findLetter = function(letter) {
        for(var i=0; i<alphabet.length; i++)
        {
            if(alphabet.charAt(i) == letter) return i;
        }
        
        return null;
    };
    
    this.drawLetter = function(ctx, value, x, y) {
        var width;
        
        if(value === null)
        {
            return 4;
        }
        else
        {
            width = widths[value];
            ctx.drawImage(image, positions[value], 0, width, image.height, x, y, width, image.height);
            return width;
        }
    }
    
    this.drawDigit = function(ctx, digit, x, y)
    {
        return this.drawLetter(ctx, 26+digit, x, y);
    }
    
    this.createText = function(text) {
        var array = [];
        
        text = text.toLowerCase();
        
        for(var i=0; i<text.length; i++) 
        {
            array[i] = this.findLetter(text.charAt(i));
        }
        
        return function(ctx, x, y) {
            var offset = 0;
            var value;
           
            for(var i=0; i<array.length; i++)
            {
                value = array[i];
                
                if(value === null)
                {
                    offset += 4;
                    continue;
                }
                else
                {
                    ctx.drawImage(image, positions[value], 0, widths[value], image.height, x + offset, y, widths[value], image.height);
                    offset += widths[value];
                }
            }
            
            return offset;
        }
    };
    
    this.getFontHeight = function() { return image.height; };
}

function Score()
{
    var score = 0;
    var lastLife = 0;
    var scoreText = font.createText("score");
    var levelText = font.createText("level");
    
    this.reset = function() { score = 0; lastLife = 0; };
    this.add = function(value) { 
        score += value; this.refresh(); 
        
        if(score - lastLife >= 5000)
        {
            player.lives++;
            lastLife += 5000;
        }
    };
    
    this.refresh = function() { 
        var temp;
        var offset = 0;
        var divisor = 100000;
        
        var x = 7 * 32 + 16 - 9;
        var y = 16;

        ctx.fillRect (x, y, 50, y+font.getFontHeight());
        
        scoreText(ctx, x, y);
        
        y +=  font.getFontHeight();
        
        for(var i=0; i<6; i++)
        {
            temp = Math.floor(score/divisor) % 10;

            offset += font.drawDigit(ctx, temp, x + offset, y);
            divisor /= 10;
        }
        
        offset = 0;
        y = 32 + 16;
        
        
        offset += levelText(ctx, x, y) + 4;
        divisor = 10;
        
        for(var i=0; i<2; i++)
        {
            temp = Math.floor(player.level/divisor) % 10;

            if(i > 0 || player.level > 9) offset += font.drawDigit(ctx, temp, x + offset, y);
            
            divisor /= 10;
        }
    };
    
    this.getScore = function() {
        return score;
    };
}

var menuActions = [
    //New Game
    function() 
    {
        player = {
            x: 8*16,
            y: 10*16,
            width: 16,
            height: 16,
            direction: STOP,
            state: STATES.ALIVE,
            level: 1,
            lives: 2,
            hiscore: player.hiscore,
            intersects: intersects
        };
        
        enemyBullets = [];
        friendlyBullets = [];
        
        statistics.startTime = new Date().getTime();
        statistics.shots = 0;
        statistics.hits = 0;
        
        gameState = GAME_STATES.CONTROLS;
        
        frame = 0;
    },
    //Instructions
    function()
    {
        gameState = GAME_STATES.INSTRUCTIONS;
    },
    //High Scores
    function()
    {
        gameState = GAME_STATES.HIGH_SCORES;
    },
    //Options
    function()
    {
        selectOption = 0;
        player.transition = true;
        gameState = GAME_STATES.OPTIONS;
    },
    //Credits
    function()
    {
        gameState = GAME_STATES.CREDITS;
    },
    //Exit
    function() 
    {
        window.location = "http://www.wiicade.com";
    }
];

function HighScores()
{
    var highscores = [];
    var previousScore;
    var index = -1;
    
    function parseHighScores(array)
    {
        highscores = [];
        
        for(var i=0; i<array.length; i++) 
        {
            if(array[i].owner == userInfo.getUserName()) 
            {
                previousScore = array[i];
            }
            
            highscores[i] = array[i].getStoredObject();
        }
        
        highscores.sort(function(a, b) { return (b.score - a.score); });
        
        if(highscores.length > 100) highscores.length = 100;
    }
    
    Storage.requestPublicItems(parseHighScores, "score");
    
    this.getScores = function()
    {
        return highscores;
    };
    
    this.getMinimumScore = function()
    {
        if(highscores.length >= 100) return highscores[100].score;
        if(previousScore) return previousScore.getStoredObject().score;
        
        return 1000;
    };
    
    this.getPlacement = function(score)
    {
        for(var i=0; i<highscores.length; i++)
        {
            if(score > highscores[i].score) return i+1;
        }

        return highscores.length + 1;
    };
    
    this.insertHighScore = function(score)
    {
        if(previousScore) 
        {
            previousScore.remove();
            previousScore = null;
        }
        
        Storage.insert("score", score, true);
        Storage.requestPublicItems(parseHighScores, "score");
    };
}

