#define ASIO_STANDALONE

#include "session.hpp"
#include "game.hpp"
#include "state/commands.hpp"
#include "util.hpp"

#include <iostream>

void trim(std::string &str)
{
    const std::string ws = " \t\r\n";
    size_t endpos = str.find_last_not_of(ws);
    if (endpos != std::string::npos) {
        str = str.substr(0, endpos+1);
    }

    // trim leading spaces
    size_t startpos = str.find_first_not_of(ws);
    if (startpos != std::string::npos) {
        str = str.substr(startpos);
    }
}

bool Session::parse(std::string s)
{
    // strip leading/trailing whitespace/newlines as they are always unintional
    trim(s);

    std::string token;
    std::string rest;

    util::splitIntoTokenAndRest(s, token, rest);

    //std::cout<<"[session] token='" << token << "' rest='" << rest << "'" << std::endl;

    // TODO:
    // from knoc:
    // ALWAYS use commands here, no direct input!
    // thats important!!!!
    // TODO
    if (s.size()==1&&s[0]=='q'){
        //quit
        m_socket.close();
        m_state->quitPlayer(m_pid);
        return false;

    } else if (s.size()==1&&s[0]=='c') {
        //clear
        m_state->clear(m_pid);

    } else if (s.size()>=3&&s[0]=='n'&&s[1]==' ') {
        //set name
        m_state->setName(m_pid, s.substr(2));

    } else if (s.size()>=3&&s[0]=='v'&&s[1]==' ') {
        //set speed
        double speed = atof(s.substr(2).c_str());
        m_state->setSpeed(m_pid, speed);

    } else if (token == "dev") {
        m_state->commandForPlayer(m_pid, new game::DeveloperCommand(rest));

    } else {
        //shoot
        double angle = atof(s.c_str());
        m_state->commandForPlayer(m_pid, new game::ShootCommand(angle));
    }

    return true;
}

void Session::start()
{
    if(m_started) return;
    m_started=true;
    m_pid = m_state->addPlayer();
    char hello[] = "\nWeclome to KlassischeKeplerKriege v0.1\n Use \"n name\" to change name, \"v velocity\" to change velocity, \"c\" to clear past shots or \"q\" to close the connection.\nEverything else is interpreted as a shooting angle.\n\n> ";
    do_write(hello, strlen(hello));
}

void Session::do_read()
{
    auto self(shared_from_this());
    m_socket.async_read_some(
            asio::buffer(m_rcv_data, max_length),
            [this, self](std::error_code ec, std::size_t length)
            {
                if (!ec) {
                    std::string s(m_rcv_data,length);
                    if(parse(s)){
                        char c[]="> ";
                        do_write(c,strlen(c));
                    }
                }
            });
}

void Session::do_write(char m_snd_data[], std::size_t length)
{
    auto self(shared_from_this());
    asio::async_write(m_socket, asio::buffer(m_snd_data, length),
            [this, self](std::error_code ec, std::size_t /*length*/)
            {
                if (!ec) {
                    do_read();
                }
            });
}
