<?php
require_once("Class/File/interface.php");

class FileAlliancesBatiments extends FileCommun implements File
{
    public function objectInFile($object)
    {
        foreach ($this->files as $keyF => $file) {
            foreach ($file as $keyE => $element) {
                if ($element[0] == $object) {
                    return array($keyF, $keyE);
                }
            }
        }
        return false;
    }

    public function nbObjectInFile($object, $type = null)
    {
        $c = 0;
        if (isset($type)) {
            if (!isset($type) || $type) {
                foreach ($this->files as $file) {
                    $c += count(array_keys($file, array($object, true)));
                }
            }
            if (!isset($type) || !$type) {
                foreach ($this->files as $file) {
                    $c += count(array_keys($file, array($object, false)));
                }
            }
        }
        return $c;
    }

    public function addObjet($object, $nombre, surface $planete)
    {
        //On vérifie que l'on ne dépasse pas la taille maximale de la file
        if (!$this->checkMaxSize($planete)) {
            throw new ExceptionHB(1, 1);
        }

        //Validation des conditions de construction
        if (!dAlliancesBatiments::needed($object, $planete)) {
            throw new ExceptionHB(1, 2);
        }

        //On vérifie qu'il n'y ait pas une demande de démolition du même bâtiment
        if ($this->nbObjectInFile($object, true) >= 1) {
            throw new ExceptionHB(1, 7);
        }

        //Calcul du prochain niveau du batiment
        $nextLvl = $planete->batiments[$object] + $this->nbObjectInFile($object, false) + 1;

        //On recherche le lieu ayant le moins de construction en cours
        $lieu = $this->findShorter();

        //On rafraîchit le temps de la file si aucun objet n'est en file d'attente
        $this->refreshTime($lieu);

        //On vérifie qu'il y ait assez de ressources sur la planète
        if ($planete->checkAndRetireRessources(dAlliancesBatiments::metal($object, $nextLvl, $planete), dAlliancesBatiments::cristal($object, $nextLvl, $planete), dAlliancesBatiments::hydrogene($object, $nextLvl, $planete), dAlliancesBatiments::credits($object, $nextLvl, $planete))) {
            $this->files[$lieu][] = array($object, false);
            $planete->addModif("file_bat");
            return true;
        } else {
            throw new ExceptionHB(1, 4);
        }
    }

    public function addDemolition($object, $nombre, surface $planete)
    {
        //On vérifie que l'on ne dépasse pas la taille maximale de la file
        if (!$this->checkMaxSize($planete)) {
            throw new ExceptionHB(1, 1);
        }

        //On vérifie que le niveau actuel du batiment ne soit non nul
        if ($planete->batiments[$object] <= $this->nbObjectInFile($object, false)) {
            throw new ExceptionHB(1, 6);
        }

        //On vérifie qu'il n'y ait pas une demande de construction du même bâtiment
        if ($this->nbObjectInFile($object, false) >= 1) {
            throw new ExceptionHB(1, 7);
        }

        //On recherche le lieu ayant le moins de construction en cours
        $lieu = $this->findShorter();

        //On rafraîchit le temps de la file si aucun objet n'est en file d'attente
        $this->refreshTime($lieu);

        $this->files[$lieu][] = array($object, true);

        $planete->addModif("file_bat");

        return true;
    }

    public function delObjet($id, $nombre, $lieu, surface $planete)
    {
        //Vérification de l'existance de l'objet en file d'attente
        if (empty($this->files[$lieu][$id])) {
            throw new ExceptionHB(1, 5);
        }

        //On récupère le type de batiment
        $object = $this->files[$lieu][$id][0];

        //On gère les démolition
        //@todo -cFileBatiments Est-ce vraiment utile de calculer le niveau du batiment en cas de démolition ?
        if ($this->files[$lieu][$id][1]) {
            $lvlAnnule = $planete->batiments[$object] - $this->nbObjectInFile($object, true) + 1;
        } else {
            $lvlAnnule = $planete->batiments[$object] + $this->nbObjectInFile($object, false);
        }

        //On met à jour le temps si on vient d'annuler le premier batiment en lice
        if ($id == $this->findFirstKey($lieu)) {
            $this->times[$lieu] = time();
        }

        $planete->addModif("file_bat");

        if (!$this->files[$lieu][$id][1]) {
            //On redonne 60% des ressources au joueur si c'est la première construction dans la file d'attente
            if ($id == 0) {
                $planete->addRessources(dAlliancesBatiments::metal($object, $lvlAnnule, $planete)*0.6, dAlliancesBatiments::cristal($object, $lvlAnnule, $planete)*0.6, dAlliancesBatiments::hydrogene($object, $lvlAnnule, $planete)*0.6, dAlliancesBatiments::credits($object, $lvlAnnule, $planete)*0.6);
            } else {
                $planete->addRessources(dAlliancesBatiments::metal($object, $lvlAnnule, $planete), dAlliancesBatiments::cristal($object, $lvlAnnule, $planete), dAlliancesBatiments::hydrogene($object, $lvlAnnule, $planete), dAlliancesBatiments::credits($object, $lvlAnnule, $planete));
            }
        }

        //Effacement de la file
        unset($this->files[$lieu][$id]);

        return true;
    }

