<?php
    /**
     * Unit entity file.
     *
     * Creates the entity and makes it available.
     *
     * @category Entity
     */

    /**
     * Require dependent entities if not present.
     */
    require_once(PATH::ENTITY . "Entity.php");
    require_once(PATH::ENTITY . "K_Unit.php");
    require_once(PATH::ENTITY . "Team.php");
    require_once(PATH::ENTITY . "Rune.php");
    require_once(PATH::ENTITY . "Building.php");

    /**
     * A Unit.
     *
     * Represents an object from the table 'unit'.
     *
     * @category Entity
     */
    class Unit extends Entity{

        /**
         * @var int User ID.
         */
        public $uid;

        /**
         * @var int Unit ID.
         */
        public $id;

        /**
         * @var Building Building the unit is on.
         */
        public $building;

        /**
         * @var K_Unit Base unit.
         */
        public $unit;

        /**
         * @var int Unit stars.
         */
        public $stars;

        /**
         * @var int Unit level.
         */
        public $level;

        /**
         * @var int Unit base HP stat.
         */
        public $hp;

        /**
         * @var int Unit base ATK stat.
         */
        public $attack;

        /**
         * @var int Unit base DEF stat.
         */
        public $defense;

        /**
         * @var int Unit base SPD stat.
         */
        public $speed;

        /**
         * @var int Unit base CRR stat.
         */
        public $crit_rate;

        /**
         * @var int Unit base CRD stat.
         */
        public $crit_damage;

        /**
         * @var int Unit base RES stat.
         */
        public $resistance;

        /**
         * @var int Unit base ACC stat.
         */
        public $accuracy;

        /**
         * @var int Total gained experience.
         */
        public $experience;

        /**
         * @var int Total gained experience in its current level.
         */
        public $exp_gained;

        /**
         * @var int Experience / hour in the current building.
         */
        public $exp_gain_rate;

        /**
         * @var int Equipped transmogification.
         */
        public $costume;

        /**
         * @var K_Source Source the unit was aquired from.
         */
        public $source;

        /**
         * @var Datetime  Time the unit was obtained.
         */
        public $create_time;

        /**
         * @var string Indicates the Homunculus name
         */
        public $homunculus_name;

        /**
         * @var bool Indicates if the monster is locked.
         */
        public $lock;

        /**
         * @var int Unit rune HP stat.
         */
        public $rune_hp = 0;

        /**
         * @var int Unit rune ATK stat.
         */
        public $rune_attack = 0;

        /**
         * @var int Unit rune DEF stat.
         */
        public $rune_defense = 0;

        /**
         * @var int Unit rune SPD stat.
         */
        public $rune_speed = 0;

        /**
         * @var int Unit rune CRR stat.
         */
        public $rune_crit_rate = 0;

        /**
         * @var int Unit rune CRD stat.
         */
        public $rune_crit_damage = 0;

        /**
         * @var int Unit rune RES stat.
         */
        public $rune_resistance = 0;

        /**
         * @var int Unit rune ACC stat.
         */
        public $rune_accuracy = 0;

        /**
         * @var float Average rune efficiency.
         */
        public $avg_rune_efficiency = 0.0;

        /**
         * @var \Rune[] Equiped Runes.
         */
        public $rune = [];

        /**
         * @var \Team[] The Teamss the unit is on.
         */
        public $teams = [];

        /**
         * @var int[] Array with the levels of the skills, in orer.
         */
        public $skill_levels = [];

        /**
         * @var int Total experience required for the current level.
         */
        public $experience_level = 0;

        /**
         * @var int Experience required to level up.
         */
        public $experience_level_up = 0;

        /**
         * @var int Indcates if the unit is in storage.
         */
        public $in_storage = false;

        /**
         * @var string Unit title.
         * If Homunculus,it will be it's name.
         * If awakened, it will be the awakened from name.
         * If unawakened, it will be <element> <name>.
         */
        public $title;


        /**
         * Constructor.
         *
         * Searches the database and retrieves the information about the
         * monster, populating it and it's items.
         *
         * @param resource $db Connection to the database.
         * @param int $id Monster identifier.
         * @param bool $complete If false, query only monster and k_monster.
         * @global int Player ID.
         */
        public function __construct($db, $id, $complete = true){
            global $UID;
            parent::__construct($db);
            $s =
              "SELECT " .
              "  uid, " .
              "  id, " .
              "  building, " .
              "  unit, " .
              "  stars, " .
              "  level, " .
              "  hp, " .
              "  attack, " .
              "  defense, " .
              "  speed, " .
              "  crit_rate, " .
              "  crit_damage, " .
              "  resistance, " .
              "  accuracy, " .
              "  experience, " .
              "  exp_gained, " .
              "  exp_gain_rate, " .
              "  costume, " .
              "  attribute, " .
              "  source, " .
              "  create_time, " .
              "  homunculus, " .
              "  homunculus_name, " .
              "  lock " .
              "FROM unit " .
              "WHERE " .
              "  uid = '$UID' AND " .
              "  id = '$id'; ";
            $q = $this->db->query($s);
            $r = $q->fetchArray(SQLITE3_ASSOC);
            $this->uid = $r["uid"];
            $this->id = $r["id"];
            if (strlen($r["building"]) > 0){
                $this->building = new Building($this->db, $r["building"]);
            }
            if (strlen($r["unit"]) > 0){
                $this->unit = new K_Unit($this->db, $r["unit"], $complete);
            }
            $this->stars = $r["stars"];
            $this->level = $r["level"];
            $this->hp = $r["hp"];
            $this->attack = $r["attack"];
            $this->defense = $r["defense"];
            $this->speed = $r["speed"];
            $this->crit_rate = $r["crit_rate"];
            $this->crit_damage = $r["crit_damage"];
            $this->resistance = $r["resistance"];
            $this->accuracy = $r["accuracy"];
            $this->experience = $r["experience"];
            $this->exp_gained = $r["exp_gained"];
            $this->exp_gain_rate = $r["exp_gain_rate"];
            $this->costume = $r["costume"];
            $this->source = new K_Source($this->db, $r["source"]);
            $this->create_time = date_create($r["create_time"]);
            $this->homunculus_name = $r["homunculus_name"];
            if ($complete){
                $this->load_runes();
                $this->load_teams();
                $this->check_storage();
                $this->lock = $r["lock"];
                $s =
                  "SELECT level " .
                  "FROM " .
                  "  unit_skill, " .
                  "  k_skill " .
                  "WHERE " .
                  "  k_skill.id = unit_skill.skill AND " .
                  "  unit = '$this->id' " .
                  "ORDER BY slot;";
                $q = $this->db->query($s);
                while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                    array_push($this->skill_levels, $r["level"]);
                }
                $s =
                  "SELECT exp " .
                  "FROM k_experience " .
                  "WHERE " .
                  "  stars = $this->stars AND " .
                  "  level = $this->level;";
                $q = $this->db->query($s);
                $r = $q->fetchArray(SQLITE3_ASSOC);
                $this->experience_level = $r["exp"];
                $this->experience_level_up = $r["exp"] - $this->exp_gained;
            }
            if ($this->homunculus){
                $this->title = $this->homunculus_name;
            }
            else{
                $this->title = $this->unit->title;
            }
        }

        /**
         * Checks if the monster is in storage and sets {@see $in_storage} to
         * true or false.
         *
         * @global int Player ID.
         */
        public function check_storage(){
            global $UID;
            $s = "
              SELECT 1
              FROM
                unit,
                building
              WHERE
                unit.id = $this->id AND
                unit.uid = '$UID' AND
                building.uid = '$UID' AND
                unit.building = building.id AND
                building.building = '" . BUILDING_ID::MONSTER_STORAGE . "';
            ";
            $q = $this->db->query($s);
            if ($q->fetchArray(SQLITE3_ASSOC) == false){
                $this->in_storage = false;
            }
            else{
                $this->in_storage = true;
            }
        }

        /**
         * Loads the {@see teams} array, with the teams the unit is on.
         *
         * @global int Player ID.
         */
        public function load_teams(){
            global $UID;
            $this->teams = [];
            $s = "
              SELECT DISTINCT team.id AS id
              FROM
                team,
                team_unit
              WHERE
                team.uid = '$UID' AND
                team.id = team_unit.team AND
                team_unit.unit = '" . $this->id . "';
            ";
            $q = $this->db->query($s);
            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                array_push($this->teams, new Team($this->db, $r["id"], false));
            }
        }

        /**
         * Loads the information about the equiped runes. 
         * It is autoatically called at construction time if the
         * $complete parameter is true (by default). No point in calling it
         * twice.
         */
        public function load_runes(){
            $this->rune = [];
            $s =
              "SELECT id " .
              "FROM rune " .
              "WHERE assigned_to = '$this->id'; ";
            $q = $this->db->query($s);
            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                array_push($this->rune, new Rune($this->db, $r["id"]));
            }
            foreach ($this->rune as $rune){
                $this->sum_rune_stat($rune->main_stat, $rune->main_stat_value);
                $this->sum_rune_stat($rune->innate_stat, $rune->innate_stat_value);
                $this->sum_rune_stat($rune->substat_1, $rune->substat_1_value + $rune->substat_1_grind);
                $this->sum_rune_stat($rune->substat_2, $rune->substat_2_value + $rune->substat_2_grind);
                $this->sum_rune_stat($rune->substat_3, $rune->substat_3_value + $rune->substat_3_grind);
                $this->sum_rune_stat($rune->substat_4, $rune->substat_4_value + $rune->substat_4_grind);
            }
            $this->rune_attack = ceil($this->rune_attack);
            $this->rune_defense = ceil($this->rune_defense);
            $this->rune_hp = ceil($this->rune_hp);
        }

        /**
         * Calculates the stat increase by a rune property.
         * 
         * @param string $stat Stat type.
         * @param int $value Stat increase value.
         */
        private function sum_rune_stat($stat, $value){
            switch ($stat){
                case RUNE_STAT_ID::ATK:
                    $this->rune_attack += $value;
                    break;
                case RUNE_STAT_ID::DEF:
                    $this->rune_defense += $value;
                    break;
                case RUNE_STAT_ID::HP:
                    $this->rune_hp += $value;
                    break;
                case RUNE_STAT_ID::SPD:
                    $this->rune_speed += $value;
                    break;
                case RUNE_STAT_ID::CRR:
                    $this->rune_crit_rate += $value;
                    break;
                case RUNE_STAT_ID::CRD:
                    $this->rune_crit_damage += $value;
                    break;
                case RUNE_STAT_ID::ACC:
                    $this->rune_accuracy += $value;
                    break;
                case RUNE_STAT_ID::RES:
                    $this->rune_resistance += $value;
                    break;
                case RUNE_STAT_ID::ATK_P:
                    $this->rune_attack += ($this->attack * $value / 100);
                    break;
                case RUNE_STAT_ID::DEF_P:
                    $this->rune_defense += ($this->defense * $value / 100);
                    break;
                case RUNE_STAT_ID::HP_P:
                    $this->rune_hp += ($this->hp * $value / 100);
                    break;
            }
        }

        /**
         * Checks if the unit skills are completly maxed.
         * 
         * @return bool True if all skills maxed, false otherwise.
         */
        public function are_skills_maxed(){
            $maxed = true;
            for ($i = 0; $i < sizeof($this->unit->skill); $i ++){
                if ($this->unit->skill[$i]->max_level > $this->skill_levels[$i]){
                    $maxed = false;
                    break;
                }
            }
            return $maxed;
        }
    }
?>
