/*
    Fichier modepage.c
    Auteur Bernard Chardonneau

    Logiciel libre, droits d'utilisation précisés en français
    dans le fichier : licence.fr

    Traductions des droits d'utilisation dans les fichiers :
    licence.de , licence.en , licence.es , licence.it
    licence.nl , licence.pt , licence.eo , licence.eo-utf


    Bibliothèque de fonctions permettant de gérer l'affichage en mode page

    Certaines de ces fonctions sont des macros de modepage.h

    On peut remarquer que les fonctions de déplacement dans le texte
    et d'affichage d'une page ne manipulent que des indicateurs
    de position dans le texte.

    La fonction affligne reste dans le fichier source principal de
    chaque application, ce qui permet d'avoir un affichage adapté
    aux données à traiter.
*/

#define modepage  // pour la déclaration de variables globales à l'application

#include <stdio.h>
#include "modepage.h"
#include "carspe.h"



/* réaffiche la page d'écran courante en tenant
   compte du changement de taille de la fenètre */

void affpage ()
{
    int i, j;


    // récupérer la taille de la fenêtre (qui peut avoir changé)
    lig_col ();

    // se positionner en haut d'écran et l'effacer
    debpage ();
    effpage ();

    // initialisation
    i = 1;
    j = lignecour - lignecran + 1;

    // réafficher toutes les lignes de la page
    while (i++ < lignepage && j < nb_lignes)
    {
        affligne (j++);
        putchar ('\n');
    }

    // remonter à la ligne sur laquelle on était
    while (--i > lignecran)
        montecurs ();
}



/* remonte de n lignes (max) dans le texte affiché */

void monte (int n)
{
    // limiter le déplacement pour ne pas sortir du texte
    if (n > lignecour)
        n = lignecour;

    // tant qu'on n'est pas en haut de page et déplacement non terminé
    while (n > 0 && lignecran > 1)
    {
        // remonter d'une ligne
        montecurs ();

        // et mettre à jour les variables
        lignecran --;
        lignecour --;
        n--;
    }

    // si déplacement de plus d'une page
    if (n > lignepage)
    {
        // on n'affichera pas les lignes intermédiaires
        lignecour = lignecour + lignepage - n;
        n = lignepage;
    }

    // tant que déplacement non terminé
    while (n-- > 0)
    {
        // descendre le texte affiché d'une ligne
        insligne ();

        // et afficher la ligne à rajouter en haut d'écran
        affligne (--lignecour);
        putchar ('\r');
    }
}



/* descend de n lignes (max) dans le texte affiché */

void descend (int n)
{
    // limiter le déplacement pour ne pas sortir du texte
    if (n > nb_lignes - lignecour - 1)
        n = nb_lignes - lignecour - 1;

    // tant qu'on n'est pas en bas de page et déplacement non terminé
    while (n > 0 && lignecran < lignepage - 1)
    {
        // descendre d'une ligne
        putchar ('\n');

        // et mettre à jour les variables
        lignecran ++;
        lignecour ++;
        n--;
    }

    // si déplacement de plus d'une page
    if (n > lignepage)
    {
        // on n'affichera pas les lignes intermédiaires
        lignecour = lignecour + n - lignepage;
        n = lignepage;
    }

    // tant que déplacement non terminé
    while (n-- > 0)
    {
        // afficher la ligne à rajouter en bas de page
        // et remonter tout le texte d'une ligne
        putchar ('\n');
        affligne (++lignecour);
        putchar ('\n');

        // remonter sur la ligne insérée
        montecurs ();
    }
}



/* récupère le nombre de lignes et de colonnes d'affichage */

void lig_col ()
{
    char commande [28];
    FILE *fcaract;


    // récupérer les caractéristiques du terminal
    sprintf (commande, "stty size > /tmp/fich%X", getpid ());
    system (commande);

    // ouvrir le fichier créé par la commande  stty
    fcaract = fopen (commande + 12, "r");

    // si ouverture réussie
    if (fcaract)
    {
        // lire le nombre de lignes et de colonnes
        fscanf (fcaract, "%d%d", &lignepage, &colonpage);

        // fermer et détruire le fichier
        fclose (fcaract);
        unlink (commande + 12);
    }
    // cas très particulier : problème de droits d'accès à /tmp
    else
    {
        // message d'avertissement
     // "Droit d'accès insuffisants à /tmp, le fonctionnement peut être dégradé"
        affiche_msg ("PB_ACCES_TMP");
        sleep (3);

        // on prend les valeurs par défaut
        lignepage = defaut_ligne;
        colonpage = defaut_colon;
    }

    // corriger avec des valeurs par défaut si l'on a récupéré des 0
    // (par exemple depuis une fenêtre telnet)
    if (! lignepage)
        lignepage = defaut_ligne;

    if (! colonpage)
        colonpage = defaut_colon;
}



/* lit un caractère au clavier et le traite si caractère spécial */

int leccar ()
{
    int car, carsuiv;

    // attendre qu'un caractère soit tapé
    do
        car = getchar ();
    while (car == -1);

    // si caractère ordinaire, on le retourne
    if (car != ESC)
        return (car);

    // lire le caractère qui suit le ESC
    car = getchar ();

    // traitement du caractère ESC et des séquences d'échappement
    if (car == '[' || car == 'O')
    {
        car = getchar ();

        if ('1' <= car && car <= '9')
        {
            // séquence  ESC[n~  où  n  est une valeur numérique
            carsuiv = getchar ();
            car = car & 0x0F;

            // récupérer la valeur numérique
            while ('0' <= carsuiv && carsuiv <= '9')
            {
                car = (car * 10) + (carsuiv & 0x0F);
                carsuiv = getchar ();
            }

            if (carsuiv == '~')
                return (CARSPE | car);
            else
                // "Caractère spécial non traité"
                affiche_msg ("CARSPE_INVALIDE");
        }
        else if (car == '[')
        {
            // séquence  ESC[[n  (certaines touches de fonction)
            car = getchar ();
            return (CARSPE + 0x0F + car);
        }
        else
            // séquence  ESC[lettre
            return (CARSPE | car);
    }

    // caractère ESC classique
    else
    {
        // si après le ESC on a eu un autre caractère de suite
        // le remettre dans le buffer
        if (car != -1)
            ungetc (car, stdin);

        // retour du caractère ESCape
        return (ESC);
    }
}



/* exécute une commande, puis repasse en mode page */

void execom (char *outil, char *fichier)
{
    char commande [130];    // chaine contenant la commande à exécuter
    unsigned long heuredeb; // pour détecter problème exécution commandes


    // effacer le bas de page
    effpage ();
    fflush (stdout);

    // fabriquer la commande à éxécuter
    sprintf (commande, "%s %s", outil, fichier);

    // récupérer l'heure courante
    heuredeb = time (0);

    // lancer la commande
    system (commande);

    // si la commande a rendu la main trop rapidement
    // et que c'est une commande interactive
    if ((time (0) <= heuredeb + 1) && (strcmp (outil, "lpr") != 0)
                                   && (strcmp (outil, "recuppj") != 0))
    {
        // attendre lecture du message d'erreur
        sleep (2);
    }

    // reconfigurer la voie que commande a remit en mode normal en se terminant
    mode_raw ();
}
