#include "graphics.hpp"
#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <vector>
#include <time.h>

using namespace genv;
using namespace std;

const unsigned int X = 500;
const unsigned int Y = 500;

const float vFarkas = 3;
const float vBarany = 3.2;

// ----------------- Vektor struct -----------------------
struct vektor
{
    float x, y;
    void random()
    {
        x = floor(rand() % X);
        y = floor(rand() % Y);
    }
    float hosszNegyzet()
    {
        return x*x + y*y;
    }
    float hossz()
    {
        return sqrt(x*x + y*y);
    }
    vektor& operator+= (const vektor& v)
    {
        this->x = this->x + v.x;
        this->y = this->y + v.y;
        return *this;
    }
};

vektor operator+ (const vektor& v1, const vektor& v2)
{
    vektor temp;
    temp.x = v1.x + v2.x;
    temp.y = v1.y + v2.y;
    return temp;
}

vektor operator- (const vektor& v1, const vektor& v2)
{
    vektor temp;
    temp.x = v1.x - v2.x;
    temp.y = v1.y - v2.y;
    return temp;
}

vektor operator* (const float skalar, const vektor& v)
{
    vektor temp;
    temp.x = skalar * v.x ;
    temp.y = skalar * v.y;
    return temp;
}

vektor operator* (const vektor& v, const float skalar)
{
    vektor temp;
    temp.x = skalar * v.x ;
    temp.y = skalar * v.y;
    return temp;
}

vektor operator/ (const vektor& v, const float skalar)
{
    vektor temp;
    temp.x = v.x / skalar;
    temp.y = v.y / skalar;
    return temp;
}


// --------------------- Állatok -----------------------
//******************************************************

// Bárány ------------------------
struct barany
{
private:
    vektor hely;
public:
    bool el_e;
    void rajzol()
    {
        gout << move_to(hely.x, hely.y) << color (255,255,255) << box(5,5);
    }
    barany()
    {
        el_e = true;
        hely.random();
        rajzol();
    }
    vektor tavolsag(vektor honnan)
    {
        return hely - honnan;
    }
    void meghal()
    {
        el_e = false;
    }
    void menekul();
};

// Farkas -------------------------
struct farkas
{
private:
    vektor hely;
public:
    void rajzol()
    {
        gout << move_to(hely.x, hely.y) << color (255,50,50) << box(5,5);
    }
    farkas()
    {
        hely.random();
        rajzol();
    }
    vektor tavolsag(vektor honnan)
    {
        return honnan - hely;
    }
    void uldoz ();
};

// Globális változók ---------------------
vector <barany> baranyok;
vector <farkas> farkasok;

// Tagfüggvények függvényteste -----------
// Farkas üldöz ---------
void farkas::uldoz ()
{
    static vektor emozg;  // Farkas lendülete (előző mozgásvektora

    // Legközelebbi bárány kiszemelése
    float minTav = 9999999; // "Végtelen" távolság
    barany *mit;
    for (int unsigned i = 0; i < baranyok.size(); i++)
    {
        if (baranyok[i].el_e)
        {
            vektor tavV = baranyok[i].tavolsag(hely);
            float tav = tavV.hosszNegyzet();
            if (tav < minTav)
            {
                mit = &baranyok[i];
                minTav = tav;
            }
        }
    }

    // Legközelebbi bárány fele mozog
    vektor mozg = mit->tavolsag(hely);
    hely += mozg / mozg.hossz() * vFarkas + emozg;
    emozg = mozg / mozg.hossz() * 2;  // a farkasok lomhábbak, mert lendületvektoruk kétszeresét adja hozzá

    // Ha beérte, akkor megeszi
    if (mozg.hossz() < vFarkas) mit->meghal();

    // Visszahozza, ha túlmegy a szélén
    if (hely.x < 0) hely.x = 0;
    else if (hely.x > X) hely.x = X;
    if (hely.y < 0) hely.y = 0;
    else if (hely.y > Y) hely.y = Y;

    rajzol();
}

// Barány menekül ---------
void barany::menekul()
{
    static vektor emozg;
    // Legközelebbi farkas keresése
    float minTav = 9999999; // "Végtelen" távolság
    farkas *mitol;
    for (int unsigned i = 0; i < farkasok.size(); i++)
    {
        vektor tavV = farkasok[i].tavolsag(hely);
        float tav = tavV.hosszNegyzet();
        if (tav < minTav)
        {
            mitol = &farkasok[i];
            minTav = tav;
        }
    }
    // Legközelebbi farkastól elfele mozog
    vektor mozg = mitol->tavolsag(hely);
    hely += mozg  / mozg.hossz() * vBarany + emozg;
    emozg = mozg / mozg.hossz() / 2; // a baranyok mozgékonyabbak, mert lendületvektor felét adja hozzá

    // Ha túlmegy, átugrik a rajzvászon túloldalára
    if (hely.x < 0) hely.x += X;
    else if (hely.x > X) hely.x -= X;
    if (hely.y < 0) hely.y += Y;
    else if (hely.y > Y) hely.y -= Y;
    rajzol();
}


// ---------------------- Main --------------------------
// ******************************************************
int main()
{
    /* initialize random seed: */
    srand (time(NULL));

    gout.open(X,Y);

    // Nyáj és horda feltöltése állatokkal
    for (int i = 1; i < 50; i++)
    {
        barany b;
        baranyok.push_back(b);
    }
    for (int i = 1; i < 20; i++)
    {
        farkas f;
        farkasok.push_back(f);
    }
    gout << refresh;

    // Akció
    event ev;
    gin.timer(40);
    while(gin >> ev)
    {
        if (ev.type == ev_timer)
        {
            gout << color(0,0,0) << move_to(0,0) << box(X,Y);
            for (unsigned int i = 0; i < farkasok.size(); i++)
            {
                farkasok[i].uldoz();
            }
            bool elfogytak = true;
            for (unsigned int i = 0; i < baranyok.size(); i++)
            {
                if (baranyok[i].el_e)
                {
                    elfogytak = false;
                    baranyok[i].menekul();
                }
            }
            if (elfogytak) break;
            gout << refresh;
        }
    }
    cout << "\n      Elfogytak a baranyok!\n";
    return 0;
}
