#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>

#include "cell.h"
#include "tm.h"

int inventaire_de_tous_les_blocs(long *nb_objets,
                                 long *tab_objets,
                                 long nb_max_objets,
                                 struct cell_tm *tab_tm,
                                 long tm_taille_max_x,
                                 long tm_taille_max_y,
                                 long tm_taille_max_z,
                                 char *buffer_erreur, int maxlen_erreur)
{
    long x, y, z, j, i;
    struct cell_tm *c_tm;
    /* faire l'inventaire de tous les types de blocs recensés */
    *nb_objets = 0;
    for (x = 0; x < tm_taille_max_x; x++) {
        for (y = 0; y < tm_taille_max_y; y++) {
            for (z = 0; z < tm_taille_max_z; z++) {
                c_tm = P_TM(x, y, z);
                j = c_tm->objet;
                if (j != OBJET_VIDE) {
                    /* chercher si on a déjà l'objet */
                    for (i = 0; i < (*nb_objets); i++) {
                        if (tab_objets[i] == j) {
                            break;
                        }
                    }
                    if (i == *nb_objets) {
                        /* pas trouvé => ajout dans tableau */
                        tab_objets[(*nb_objets)++] = j;
                        if (*nb_objets == nb_max_objets) {
                            snprintf(buffer_erreur, maxlen_erreur,
                                     "Trop d'objets différents recensés "
                                     "il n'y a plus de place "
                                     "dans le tableau qui les liste.\n"
                                     "La limite est de %ld objets.\n",
                                     nb_max_objets);
                            return -1;
                        }
                    }
                }
            }
        }
    }

    /* mettre les routes en premier avant tous les autres */
    for (i = 0; i < ((*nb_objets) - 1); i++) {
        if (tab_objets[i] == OBJET_ROUTE) {
            j = tab_objets[0];
            tab_objets[0] = tab_objets[i];
            tab_objets[i] = j;
            break;
        }
    }
    return 0;
}

int transferer_dans_tableau_tm(struct cell *tabcells,
                               long total_cells,
                               long taille_x, long taille_y, long taille_z,
                               struct cell_tm *tab_tm,
                               int tm_taille_max_x, int tm_taille_max_y,
                               int tm_taille_max_z, int opt_silent_mode,
                               char *buffer_erreur, int maxlen_erreur)
{
    long i, j, x, y, z;
    long diff, size;
    struct cell *c;
    struct cell_tm *c_tm;

    /* pour chaque cellule, remplissage au bon endroit d'un bloc au centre
       et des blocs N / E / S / O
     */
    j = tm_taille_max_x * tm_taille_max_y * tm_taille_max_z;
    for (i = 0; i < j; i++) {
        c_tm = &tab_tm[i];
        c_tm->objet = OBJET_VIDE;
        c_tm->orientation = DIR_NORD;
        c_tm->forcer_direction = 0;
    }
    size = taille_x * taille_y;
/*
    printf("taille_x = %ld\n", taille_x);
    printf("taille_y = %ld\n", taille_y);
    printf("taille_z = %ld\n", taille_z);
    printf("size = %ld\n", size);
*/
    for (i = 0; i < (long) total_cells; i++) {
        z = i / size;
        x = (i % size) % taille_x;
        y = (i % size) / taille_x;
        c = &tabcells[i];

        z++;
        /* Bloc Centre cellule */
        c_tm = P_TM(x, y, z);
        if (c->nb_paths == 0) {
            continue;
        }
        c_tm->objet = OBJET_ROUTE;
        c_tm->orientation = DIR_NORD;
        for (j = 0; j < c->nb_paths; j++) {
            diff = (long) c->no - (long) c->paths[j].link->no;
            printf("Cellule %ld (%ld,%ld,%ld) : lien %ld = n.%lu => diff=%ld\n", i, x,y,z, j,c->paths[j].link->no,diff);
/*
*/
            if (diff == (-size)) {
                printf("Lien vers le haut\n");
                /* lien vers le haut */
                c_tm->objet = OBJET_SAUT_ROUTE;
                c_tm->forcer_direction = 0;
                /* toujours 2 paths : lien haut et sortie */
                if (c->nb_paths != 2) {
                    snprintf(buffer_erreur, maxlen_erreur,
                             "Erreur : le fichier de labyrinthe "
                             "n'est pas construit pour Trackmania.\n"
                             "La cellule %ld doit avoir deux paths.\n"
                             "Elle en a %ld\n", (long int) c->no,
                             (long int) c->nb_paths);
                    return -1;
                }
                /* prendre l'autre lien */
                j = (j == 0 ? 1 : 0);
                diff = (long) c->no - (long) c->paths[j].link->no;
                if (diff == 1) {
                    /* Est */
                    if (opt_silent_mode == 0) {
                        printf("    Montée Est (%ld %ld %ld)\n", x, y, z);
                    }
                    c_tm->orientation = DIR_EST;
                } else if (diff == (-1)) {
                    /* Ouest */
                    if (opt_silent_mode == 0) {
                        printf("    Montée Ouest (%ld %ld %ld)\n", x, y,
                               z);
                    }
                    c_tm->orientation = DIR_OUEST;
                } else if (diff == (-(long) taille_x)) {
                    /* Sud */
                    if (opt_silent_mode == 0) {
                        printf("    Montée Nord (%ld %ld %ld)\n", x, y, z);
                    }
                    c_tm->orientation = DIR_NORD;
                } else if (diff == (long) taille_x) {
                    /* Nord */
                    if (opt_silent_mode == 0) {
                        printf("    Montée Sud (%ld %ld %ld)\n", x, y,
                               z);
                    }
                    c_tm->orientation = DIR_SUD;
                }
                break;
            } else if (diff == size) {
                /* lien vers le bas */
                printf("Lien vers le bas\n");
                c_tm->objet = OBJET_VIDE;
                break;
            } else if (diff == 1) {
                /* Ouest */
                c_tm->forcer_direction |= DIR_OUEST;
            } else if (diff == (-1)) {
                /* Est */
                c_tm->forcer_direction |= DIR_EST;
            } else if (diff == (-(long) taille_x)) {
                /* Sud */
                c_tm->forcer_direction |= DIR_SUD;
            } else if (diff == (long) taille_x) {
                /* Nord */
                c_tm->forcer_direction |= DIR_NORD;
            }
        }
    }

    /* poser le départ tout en haut à gauche */
    c_tm = P_TM(0, 0, 1);
    c_tm->objet = OBJET_DEPART;
    c_tm->orientation = DIR_SUD;
    c_tm->forcer_direction = 0;

    /* (!) il faut que l'arrivée se dirige vers le nord. mais la connexion 
       de l'arrivée est à l'opposé de la connexion des objets 
       => pour connecter la sortie vers le NORD je précise DIR_SUD...  */
    c_tm = P_TM((taille_x - 1), (taille_y - 1), taille_z);
    c_tm->objet = OBJET_ARRIVEE;
    c_tm->orientation = DIR_SUD;
    c_tm->forcer_direction = 0;

    return 0;
}
