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

#include "utils.h"
/*
#include <unistd.h>
#include <strings.h>

#include "opts.h"
*/
#include "output_autohotkey.h"
#include "cell.h"
#include "tm.h"
/*
#include "laby_lecture.h"
*/

#define MAX_LONGUEUR_ORDRES (unsigned long)60
#define AJOUT_ORDRES( z ) printf("%s\n", z); ajouter_ordres(&houtput, z, MAX_LONGUEUR_ORDRES)
/*
#define AJOUT_ORDRES( z ) ajouter_ordres(&houtput, z, MAX_LONGUEUR_ORDRES)
*/


char ordres[200] = "";

void ecrire_ordres(FILE ** houtput)
{
    if (strlen(ordres)) {
        fprintf(*houtput, "TMExecute( \"%s\" )\n", ordres);
        ordres[0] = 0;
    }
}

void ajouter_ordres(FILE ** houtput, char *nouveaux_ordres,
                    unsigned long max_longueur)
{
    strcat(ordres, nouveaux_ordres);
    if (strlen(ordres) > max_longueur) {
        ecrire_ordres(houtput);
    }
}

void fichier_ecrire_entete(FILE ** houtput,
                           long taille_x, long taille_y, long taille_z,
                           unsigned char rewrite_fichier_sortie)
{
    /* on peut ne pas écrire l'entête si on veut ajouter le fichier
       de sortie à un fichier déjà existant (par exemple pour
       créer plusieurs labyrinthes dans une même map) */
    /* si on est en mode "tout écraser", alors mettre l'entete au complet : */
    if (rewrite_fichier_sortie) {
        fprintf(*houtput, ";-------------------------------\n");
        fprintf(*houtput, "; Fichier de génération de labyrinthe\n;\n");
        fprintf(*houtput, "; (c) Olivier Pons\n;\n");
        fprintf_time_desc(*houtput, "; fichier généré ");
        fprintf(*houtput, ";\n");

        fprintf(*houtput, "#Include Tm.ahk\n\n");
        fprintf(*houtput, "TailleX := %lu\n", taille_x);
        fprintf(*houtput, "TailleY := %lu\n", taille_y);
        fprintf(*houtput, "TailleZ := %lu\n\n", taille_z);
        fprintf(*houtput, ";-----------------------------------\n");
        fprintf(*houtput, "\n");
        fprintf(*houtput, "ActiverFenetre( \"TrackMania\" )\n");
        fprintf(*houtput, "Sleep, 3000\n");
        fprintf(*houtput, "\n");
        fprintf(*houtput,
                ";TMCarresARelierPoser( TailleX, TailleY, TailleZ )\n");
    }
    fprintf(*houtput, "TMPlaceHomeDecale( %ld, %ld, %ld )\n",
            taille_x, taille_y, taille_z);
}

