/*
 *   ORXONOX - the hottest 3D action shooter ever to exist
 *                    > www.orxonox.net <
 *
 *
 *   License notice:
 *
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License
 *   as published by the Free Software Foundation; either version 2
 *   of the License, or (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 *   Author:
 *      ...
 *   Co-authors:
 *      ...
 *
 */

/**
    @file TowerDefenseField.cc
    @brief Implementation of the TowerDefenseField class.
*/

#include "TowerDefenseField.h"
#include "core/CoreIncludes.h"
#include "core/XMLPort.h"
#include "TowerDefense.h"

namespace orxonox
{
    RegisterClass(TowerDefenseField);

    /**
    @brief
        Constructor. Registers and initializes the object and checks whether the gametype is actually TowerDefense.
    */
    TowerDefenseField::TowerDefenseField(Context* context) : MovableEntity(context)
    {
        RegisterObject(TowerDefenseField);

        tower_ = nullptr;
        type_ = TowerDefenseFieldType::FREE;
        center_ = nullptr;
        upgrade_ = 0;
        setPosition(0,0,0);                            
        modelGround_ = new Model(getContext());
        modelGround_->setScale(25);
        modelGround_->pitch(Degree(90));
        attach(modelGround_);
        modelObject_ = new Model(getContext());
        modelObject_->setScale(25);
        modelObject_->pitch(Degree(90));
        attach(modelObject_);
        setAngle(0);
    }

    /**
    @brief
        Method to create a TowerDefenseField through XML.
    */
    void TowerDefenseField::XMLPort(Element& xmlelement, XMLPort::Mode mode)
    {
        SUPER(TowerDefenseField, XMLPort, xmlelement, mode);

        //XMLPortParam(TowerDefenseField, "width", setWidth, getWidth, xmlelement, mode);

    }

    void TowerDefenseField::setCenterpoint(TowerDefenseCenterpoint* center)
    {
        center_ = center;
    }

    void TowerDefenseField::upgrade()
    {
        if (canUpgrade() == true)
        {
            destroyTower();
            createTower(getUpgrade() + 1);
        }
    }

    int TowerDefenseField::getUpgrade()
    {
        return upgrade_;
    }

    TowerDefenseFieldType TowerDefenseField::getType()
    {
        return type_;
    }

    void TowerDefenseField::setUpgrade(int upgrade)
    {
        if (upgrade < 0)
        {
            upgrade_ = 0;
        }   
        else if (upgrade > 5)
        {
            upgrade = 5;
        }
        else
        {
            upgrade_ = upgrade;
        }                            
    }

    bool TowerDefenseField::canUpgrade()
    {
        if (tower_ != nullptr && upgrade_ < 5)
        {
            return true;
        }

        return false;
    }

    void TowerDefenseField::setAngle(int newAngle)
    {
        if (modelGround_ != nullptr)
        {
            switch (newAngle)
            {
            case 0:
                modelGround_->yaw(Degree(0));
                angle_ = 0;
                break;
            case 1:
                modelGround_->yaw(Degree(90));
                angle_ = 1;
                break;    
            case 2:
                modelGround_->yaw(Degree(180));
                angle_ = 2;
                break;   
            case 3:
                modelGround_->yaw(Degree(270));
                angle_ = 3;
                break;                                           
            }
        }

        if (modelObject_ != nullptr)
        {
            switch (newAngle)
            {
            case 0:
                modelObject_->yaw(Degree(0));
                angle_ = 0;
                break;
            case 1:
                modelObject_->yaw(Degree(90));
                angle_ = 1;
                break;    
            case 2:
                modelObject_->yaw(Degree(180));
                angle_ = 2;
                break;   
            case 3:
                modelObject_->yaw(Degree(270));
                angle_ = 3;
                break;                                           
            }
        }
        
    }

    int TowerDefenseField::getAngle()
    {
        return angle_;
    }