    public function ready(SURFACE $planete)
    {
        //On parcourt la liste des lieux de construction
        foreach ($this->files as $keyF => $file) {
            //On vérifie qu'il y a bien des éléments dans cette file d'attente
            if (count($file) == 0) {
                continue;
            }

            //On parcourt la file
            foreach ($file as $keyE => $element) {
                $tempsEcoule = time() - $this->times[$keyF];

                //On gère les démolitions
                if ($element[1]) {
                    //On récupère le niveau actuel du batiment
                    $lvl = $planete->batiments[$element[0]];

                    //On calcul le temps de démolition nécessaire (60% du niveau actuel)
                    $tempsNecessaire = dAlliancesBatiments::temps($element[0], $lvl, $planete, true);

                    if ($tempsEcoule >= $tempsNecessaire) {
                        $metal = dAlliancesBatiments::metal($element[0], $lvl, $planete);
                        $cristal = dAlliancesBatiments::cristal($element[0], $lvl, $planete);
                        $hydrogene = dAlliancesBatiments::hydrogene($element[0], $lvl, $planete);

                        //On redonne 70% des ressources du batiment au joueur
                        $planete->addRessources($metal*0.7, $cristal*0.7, $hydrogene*0.7);

                        //On retire un niveau au batiment
                        $planete->batiments[$element[0]]--;

                        //On efface l'entrée de la file et on met à jour le temps de la file
                        unset($this->files[$keyF][$keyE]);
                        $this->times[$keyF] += $tempsNecessaire;

                        //On demande la mise à jour des champs modifiés
                        $planete->addModif(array("batiments", $element[0]));
                        $planete->addModif("file_bat");

                        //On retire les points
                        $planete->addPoints($metal, $cristal, $hydrogene, 0, true);

                        unset($metal, $cristal, $hydrogene);
                    }
                    //Si le temps écoulé n'est pas suffisant pour ce batiment, on annule tous les suivants
                    else {
                        break;
                    }
                } else { //Cas de la construction
                    //Récupération du niveau du batiment
                    $lvl = $planete->batiments[$element[0]] + 1;

                    $tempsNecessaire = dAlliancesBatiments::temps($element[0], $lvl, $planete);

                    //Si le temps écoulé est suffisant
                    if ($tempsEcoule >= $tempsNecessaire) {
                        //On ajoute un niveau au batiment
                        $planete->batiments[$element[0]]++;

                        //On efface l'entrée de la file et on met à jour le temps de la file
                        unset($this->files[$keyF][$keyE]);
                        $this->times[$keyF] += $tempsNecessaire;

                        //On demande la mise à jour des champs modifiés
                        $planete->addModif(array("batiments", $element[0]));
                        $planete->addModif("file_bat");

                        //On ajoute les points
                        $planete->addPoints(dAlliancesBatiments::metal($element[0], $planete->batiments[$element[0]], $planete), dAlliancesBatiments::cristal($element[0], $planete->batiments[$element[0]], $planete), dAlliancesBatiments::hydrogene($element[0], $planete->batiments[$element[0]], $planete));
                    }
                    //Si le temps écoulé n'est pas suffisant pour ce batiment, on annule tous les suivants
                    else {
                        break;
                    }
                }
            }
        }
    }


    public function printFile(SURFACE $planete, $lieu = null)
    {
        $out = array();
        foreach ($this->files as $keyF => $file) {
            if (isset($lieu) && $lieu != $keyF) {
                continue;
            }

            $prems = true;
            foreach ($file as $keyE => $element) {
                if ($element[1]) { //Cas d'une démolition
                    $temps = dAlliancesBatiments::temps($element[0], $planete->batiments[$element[0]], $planete, true);
                    if ($prems) {
                        $temps -= time() - $this->times[$keyF];
                    }
                    $out[$keyF][$keyE] = array($element[0], $element[1], ceil($temps), $prems);
                } else { //Cas d'une construction
                    $temps = dAlliancesBatiments::temps($element[0], $planete->batiments[$element[0]]+1, $planete);
                    if ($prems) {
                        $temps -= time() - $this->times[$keyF];
                    }
                    $out[$keyF][$keyE] = array($element[0], $element[1], ceil($temps), $prems);
                }
                $prems = false;
            }
        }
        return $out;
    }
}