int output_autohotkey(char *nom_fichier_sortie,
                      long taille_x, long taille_y, long taille_z,
                      unsigned char rewrite_fichier_sortie,
                      long *tab_objets,
                      long nb_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)
{
    FILE *houtput;
    /* se souvenir de la direction
       quand on pose des routes : */
    unsigned char dir_courante = DIR_NORD;

    long i, j, k, l, x, y, z, diff;
    long tm_pos_x, tm_pos_y, tm_pos_z;
    long add_x, add_y, add_z;
    long objet_courant;
    char buf[20];
    struct cell_tm *c_tm;

    if (rewrite_fichier_sortie) {
        houtput = fopen(nom_fichier_sortie, "wb+");
    } else {
        houtput = fopen(nom_fichier_sortie, "ab+");
    }
    if (houtput == NULL) {
        snprintf(buffer_erreur, maxlen_erreur,
                 "Erreur d'ecriture dans le fichier <%s>.\n",
                 nom_fichier_sortie);
        return -1;
    }

    fichier_ecrire_entete(&houtput, taille_x, taille_y, taille_z,
                          rewrite_fichier_sortie);

    /* pour chaque type de bloc, déplacer le curseur là où il
       faut et poser le bloc */
    /* inits à ne faire qu'une fois */
    i = tm_pos_x = tm_pos_y = tm_pos_z = 0;
    z = y = x = 0;
    add_x = add_y = add_z = 1;

    /* boucle de parcours du tableau */
    while (i < nb_objets) {
        objet_courant = tab_objets[i];
        j = 0;
        while (1) {
            c_tm = P_TM(x, y, z);
            if (c_tm->objet == objet_courant) {
                if (j == 0) {
                    /* pas encore demandé d'écrire
                       l'objet courant => le faire */
                    j = 1;

                    /* vider le buffer d'écriture des ordres en attente : */
                    ecrire_ordres(&houtput);

                    switch (objet_courant) {
                    case OBJET_VIDE:
                        break;
                    case OBJET_BLOC:
                        fprintf(houtput, "TMBlocBasiqueSelectionner()\n");
                        break;
                    case OBJET_SAUT:
                        fprintf(houtput, "TMSautSelectionner()\n");
                        break;
                    case OBJET_SAUT_COMPLEMENT:
                        fprintf(houtput,
                                "TMSautComplementSelectionner()\n");
                        break;
                    case OBJET_DEPART:
                        printf("TMDepartSelectionner()\n");
                        fprintf(houtput, "TMDepartSelectionner()\n");
                        break;
                    case OBJET_ARRIVEE:
                        printf("TMArriveeSelectionner()\n");
                        fprintf(houtput, "TMArriveeSelectionner()\n");
                        break;
                    case OBJET_LUMIERE:
                        fprintf(houtput, "TMLumiereSelectionner()\n");
                        break;
                    case OBJET_ROUTE:
                        printf("TMRouteSelectionner()\n");
                        fprintf(houtput, "TMRouteSelectionner()\n");
                        break;
                    case OBJET_SAUT_ROUTE:
                        printf("TMSautRouteSelectionner()\n");
                        fprintf(houtput, "TMSautRouteSelectionner()\n");
                        break;
                    }
                }

                /* s'assurer qu'un seul char de transmis
                   dans AJOUT_ORDRES : */
                buf[1] = 0;

                if (tm_pos_z != z) {
                    while (z != tm_pos_z) {
                        diff = ((tm_pos_z - z) < 0 ? 1 : -1);
                        buf[0] = (diff > 0 ? '+' : '-');
                        AJOUT_ORDRES(buf);
                        tm_pos_z += diff;
                    }
                }
                if (tm_pos_y != y) {
                    diff = ((tm_pos_y - y) < 0 ? 1 : -1);
                    buf[0] = (diff > 0 ? 'D' : 'U');
                    while (tm_pos_y != y) {
                        tm_pos_y += diff;
                        AJOUT_ORDRES(buf);
                    }
                }
                if (tm_pos_x != x) {
                    diff = ((tm_pos_x - x) < 0 ? 1 : -1);
                    buf[0] = (diff > 0 ? 'R' : 'L');
                    while (tm_pos_x != x) {
                        tm_pos_x += diff;
                        AJOUT_ORDRES(buf);
                    }
                }
                if (c_tm->forcer_direction == 0) {
                    printf("Orientation = %d\n", c_tm->orientation);
                    /* c'est pas une route => on peut faire
                       des rotations avant de poser l'objet : */
                    switch (c_tm->orientation) {
                    case DIR_NORD:
                        switch (dir_courante) {
                        case DIR_NORD:
                            break;
                        case DIR_EST:
                            AJOUT_ORDRES("TTT");
                            break;
                        case DIR_SUD:
                            AJOUT_ORDRES("TT");
                            break;
                        case DIR_OUEST:
                            AJOUT_ORDRES("T");
                            break;
                        }
                        break;
                    case DIR_EST:
                        switch (dir_courante) {
                        case DIR_NORD:
                            AJOUT_ORDRES("T");
                            break;
                        case DIR_EST:
                            break;
                        case DIR_SUD:
                            AJOUT_ORDRES("TTT");
                            break;
                        case DIR_OUEST:
                            AJOUT_ORDRES("TT");
                            break;
                        }
                        break;
                    case DIR_SUD:
                        switch (dir_courante) {
                        case DIR_NORD:
                            AJOUT_ORDRES("TT");
                            break;
                        case DIR_EST:
                            AJOUT_ORDRES("T");
                            break;
                        case DIR_SUD:
                            break;
                        case DIR_OUEST:
                            AJOUT_ORDRES("TTT");
                            break;
                        }
                        break;
                    case DIR_OUEST:
                        switch (dir_courante) {
                        case DIR_NORD:
                            AJOUT_ORDRES("TTT");
                            break;
                        case DIR_EST:
                            AJOUT_ORDRES("TT");
                            break;
                        case DIR_SUD:
                            AJOUT_ORDRES("T");
                            break;
                        case DIR_OUEST:
                            break;
                        }
                        break;

                    }
                    dir_courante = c_tm->orientation;
                    AJOUT_ORDRES("*");
                } else {
                    k = 0;
                    l = c_tm->forcer_direction;
                    buf[k++] = 'S';
                    if ((add_y == -1) && (l & DIR_NORD)) {
                        buf[k++] = 'U';
                        buf[k++] = 'D';
                        dir_courante = DIR_SUD;
                    }
                    if ((add_x == 1) && (l & DIR_EST)) {
                        buf[k++] = 'R';
                        buf[k++] = 'L';
                        dir_courante = DIR_OUEST;
                    }
                    if ((add_y == 1) && (l & DIR_SUD)) {
                        buf[k++] = 'D';
                        buf[k++] = 'U';
                        dir_courante = DIR_NORD;
                    }
                    if ((add_x == -1) && (l & DIR_OUEST)) {
                        buf[k++] = 'L';
                        buf[k++] = 'R';
                        dir_courante = DIR_EST;
                    }
                    buf[k++] = 's';
                    if (k > 2) {
                        buf[k] = 0;
                        AJOUT_ORDRES(buf);
                    }
                }
            }
            x += add_x;
            if (x < 0) {
                /* X arrivé au bout => demi tour */
                x = 0;
                add_x = 1;
                y += add_y;
            } else if (x == tm_taille_max_x) {
                /* X arrivé au bout => demi tour */
                x = tm_taille_max_x - 1;
                add_x = -1;
                y += add_y;
            }
            /* si X arrivé au bout tester Y : */
            if (y < 0) {
                add_y = 1;
                y = 0;
                z += add_z;
            } else if (y == tm_taille_max_y) {
                add_y = -1;
                y = tm_taille_max_y - 1;
                z += add_z;
            }
            /* si Y arrivé au bout tester Z : */
            if (z < 0) {
                add_z = 1;
                z = 0;
                break;
            } else if (z == tm_taille_max_z) {
                add_z = -1;
                z = tm_taille_max_z - 1;
                break;
            }
        }
        i++;
    }

    ecrire_ordres(&houtput);
    fclose(houtput);
    return 0;
}
