#include "common.h"
#include "display.h"
#include "huftree.h"

#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <locale.h>

/**
 * Détermine la profondeur maximale de l'arbre de Huffman donné
 */
static int _treeDepth(HufTree);

/**
 * Sous-fonction pour l'affichage récursif d'un arbre de Huffman
 */
static void _subPrintTree(HufTree, wchar_t*, int);

/**
 * Transforme le caractère donné en espace s'il est non-imprimable
 * ou le laisse tel quel sinon
 */
static char _safeChar(char input);

// Drapeau pour l'affichage verbeux ou non-verbeux
static int is_verbose = FALSE;

void printVerbose(const char* format, ...) {
    if (is_verbose) {
        va_list args_list;

        va_start(args_list, format);
        vfprintf(stderr, format, args_list);
        va_end(args_list);
    }
}

void setVerbose(int flag) {
    is_verbose = flag;
}

int isVerbose() {
    return is_verbose;
}

void printTree(HufTree tree) {
    if (tree == NULL) {
        // Cas particulier : arbre vide
        printVerbose("(Arbre vide.)\n");
    } else {
        // Allocation d'un tampon suffisamment grand pour contenir
        // les indentations des sommets les plus profonds de l'arbre
        wchar_t* buffer = malloc(_treeDepth(tree) * 4 * sizeof(*buffer));
        _subPrintTree(tree, buffer, 0);
        free(buffer);
    }
}

void _subPrintTree(HufTree tree, wchar_t* buffer, int length) {
    if (tree->child_l != NULL && tree->child_r != NULL) {
        // Affichage d'un sommet avec enfants, on montre
        // la probabilité somme des enfants
        printVerbose("■\n");

        // Affichage du fils gauche. Augmentation du préfixe
        // pour l'affichage des enfants du fils gauche
        buffer[length] = '\0';
        printVerbose("%ls├── ", buffer);

        buffer[length] = L'│';
        buffer[length + 1] = ' ';
        buffer[length + 2] = ' ';
        buffer[length + 3] = ' ';
        buffer[length + 4] = '\0';
        _subPrintTree(tree->child_l, buffer, length + 4);

        // Affichage du fils droite. Augmentation du préfixe
        // pour l'affichage des enfants du fils droit
        buffer[length] = '\0';
        printVerbose("%ls└── ", buffer);

        buffer[length] = ' ';
        _subPrintTree(tree->child_r, buffer, length + 4);
    } else {
        // Affichage d'une feuille de l'arbre, correspondant
        // à un caractère du corpus
        printVerbose("%c\n", _safeChar(tree->value));
    }
}

int _treeDepth(HufTree tree) {
    if (tree->child_l != NULL && tree->child_r != NULL) {
        int left = _treeDepth(tree->child_l);
        int right = _treeDepth(tree->child_r);

        return (left > right ? left : right) + 1;
    } else {
        return 1;
    }
}

void printCountsTable(bytecount* table, bytecount total, size_t size) {
    printVerbose("┌─┬────┬────────┐\n");
    printVerbose("│C│code│effectif│\n");
    printVerbose("├─┼────┼────────┤\n");

    for (size_t i = 0; i < size; i++) {
        if (table[i] != 0) {
            printVerbose("│%c│%4d│%8llu│\n", _safeChar(i), (int) i, table[i]);
        }
    }

    printVerbose("├─┴────┼────────┤\n");
    printVerbose("│ Total│%8llu│\n", total);
    printVerbose("└──────┴────────┘\n");
}

void printLabelsTable(char** table, size_t size) {
    printVerbose("┌─┬────┬────────────────┐\n");
    printVerbose("│C│code│       étiquette│\n");
    printVerbose("├─┼────┼────────────────┤\n");

    double total_length = 0;
    size_t label_count = 0;

    for (size_t i = 0; i < size; i++) {
        if (table[i] != 0) {
            printVerbose("│%c│%4d│%16s│\n", _safeChar(i), (int) i, table[i]);

            total_length += strlen(table[i]);
            label_count++;
        }
    }

    printVerbose("├─┴────┴───┬────────────┤\n");
    printVerbose("│Long. moy.│%12.4lf│\n", total_length / label_count);
    printVerbose("└──────────┴────────────┘\n");
}

char _safeChar(char input) {
    if (input < 32 || input == 127) {
        return ' ';
    }

    return input;
}
