/*

--------
|SKRUZD|
--------

The MIT License

Copyright (c) 2006 Inko Illarramendi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <crystalspace.h>

#include <physicallayer/entity.h>
#include <physicallayer/propclas.h>
#include <propclass/linmove.h>
#include <propclass/prop.h>
#include <propclass/trigger.h>
#include <propclass/region.h>

#include <propclass/tooltip.h>
#include <propclass/timer.h>
#include <propclass/move.h>
#include <propclass/input.h>
#include <propclass/solid.h>
#include <propclass/colldet.h>

#include "behave.h"
#include "bbad.h"


BehaviourBad::BehaviourBad (iCelEntity* entity, BehaviourLayer* bl, iCelPlLayer* pl)
        : BehaviourCommon (entity, bl, pl, app)
{

    id_pctimer_wakeup = pl->FetchStringID ("pctimer_wakeup");

}

bool BehaviourBad::SendMessage (csStringID msg_id,
                                iCelPropertyClass* pc,
                                celData& ret, iCelParameterBlock* params, va_list arg)
{

    csRef<iCelEntity> bad_entity;
    bad_entity = pc-> GetEntity();

    csRef<iPcTimer> pctimer = CEL_QUERY_PROPCLASS_ENT (
                                  bad_entity, iPcTimer);


    if (msg_id == id_pctimer_wakeup)
    {
        /**
        ENEMIES A.I.:
        1.- DECIDE WHAT TO DO DEPENDING ON THE STATE:
            a) normal: CALCULATE NEW ROTATION OF THE ENEMY TO FOLLOW CHARACTER
            b) preparing to shoot: AIM AND SHOOT
        2.-DECIDE IF ENEMY IS GOING TO PREPARE TO SHOOT
        */

        //BEGINING OF TRIGONOMETRICAL OPERATIONS TO SET ENEMIES NEW HEADING
        iCelEntity* player_entity = pl->FindEntity ("player");
        csRef<iPcLinearMovement> player_pclinmove = CEL_QUERY_PROPCLASS_ENT (
                    player_entity, iPcLinearMovement);

        csVector3 player_pos;
        iSector* player_sector;
        float player_yrot;
        player_pclinmove -> GetLastFullPosition (player_pos, player_yrot, player_sector);

        float player_x = player_pos.operator[] (0);//0=x 1=y 2=z;; We want X & Z
        float player_z = player_pos.operator[] (2);


        csRef<iPcLinearMovement> bad_pclinmove = CEL_QUERY_PROPCLASS_ENT (
                    bad_entity, iPcLinearMovement);

        csVector3 bad_pos;
        iSector* bad_sector;
        float bad_yrot;
        bad_pclinmove -> GetLastFullPosition (bad_pos, bad_yrot, bad_sector);

        float bad_x = bad_pos.operator[] (0);//0=x 1=y 2=z;; We want X & Z
        float bad_z = bad_pos.operator[] (2);

        float dif_x = player_x - bad_x;
        float dif_z = player_z - bad_z;
        float hyp = hypot(dif_x, dif_z);
        float cosv = dif_z/hyp;
        float angle0 = acos(dif_z/hyp);
        float dif_rot;
        float vel=-10;
        float newangle;

        if (dif_x < 0) //LEFT CUADRANTS
        {
            angle0= 2*acos(0) - angle0;
            dif_rot= angle0 - bad_yrot;
        }
        else //RIGHT CUADRANTS
        {
            angle0=2*acos(0)-angle0;
            angle0=4*acos(0)-angle0;
            dif_rot= angle0 - bad_yrot;
        }
        // to calculate the direction of the rotation
        if (fabs(dif_rot) > 2*acos(0))
            vel=vel*(-1);
        if (dif_rot < 0)
            vel=vel*(-1);

        // Set the rotation speed and the goal angle.
        bad_pclinmove-> SetAngularVelocity (csVector3(0,vel,0),csVector3(0, angle0,0));

        csRef<iPcActorMove> pcactormove = CEL_QUERY_PROPCLASS_ENT (
                                              bad_entity, iPcActorMove);

        if (!pcactormove-> IsMovingForward())
        {//MEANS THAT IS NOT MOVING FORWARD, SO IS PREPARING TO SHOOT
            //THEREFORE, IT WILL SHOOT

            //---------------CREATE THE SHOOT---------------------
            csRef<iPcMesh> bad_pcmesh = CEL_QUERY_PROPCLASS_ENT (
                                            bad_entity, iPcMesh);

            if (bad_pcmesh-> IsVisible())
            {
                csRef<iCelEntity> shoot_entity;
                //Shoot entity will be an invisible entity, only to calculate
                //in more precise way if the shoot is hitting the player
                shoot_entity = pl->CreateEntity ("shoot",  bl, "shoot_behave",
                                                 "pcmesh",
                                                 "pclinearmovement",
                                                 "pctimer",//To destroy the shoot
                                                 0);
                if (!shoot_entity)
                    printf("Error creating collider entity!");

                csRef<iPcMesh> pcmeshcol = CEL_QUERY_PROPCLASS_ENT (
                                               shoot_entity, iPcMesh);
                pcmeshcol -> CreateEmptyThing ();
                if (!pcmeshcol->GetMesh ())
                    printf("Error loading model!");

                csRef<iPcLinearMovement> pclinmovcol = CEL_QUERY_PROPCLASS_ENT (
                                                           shoot_entity, iPcLinearMovement);

                //TRIGONOMETRICAL OPERATIONS TO GET THE HEADING OF THE SHOOT
                csVector3 shoot_pos;
                float shootx= bad_pos.operator[] (0);
                float shooty=bad_pos.operator[] (1);
                shooty= shooty + 0.5;
                float shootz =  bad_pos.operator[] (2);
                shoot_pos = csVector3(shootx,
                                      shooty,
                                      shootz);
                pclinmovcol -> SetFullPosition (shoot_pos, angle0, bad_sector);

                csRef<iPcTimer> pctimershoot = CEL_QUERY_PROPCLASS_ENT (
                                                   shoot_entity, iPcTimer);
                pctimershoot-> WakeUp(5000, true);

                float bad_y = bad_pos.operator[] (1);
                float player_y = player_pos.operator[] (1);

                float dif_y = player_y - bad_y +0.3; //+0.3 is to shot to the body, not to the feets.
                float hyplast= -hypot(hyp, dif_y);
                float velshot=10; /// rotar

                pclinmovcol -> SetVelocity(csVector3(0,dif_y*velshot/hyplast*(-1),hyp*velshot/hyplast)); //to throw at velocity 10

                //------------------CREATE THE ENEMIES SHOOT (ACID) PARTICLE-----------------------
                csRef<iCelEntity> acid_entity;
                //Acid is an entity following the entity shoot. It is the visual
                //representation of the shoot.
                acid_entity = pl->CreateEntity ("acid",  bl, "shoot_behave",
                                                "pcmesh",
                                                "pclinearmovement",
                                                "pctimer",//to destroy the acid
                                                0);
                if (!acid_entity)
                    printf("Error creating acid entity!");

                // Get the iPcMesh interface
                csRef<iPcMesh> pcmeshacid = CEL_QUERY_PROPCLASS_ENT (
                                                acid_entity, iPcMesh);
                pcmeshacid->SetPath ("/this/model");
                pcmeshacid->SetMesh ("partAcid", "acid");

                if (!pcmeshacid->GetMesh ())
                    printf("Error loading model!");

                csRef<iPcLinearMovement> pclinmovacid = CEL_QUERY_PROPCLASS_ENT (
                                                            acid_entity, iPcLinearMovement);
                pclinmovacid -> SetFullPosition (shoot_pos, angle0, bad_sector);
                pclinmovacid -> SetAnchor (pcmeshcol); //tell the acid to follow the shoot

                csRef<iPcTimer> pctimeracid = CEL_QUERY_PROPCLASS_ENT (
                                                  acid_entity, iPcTimer);
                pctimeracid-> WakeUp(5000, true);

                //------------------END CREATE ACID--------------------------

                //Set the enemy moving, so it is not longer preparing to shoot
                pcactormove-> Forward(true);
                bad_pclinmove-> SetAngularVelocity (csVector3(0,vel,0),csVector3(0, angle0,0));
                pctimer-> WakeUp(500, true); //the timer is set for walk

                //-----------------END OF SHOOT-----------------------------------

            }
        }

        //--------------------DECIDE TO SHOOT WITH RANDOM NUMBERS-------------
        int shootyesno = (rand() % 20) + 1; //1 time each 20 will shoot
        if (shootyesno==1)
        {//Start preparing the shoot stoping the movement of the enemy
            pcactormove-> Forward(false);

            csRef<iPcMesh> bad_pcmesh = CEL_QUERY_PROPCLASS_ENT (
                                            bad_entity, iPcMesh);
            //Load "preparing to shoot" animation
            csRef<iMeshFactoryWrapper> imeshfact;
            csRef<iMeshWrapper> imesh;
            imesh = bad_pcmesh -> GetMesh ();
            imeshfact = imesh-> GetFactory ();
            // Load and start the animation
            csRef<iSpriteCal3DFactoryState> factstate(
                scfQueryInterface<iSpriteCal3DFactoryState> (
                    imeshfact->GetMeshObjectFactory()));
            csRef<iSpriteCal3DState> cal3dstate(scfQueryInterface<iSpriteCal3DState> (
                                                    imesh->GetMeshObject()));
            cal3dstate->SetAnimCycle("shoot", 1.0f);

            //set the timer it will be preparing to shoot
            pctimer-> WakeUp(1000, true);

        }
        else
        {
            pcactormove-> Forward(true);
            bad_pclinmove-> SetAngularVelocity (csVector3(0,vel,0),csVector3(0, angle0,0));
        }
        return true;

    }

    return BehaviourCommon::SendMessage (msg_id, pc, ret, params, arg);
}
