/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.

* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

#include "engine/cmd.h"
#include "engine/game_env.h"
#include "engine/cmd_receiver.h"

// Derived class. Note that the definition is automatically generated by a python file.
#include "engine/cmd.gen.h"
#include "engine/cmd_specific.gen.h"
#include "cmd_specific.gen.h"


#define _CREATE(...) receiver->SendCmd(CmdIPtr(new CmdCreate(INVALID, __VA_ARGS__)))
#define _CHANGE_RES(...) receiver->SendCmd(CmdIPtr(new CmdChangePlayerResource(INVALID, __VA_ARGS__)))

bool CmdTowerDefenseGameStart::run(GameEnv *env, CmdReceiver *receiver) {
    const PlayerId player_id = 0;
    const PlayerId enemy_id = 1;
    _CREATE(TOWER_BASE, PointF(0, 0), player_id);
    _CREATE(TOWER_BASE, PointF(19, 19), enemy_id);
    _CHANGE_RES(player_id, 100);
    env->GenerateTDMaze();
    return true;
}

bool CmdTowerDefenseWaveStart::run(GameEnv*, CmdReceiver *receiver) {
    const int enemy_id = 1;
    int num_army = _wave;
    auto gen_loc = [&] (int i) -> PointF {
        int x = 15 + i % 5;
        int y = 15 + i / 5;
        return PointF(x, y);
    };
    for (int i = 0; i < num_army; i++) {
        _CREATE(TOWER_ATTACKER, gen_loc(i), enemy_id);
    }
    return true;
}

bool CmdUpgradeTowerAttack::run(GameEnv *env, CmdReceiver *receiver) {
    if (receiver->SendCmd(CmdIPtr(new CmdChangePlayerResource(INVALID, _player_id, -_price)))) {
        Unit* target = env->GetUnit(_target_id);
        if (target == nullptr) return true;
        target->GetProperty()._att += 5;
    }
    return true;
}

bool CmdUpgradeTowerRange::run(GameEnv *env, CmdReceiver *receiver) {
    if (receiver->SendCmd(CmdIPtr(new CmdChangePlayerResource(INVALID, _player_id, -_price)))) {
        Unit* target = env->GetUnit(_target_id);
        if (target == nullptr) return true;
        target->GetProperty()._att_r += 1;
    }
    return true;
}

bool CmdBuildTower::run(const GameEnv&, CmdReceiver *receiver) {
    receiver->SendCmd(CmdIPtr(new CmdChangePlayerResource(INVALID, _player_id, -_price)));
    receiver->SendCmd(CmdIPtr(new CmdCreate(INVALID, TOWER, _p, _player_id, _price)));
    _done = true;
    return true;
}

#undef _CHANGE_RES
#undef _CREATE
