class Game {

    data: {[key: string]: any};
    mainFont: PH.CanvasFont;
    titleFont: PH.CanvasFont;
    ctx: CanvasRenderingContext2D;

    soundPlayer: PH.SoundPlayer;
    jukeBox: PH.JukeBox;

    layerManager = new PH.LayerManager();
    newHighScore = false;

    constructor(data: {[key: string]: any}, audioContext: AudioContext, mainFont: PH.CanvasFont, ctx: CanvasRenderingContext2D) {
        this.data = data;
        this.soundPlayer = new PH.SoundPlayer(audioContext, {});
        this.soundPlayer.fader!.gainNode.gain.value = 0.3;
        this.jukeBox = new PH.JukeBox(this.soundPlayer);
        this.mainFont = mainFont;
        this.titleFont = mainFont;
        this.ctx = ctx;

        this.layerManager.setupMouseListeners(this.ctx.canvas);
        this.layerManager.setupKeyboardListeners(window);

        this.layerManager.setMainLayers(new MenuLayer(this));

        // Start animation frames.
        let fm = new PH.FrameManager({
            frameCallback: (deltat) => this.frame(deltat)
        });
        fm.start();
    }

    getDims() {
        let canv = this.ctx.canvas;
        let w = canv.width;
        let h = canv.height;
        let cx = w / 2;
        let cy = h / 2;
        let scale = Math.min(w / 10, h / 12);
        let titley = cy - scale * 4.5;
        let instructiony = cy + scale * 4.5
        return { cx: cx, cy: cy, scale: scale, titley: titley, instructiony: instructiony };
    }

    frame(deltat: number) {
        // Update step.
        this.layerManager.update(deltat);

        let dims = this.getDims();
        this.mainFont = new PH.SimpleFont("novamono", dims.scale * 0.35, 1, '#fff');
        this.titleFont = new PH.SimpleFont("novamono", dims.scale * 2, 1, '#fff');

        // Graphics step.
        PH.resizeCanvasToSizeOnScreen(this.ctx.canvas);
        PH.fillCanvas(this.ctx, "#000");
        this.layerManager.draw();
    }

    endMenu() {
        this.startGameplay();
    }

    startGameplay() {
        this.layerManager.setMainLayers(new GameLayer(this));
    }

    getBestScore() {
        if(PH.localStorageIsSaved("bestScore")) {
            return PH.localStorageLoad("bestScore");
        }
        else {
            return 0;
        }
    }

    endGameplay(score: number) {
        let bestScore = this.getBestScore();
        this.newHighScore = (score > bestScore);
        if(this.newHighScore) {
            PH.localStorageSave("bestScore", score);
        }
        this.layerManager.setMainLayers(new MenuLayer(this));
    }

}

async function start() {
    window.onerror = null;

    let outGameCanvas = <HTMLCanvasElement>document.getElementById('outGameCanvas')!;
    outGameCanvas.hidden = false;
    let audioContext = new AudioContext();
    let loader = new PH.Loader(audioContext);

    let ctx = outGameCanvas.getContext('2d')!;
    
    // Load a font
    await PH.quickFont("novamono", "NovaMono-Regular.ttf");
    let mainFont = new PH.SimpleFont("novamono", 16, 1.0, "#fff");

    // Set up loading sceen
    let loadingScreen = new LoadingScreen(ctx);

    // Start animation frames for while the game is loading.
    let fm = new PH.FrameManager({
        frameCallback: (deltat) => {
            PH.resizeCanvasToSizeOnScreen(ctx.canvas);
            PH.fillCanvas(ctx, "#000");
            loadingScreen.draw();
        }
    });
    fm.start();

    // Load the main contents of the game.
    let data = await loader.getFile('game.dat', (bytes, totalBytes) => loadingScreen.setProgress(bytes, totalBytes));

    fm.stop();
    new Game(data, audioContext, mainFont, ctx);
}

window.onload = start;
