#include "towers.h"

#include <cmath>

Towers::Towers(Game_Data *gd, QObject *parent) :
    QObject(parent)
{
    gameData = gd;
}

bool Towers::addTower(int playerId, int srcId, QPoint pos)
{
    if (playerId < 0 || playerId >= gameData->players.size())
    {
        qCritical("ERROR out of players range");
        return false;
    }
    Player * p = gameData->players.at(playerId);
    if (srcId < 0 || srcId >= p->srcTowers.size())
    {
        qCritical("ERROR out of towers range");
        return false;
    }
    if (p->money < p->srcTowers.at(srcId).cost)
    {
        qDebug() << "not enought money!";
        return false;
    }
    QRect alrec(pos,QSize(2,2));
    for (QHash<int, AlienType>::iterator i = gameData->aliens->curAliens.begin(); i != gameData->aliens->curAliens.end(); ++i)
        if (alrec.contains(i->pos.toPoint())) return false;
    TowerType tw;
    tw.src = &(p->srcTowers[srcId]);
    tw.PlayerId = playerId;
    tw.angle = 0;
    tw.build = 0;
    tw.reload = 0;
    tw.aim = -1;
    tw.experience = 0;
    tw.isBilding = true;
    if (gameData->map->addTowerOnMap(playerId,pos))
    {
        tw.pos = pos;
        tw.item = new ADItem(tw.pos,tw.src->image,QRectF(-cellSize,-cellSize,cellSize*2,cellSize*2));
        tw.item->setPos(tw.pos * cellSize);
        tw.item->setRotation(tw.angle);
        tw.item->setOpacity(0.5);
        scene->addItem(tw.item);
        gameData->curTowers.insert(tw.pos,tw);
        p->money -= tw.src->cost;
        p->stats.spend_money += tw.src->cost;
        p->stats.builded_towers++;
        return true;
    }
    return false;
}


void Towers::delTower(QPoint pos)
{
//    qDebug("del tower start");
//    QPoint p;
//    if (gameData->curTowers.contains(pos)) p = pos;
//    if (gameData->curTowers.contains(pos+QPoint(1,0))) p = pos+QPoint(1,0);
//    if (gameData->curTowers.contains(pos+QPoint(1,1))) p = pos+QPoint(1,1);
//    if (gameData->curTowers.contains(pos+QPoint(0,1))) p = pos+QPoint(0,1);
    if (gameData->curTowers.contains(pos))
    {
//        qDebug()<< "del tower contain" << pos;
//        emit tower_killed(pos);
        TowerType * t = &(gameData->curTowers[pos]);
        gameData->map->delTowerOnMap(t->PlayerId,pos);
        gameData->players[t->PlayerId]->money += t->src->cost/2;
        scene->removeItem(t->item);
        delete t->item;
        gameData->curTowers.remove(pos);
    }
//    qDebug("del tower end");
}


void Towers::update()
{
    for (QHash<QPoint, TowerType>::iterator i = gameData->curTowers.begin(); i != gameData->curTowers.end(); ++i)
    {
        if (i->isBilding)
        {
            if (i->build < i->src->buildTime)
            {
                i->build++;
                i->item->setBarValue((float)(i->build)/i->src->buildTime);
            } else {
                i->isBilding = false;
                i->item->hideBar();
                i->item->setOpacity(1.0);
            }
        } else {
            float rad = i->src->radius;
            float rad2 = rad*rad;
            if (!(gameData->aliens->curAliens.contains(i->aim)))
                i->aim = -1;
            else
            {
                if (distance2(i->pos,gameData->aliens->curAliens.value(i->aim).pos+QPointF(0.5f,0.5f)) > rad2)
                    i->aim = -1;
            }
            if (gameData->players.at(i->PlayerId)->selectAlienId > 0)
            {
                AlienType al = gameData->aliens->curAliens.value(gameData->players.at(i->PlayerId)->selectAlienId);
                if (distance2(al.pos+QPointF(0.5f,0.5f), i->pos) < rad2) i->aim = al.id;
                else i->aim = -1;
            }
            if (i->aim == 0)
            {
                qDebug() << tr("err tower") << i->pos << gameData->players.at(i->PlayerId)->selectAlienId;
                qFatal("tower has incorrect aim = 0");
                return;
            }
            if (i->aim < 0)
            {
                for (QHash<int, AlienType>::iterator j = gameData->aliens->curAliens.begin(); j != gameData->aliens->curAliens.end(); ++j)
                {
                    float dist = distance2(i->pos, j->pos+QPointF(0.5f,0.5f));
                    if (dist < rad2) i->aim = j->id;
                }
            }
            if (i->aim > 0)
            {
                float arctg = std::atan2(i->pos.x() - gameData->aliens->curAliens[i->aim].pos.x() - 0.5f, i->pos.y() - gameData->aliens->curAliens[i->aim].pos.y() - 0.5f);
                i->angle = 180.0f*(-arctg)/M_PI;
                i->item->setRotation(i->angle);
            }
            /// TODO: smooth rotate tower to aim
            if (i->reload < i->src->reload)
                i->reload++;
            else
            {
                if (i->aim > 0)
                {
                    i->reload = 0;
                    i->experience += i->src->expByShot;
                    emit shot((*i));
                }
            }
        }
    }
}


bool Towers::morphTower(QPoint id, int index)
{
    if (!canMorph(id, index)) return false;
//    tower_killed(id);
    TowerType & t(gameData->curTowers[id]);
    gameData->players[t.PlayerId]->money -= t.src->morphs[index].cost;
    gameData->players[t.PlayerId]->stats.spend_money += t.src->morphs[index].cost;
    t.src = t.src->morphs[index].morph;
    t.build = 0;
    t.reload = 0;
    t.isBilding = true;
    scene->removeItem(t.item);
    //delete t.item;
    t.item = new ADItem(t.pos,t.src->image,QRectF(-cellSize,-cellSize,cellSize*2,cellSize*2));
    t.item->setPos(t.pos * cellSize);
    t.item->setRotation(t.angle);
    t.item->setOpacity(0.5);
    scene->addItem(t.item);
    return true;
}

