/**
 * @file
 * @brief Abstraction de l'écriture et la lecture d'un fichier bit à bit.
 *
 * Définir des structures et des fonctions de manipulation liées à
 * un fichier et permettant d'accéder à son contenu ou de le modifier
 * bit par bit au lieu d'octet par octet.
 */

#ifndef __HUFFMAN_BUFFER_H_INCLUDED__
#define __HUFFMAN_BUFFER_H_INCLUDED__

#include <stdio.h>
#include <stdint.h>

#include "common.h"

/**
 * @brief Tampon d'écriture bit par bit.
 *
 * Tampon permettant d'abstraire l'écriture dans un fichier bit par
 * bit au lieu d'octet par octet. Les bits sont vidés dans le fichier
 * dès qu'un octet est complet, ou lorsque le vidage est forcé.
 */
typedef struct WriteBuffer {
    /**
     * Données du tampon d'écriture en attente de vidage.
     */
    int data;

    /**
     * Nombre de bits utilisés dans WriteBuffer#data.
     */
    size_t pending_bits;

    /**
     * Nombre de vidages effectués par le tampon.
     */
    bytecount flushed_count;

    /**
     * Fichier dans lequel le tampon est vidé.
     */
    FILE* dest_file;
} WriteBuffer;

/**
 * @brief Initialiser un tampon d'écriture.
 *
 * Initialiser un tampon vide avec le fichier @p dest pour destination.
 * @param dest Fichier de destination.
 * @return Tampon créé.
 */
WriteBuffer createWriteBuffer(FILE* dest);

/**
 * @brief Écrire un bit dans le tampon d'écriture.
 *
 * Ajouter le bit @p bit aux données du tampon @p buffer. Si le tampon est
 * plein, vidage dans le fichier associé.
 * @param bit Bit à ajouter au tampon (0 ou 1).
 * @param buffer Tampon dans lequel ajouter le bit.
 */
void putBuffer(char bit, WriteBuffer* buffer);

/**
 * @brief Forcer le vidage du tampon d'écriture.
 *
 * Forcer le vidage du tampon dans son fichier et sa réinitialisation.
 * Si le tampon est vide, pas de vidage (pas d'octet superflu écrit).
 * Si le tampon n'est pas rempli, complétion à droite par des 0.
 * @param buffer Tampon à vider.
 */
void flushBuffer(WriteBuffer* buffer);

/**
 * @brief Récupèrer le nombre de vidages effectués par ce tampon.
 *
 * Permet de savoir combien d'octets ont été écrits dans le fichier
 * par le tampon @p buffer.
 * @param buffer Tampon à vérifier.
 * @return Nombre de vidages effectués.
 */
bytecount getFlushedCount(WriteBuffer* buffer);

/**
 * @brief Tampon de lecture bit par bit.
 *
 * Tampon permettant d'abstraire la lecture d'un fichier bit par
 * bit au lieu d'octet par octet. Un octet est lu depuis le fichier
 * seulement lorsque tous les bits du précédent octet ont été consommés.
 */
typedef struct ReadBuffer {
    /**
     * Données du tampon de lecture en attente de lecture.
     */
    int data;

    /**
     * Numéro du prochain bit de ReadBuffer#data à lire.
     */
    size_t next_bit;

    /**
     * Fichier depuis lequel les données sont lues.
     */
    FILE* source_file;
} ReadBuffer;

/**
 * @brief Initialiser un tampon de lecture.
 *
 * Initialiser un tampon vide avec le fichier @p source comme source.
 * @param source Fichier source.
 * @return Tampon créé.
 */
ReadBuffer createReadBuffer(FILE* source);

/**
 * @brief Lire un bit depuis le tampon de lecture.
 *
 * Lire le prochain bit depuis le tampon de lecture, et lire un octet
 * depuis la source si besoin est.
 * @param buffer Tampon depuis lequel lire un bit.
 * @return Valeur du bit qui est lu : 0 ou 1.
 */
char getBuffer(ReadBuffer* buffer);

#endif // __HUFFMAN_BUFFER_H_INCLUDED__