    void TowerDefenseField::createFree(int orientation)
    {            
        modelGround_->setMeshSource("TD_F1.mesh");
        tower_ = nullptr;
        type_ = TowerDefenseFieldType::FREE;
        setUpgrade(0);
        setAngle(orientation);
    }

    void TowerDefenseField::createStart(int orientation)
    {      
        modelGround_->setMeshSource("TD_S5.mesh");
        tower_ = nullptr;
        type_ = TowerDefenseFieldType::START;
        setUpgrade(0);
        setAngle(orientation);    
    }


    void TowerDefenseField::createEnd(int orientation)
    {     
        modelGround_->setMeshSource("TD_S4.mesh");
        tower_ = nullptr;
        type_ = TowerDefenseFieldType::END;
        setUpgrade(0);
        setAngle(orientation);
    }   

    void TowerDefenseField::createStraight(int orientation)
    {      
        modelGround_->setMeshSource("TD_S1.mesh");
        tower_ = nullptr;
        type_ = TowerDefenseFieldType::STREET;
        setUpgrade(0);
        setAngle(orientation);
    }  

    void TowerDefenseField::createRCurve(int orientation)
    {     
        modelGround_->setMeshSource("TD_S2.mesh");
        tower_ = nullptr;
        type_ = TowerDefenseFieldType::STREET;
        setUpgrade(0);
        setAngle(orientation);
    }  

    void TowerDefenseField::createLCurve(int orientation)
    {    
        modelGround_->setMeshSource("TD_S3.mesh");
        tower_ = nullptr;
        type_ = TowerDefenseFieldType::STREET;
        setUpgrade(0);
        setAngle(orientation);
    } 

    void TowerDefenseField::createObstacle(int orientation)
    {    
        modelGround_->setMeshSource("TD_F1.mesh");
        modelObject_->setMeshSource("TD_O1.mesh");
        tower_ = nullptr;
        type_ = TowerDefenseFieldType::OBSTACLE;
        setUpgrade(0);
        setAngle(orientation);
    }

    void TowerDefenseField::createTower(int upgrade)
    {        
        if (tower_ == nullptr)
        {
            modelGround_->setMeshSource("TD_F1.mesh");
            tower_ = new TowerDefenseTower(center_->getContext());
            attach(tower_);
            type_ = TowerDefenseFieldType::TOWER;
            setUpgrade(upgrade);
            if (upgrade_ > 0 && modelObject_ != nullptr)
            {
                switch (upgrade_)
                {
                    case 1:
                        modelObject_->setMeshSource("TD_T1.mesh");                    
                        tower_->addTemplate(center_->getTower1Template());
                        break;
                    case 2:
                        modelObject_->setMeshSource("TD_T2.mesh");
                        tower_->addTemplate(center_->getTower2Template());
                        break;
                    case 3:
                        modelObject_->setMeshSource("TD_T3.mesh");
                        tower_->addTemplate(center_->getTower3Template());
                        break;
                    case 4:
                        modelObject_->setMeshSource("TD_T4.mesh");
                        tower_->addTemplate(center_->getTower4Template());
                        break;
                    case 5:
                        modelObject_->setMeshSource("TD_T5.mesh");
                        tower_->addTemplate(center_->getTower5Template());
                        break;
                }
            }
        }                           
    }

    void TowerDefenseField::destroyTower()
    {
        if (tower_ != nullptr)
        {
            tower_->destroy();
            tower_ = nullptr;
        }
    }

    void TowerDefenseField::create(char object, char param)
    {
        int paramInt = atoi(&param);
        switch (object)
        {
            case 'F':
                createFree(paramInt);
                break;
            case 'I':                
                createStraight(paramInt);
                break;
            case 'R':                
                createRCurve(paramInt);
                break;  
            case 'L':               
                createLCurve(paramInt);
                break;
            case 'X':               
                createStart(paramInt);
                break;     
            case 'O':               
                createEnd(paramInt);
                break;
            case 'Y':               
                createObstacle(paramInt);
                break;                 
            case 'T':                               
                createTower(paramInt);               
                break;                                                                                                         
        }
    }
}
