function start_game(is_server, game_id, on_fail)
{
    console.log("Game started");
    console.log("Is server? = " + is_server)
    var failed_to_join = false
    var fail_callback = on_fail

    var canvas = document.getElementById("screen");

    var ctx = canvas.getContext("2d");

    var camera_x = 0
    var camera_y = 0

    var client_id = 0

    var images = {}

    var background_img = load_image("Graphics/background_1.png")

    function get_animation_frame(obj) {
        var img = images[obj.img];
        var w = Math.floor(img.image.width / img.frames);
        var h = img.image.height;
        var fps = img.fps;
        var time = Date.now() - obj.whenCreated;
        var frame = Math.floor((time * fps) / 1000.0);
        if (frame >= img.frames)
        {
            if (img.loop)
                frame %= img.frames;
            else
                frame = img.frames - 1;
        }
        return {'img': img.image, 'x': frame * w, 'y': 0, 'w': w, 'h': h};
    }

    function draw_object(ob) {
        ctx.save();
        ctx.translate(ob['x'], ob['y'])
        if (ob['f'] == 'true') {
            ctx.scale(-1.0, 1.0)
        }
        ctx.rotate(-ob['a'])
        var frame = get_animation_frame(ob)
        ctx.drawImage(frame.img, frame.x, frame.y, frame.w, frame.h, -(frame.w / 2), -(frame.h / 2), frame.w, frame.h);
        ctx.restore();
    }

    function draw_objects() {
        ctx.save()
        ctx.translate(
            -camera_x + (canvas.width/2),
            -camera_y + (canvas.height/2)
        );
        for (var id in obs) {
            draw_object(obs[id])
        }
        ctx.restore()
    }

    function load_image(filename) {
        var image = new Image();
        image.src = filename;
        return image;
    }

    function create_image(filename, frames, fps, loop)
    {
        return {
            'image': load_image(filename),
            'frames': frames,
            'fps': fps,
            'loop': loop
        };
    }

    function create_object(img_id, x, y, a, f, frames, fps) {
        return { 'img' : img_id , 'x' : x, 'y' : y, 'a' : a, 'f' : f, 'frames': frames, 'fps': fps, 'whenCreated': Date.now() };
    }

    var ws = new WebSocket("ws://" + location.host + "/game");
    function safeSend(msg) {
        if (ws.readyState == 1) {
            console.log("SEND: " + msg)
            ws.send(msg)
        }
    }

    window.onresize = function(event) {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        safeSend("viewport:"+canvas.width+":"+canvas.height)
    }

    function on_input(down) {
        var map = {}
        map["1"] = "right"
        map["2"] = "jump"
        map["3"] = "dig"
        map["4"] = "left"
        map["5"] = "shootFireball"
        map["6"] = "setBomb"

        var client_control = client_id % 7;
        console.log("client_id = " + client_id)
        console.log("map = " + map[client_control])

        if (down) {
            safeSend("inputdown:" + map[client_control])
        } else {
            safeSend("inputup:" + map[client_control])
        }
    }

    function playTheme()
    {
        theme = new Audio('oxenmoron_theme.mp3'); 
        theme.addEventListener('ended', function() {
            this.currentTime = 0;
            this.play();
        }, false);
        theme.play();
    }

    ws.onopen = function(event) {
        console.log("onconnect");
        if (is_server) {
            console.log("requesting a new game");
            ws.send("gameplz")
        } else {
            console.log("attempting to join game " + game_id)
            ws.send("joinplz:" + game_id)
        }

        window.onresize();
    }
    ws.onmessage = function(event) {
        // console.log("Data: " + event.data);
        var m = event.data.split(':');
        cmd = m[0]
        if (cmd == "register") {
            images[m[1]] = create_image(m[2], Number(m[3]), Number(m[4]), Number(m[5]))
        } else if (cmd == "create") {
            obs[m[1]] = create_object(
                m[2], // img_id
                m[3], // x
                m[4], // y
                m[5], // a
                m[6], // f
                m[7], // frames
                m[8]  // fps
            )
        } else if (cmd == "update") {
            obs[m[1]]['x'] = m[2]
            obs[m[1]]['y'] = m[3]
            obs[m[1]]['a'] = m[4]
            obs[m[1]]['f'] = m[5]
        } else if (cmd == "sprite") {
            obs[m[1]].img = m[2]
        } else if (cmd == "delete") {
            delete obs[m[1]];
        } else if (cmd == "camera") {
            camera_x = m[1]
            camera_y = m[2]
        } else if (cmd == "created") {
            game_id = m[1]

            playTheme();

            console.log("server created game id : " + game_id)
        } else if (cmd == "failed") {
            console.log("Failed to join game id : " + game_id)
            fail_callback()
        } else if (cmd == "joined") {
            client_id = m[1]
            playTheme();
            console.log("Joined game with gamd id : " + game_id)
        } else if (cmd == "draw") {
            draw();
        } else {
            console.log("Unknown cmd: " + cmd)
        }
    }

    var obs = {}


    function draw() {
        ctx.rect(0, 0, canvas.width, canvas.height);
        ctx.drawImage(background_img, 0, 0, canvas.width, canvas.height);

        var count = Object.keys(obs).length

        ctx.fillStyle = "#000000";
        ctx.fillText(
            "GameID:" + game_id +
            "  Object count: " + count, 10, 10);

        draw_objects()
    }

    return {'inputCallback': on_input, '_debugSend': safeSend};
}
