#define ASIO_STANDALONE

#include <iostream>
#include <getopt.h>
#include <asio.hpp>
#include <cstdlib>

#include "opengl.hpp"
#include "game_window.hpp"
#include "network/server.hpp"
#include "options.hpp"

#include "sound/sound.hpp"
#include "sound/sound_effects.hpp"

#include "state/state_update_event.hpp"

#include <sys/time.h>

uint64_t optionsFlags;

using asio::ip::tcp;

int main(int argc, char *argv[])
{
    bool devMode = false;
    bool soundEnabled = false;
    char port[]="3490";

    static struct option long_options[] =
        {
          /* These options set a flag. */
//        {"verbose", no_argument,       &verbose_flag, 1},
//        {"brief",   no_argument,       &verbose_flag, 0},
          /* These options don’t set a flag.
             We distinguish them by their indices. */
//        {"add",     no_argument,       0, 'a'},
//        {"append",  no_argument,       0, 'b'},
//        {"delete",  required_argument, 0, 'd'},
          {"autorun", required_argument, 0, 'a'},
          {"port",    required_argument, 0, 'p'},
          {"sound",   no_argument,       0, 's'},
          {"fps",     no_argument,       0, 'f'},
          {"dev",     no_argument,       0, 'd'},
          {0, 0, 0, 0}
        };

    int option_index = 0;

    while(1){
        char c = getopt_long (argc, argv, "p:fads",
                       long_options, &option_index);
        if (c == -1)
            break;

        switch (c)
        {
            case 'f':
                SET_FLAG(SHOW_FPS,true);
                break;

            case 'd':
                std::cout<<"enabling developer mode" << std::endl;
                devMode = true;
                break;

            case 'p':
                strcpy(port,optarg);
                break;

            case 's':
                soundEnabled = true;
                break;

            case 'a':
                SET_FLAG(TEST_AUTORUN, true);
                break;

            case '?':
                /* getopt_long already printed an error message. */
                break;

            default:
                abort();
        }
    }

    srand(time(NULL));

    sound::SoundEffects *sounds = nullptr;
    if (soundEnabled) {
        if (sound::initSound()) {
            sounds = new sound::SoundEffects();
        }
    }

    Game game;
    game.state()->setDeveloperMode(devMode);

    asio::io_service io_service;
    Server s(io_service, game.state(), atoi(port) );

    //GameWindow window(500, 500, &game);
    GameWindow window(500, 500, &game);
    window.set_maxfps(60.0);
    window.open();

    while(window.running()){
        window.poll();
        io_service.poll();

        //size_t numEvents = game.state()->currentStateUpdateEvents().size();
        //if (numEvents != 0) {
        //    std::cout<<"game state update events: " << numEvents << std::endl;
        //    for (game::StateUpdateEvent *evt : game.state()->currentStateUpdateEvents()) {
        //        std::cout<< evt->description() << std::endl;
        //    }
        //}

        if (sounds != nullptr) {
            // TODO: get time diff too
            sounds->advance(1/50.0f, game.state()->currentStateUpdateEvents());
            // TODO: use flag to now when to do this.
            sound::deleteOldSounds();
        }

        game.state()->applyAndClearAllOldStateUpdates();
    }

    return 0;
}
