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

class FileCaserne extends FileCommun implements File
{
    public function objectInFile($object, $lieu = null)
    {
        if (isset($lieu)) {
            if (!empty($this->files[$lieu])) {
                foreach ($this->files[$lieu] as $keyE => $element) {
                    if ($element[0] == $object) {
                        return array($lieu, $keyE);
                    }
                }
            }
        } else {
            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)
    {
        $c = 0;
        foreach ($this->files as $key => $file) {
            foreach ($file as $element) {
                if ($element[0] == $object) {
                    $c += $element[1];
                }
            }
        }
        return $c;
    }

    public function addObjet($object, $nombre, surface $planete, $lieu = null)
    {
        //Vérification du nombre passé en entrée
        if (!is_numeric($nombre) || $nombre < 0 || $nombre > 99999) {
            throw new ExceptionHB(3, 8);
        }

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

        //On vérifie que l'on ne dépasse pas la taille maximale de la file
        if (!($sauvLastKey = $this->objectInFile($object, $lieu)) && !$this->checkMaxSize($planete, $lieu)) {
            throw new ExceptionHB(3, 1);
        }

        //On tronque au maximum d'unités constructible sur la planète
        if (($metal = dCaserne::metal($object, 1, $planete)) > 0) {
            $metal = $planete->metal/$metal;
        } else {
            $metal = $nombre;
        }
        if (($cristal = dCaserne::cristal($object, 1, $planete)) > 0) {
            $cristal = $planete->cristal/$cristal;
        } else {
            $cristal = $nombre;
        }
        if (($hydrogene = dCaserne::hydrogene($object, 1, $planete)) > 0) {
            $hydrogene = $planete->hydrogene/$hydrogene;
        } else {
            $hydrogene = $nombre;
        }

        $nombre = floor(min($nombre, $metal, $cristal, $hydrogene));

        //On vérifie qu'il y ait assez de ressources sur la planète
        if ($planete->checkAndRetireRessources(dCaserne::metal($object, $nombre, $planete), dCaserne::cristal($object, $nombre, $planete), dCaserne::hydrogene($object, $nombre, $planete), dCaserne::credits($object, $nombre, $planete))) {
            //Si il existe déjà l'objet en file d'attente, on l'ajoute
            if (isset($sauvLastKey) && isset($this->files[$sauvLastKey[0]][$sauvLastKey[1]])) {
                //On rafraîchit le temps de la file si aucun objet n'est en file d'attente
                $this->refreshTime($sauvLastKey[0]);

                $this->files[$sauvLastKey[0]][$sauvLastKey[1]][1] += $nombre;
            } else {
                if (!isset($lieu)) {
                    //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, $nombre, false);
            }

            $planete->addModif("file_cas");
            return true;
        } else {
            throw new ExceptionHB(3, 4);
        }
    }

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

        //Vérification du nombre passé en entrée
        if (!is_numeric($nombre) || $nombre < 0 || $nombre > 99999) {
            throw new ExceptionHB(3, 8);
        }

        //On vérifie que le nombre d'unité actuel soit non nul
        if ($planete->casernes[$object] < $nombre) {
            throw new ExceptionHB(3, 6);
        }

        if (!isset($lieu)) {
            //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);

        //Si il existe déjà l'objet en file d'attente, on l'ajoute
        if (isset($sauvLastKey)) {
            $this->files[$sauvLastKey[0]][$sauvLastKey[1]][1] += $nombre;
        } else {
            $this->files[$lieu][] = array($object, $nombre, false);
        }

        $planete->addModif("file_cas");

        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);
        }

        //Si $nombre est supérieur au nombre présent dans la file, on le réduit
        if ($this->files[$lieu][$id][1] < $nombre) {
            $nombre = $this->files[$lieu][$id][1];
        }

        //On récupère les informations disponibles
        $objet = $this->files[$lieu][$id][0];
        $nombreMax = $this->files[$lieu][$id][1];

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

        $planete->addModif("file_cas");

        if (!$this->files[$lieu][$id][2]) {
            $planete->addRessources(dCaserne::metal($objet, $nombre, $planete), dCaserne::cristal($objet, $nombre, $planete), dCaserne::hydrogene($objet, $nombre, $planete), dCaserne::credits($objet, $nombre, $planete));
        }

        //Effacement de la file
        if ($nombre >= $nombreMax) {
            unset($this->files[$lieu][$id]);
        } else {
            $this->files[$lieu][$id][1] -= $nombre;
        }
        $planete->addModif("file_cas");

        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 liste à la recherche des unités terminées dans l'ordre
            foreach ($file as $keyE => $element) {
                //Calcul du temps écoulé depuis le dernier entraînement
                $tempsEcoule = time() - $this->times[$keyF];

                //On gére les licenciments !
                if ($element[2]) {
                    //On vérifie qu'il reste des unités du type sur la planète
                    if ($planete->casernes[$element[0]] <= 0) {
                        unset($this->files[$keyF][$keyE]);
                        $planete->addModif("file_cas");
                    } else {
                        //Récupération de 60% du temps nécessaire
                        $tempsNecessaire = dCaserne::temps($element[0], 1, $planete) * 0.6;

                        //Calcul du nombre d'unités maximum
                        $nbUnitee = min(floor($tempsEcoule/$tempsNecessaire), $element[1], $planete->casernes[$element[0]]);

                        //Si le temps écoulé est suffisant
                        if ($nbUnitee > 0) {
                            //On redonne 70% des ressources de l'unité au joueur
                            $planete->addRessources(dCaserne::metal($element[0], $nbUnitee, $planete)*0.7, dCaserne::cristal($element[0], $nbUnitee, $planete)*0.7, dCaserne::hydrogene($element[0], $nbUnitee, $planete)*0.7, dCaserne::credits($element[0], $nbUnitee, $planete)*0.7);

                            //On retire les unités
                            $planete->casernes[$element[0]] -= $nbUnitee;

                            //On efface l'entrée de la file et on met à jour le temps de la file
                            if ($nbUnitee >= $element[1]) {
                                unset($this->filefiles[$keyF][$keyE]);
                            } else {
                                $this->file[$key][1] -= $nbUnitee;
                            }
                            $this->timefiles[$keyF] += $tempsNecessaire*$nbUnitee;

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

                            if ($nbUnitee < $element[1]) {
                                return false;
                            }
                        }
                        //Si le temps écoulé n'est pas suffisant pour cette unité, on annule toutes les suivantes
                        else {
                            break;
                        }
                    }
                } else { //Cas de la construction
                    //Récupération du temps nécessaire
                    $tempsNecessaire = dCaserne::temps($element[0], 1, $planete);

                    //Calcul du nombre d'unités maximum
                    $nbUnitee = min(floor($tempsEcoule/$tempsNecessaire), $element[1]);

                    //Si le temps écoulé est suffisant
                    if ($nbUnitee > 0) {
                        //On ajoute le nombre d'unités
                        $planete->casernes[$element[0]] += $nbUnitee;

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

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

                        if ($nbUnitee < $element[1]) {
                            break;
                        }
                    }
                    //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[2]) {
                    $temps = dCaserne::temps($element[0], 1, $planete) * 0.6;
                    if ($prems) {
                        $temps_moins = time() - $this->times[$keyF];
                    } else {
                        $temps_moins = 0;
                    }
                    $out[$keyF][$keyE] = array($element[0], $element[1], $element[2], ceil($temps * $element[1] - $temps_moins), ceil($temps - $temps_moins), $prems);
                } else {
                    $temps = dCaserne::temps($element[0], 1, $planete);
                    if ($prems) {
                        $temps_moins = time() - $this->times[$keyF];
                    } else {
                        $temps_moins = 0;
                    }
                    $out[$keyF][$keyE] = array($element[0], $element[1], $element[2], ceil($temps * $element[1] - $temps_moins), ceil($temps - $temps_moins), $prems);
                }
                $prems = false;
            }
        }
        return $out;
    }
}
