/****************************************************************************
 *
 * MODULE:       g.mkfontcap
 * AUTHOR(S):    Paul Kelly
 * PURPOSE:      Generates the font configuration file by scanning various
 *               directories for GRASS stroke and Freetype-compatible fonts.
 *
 * COPYRIGHT:    (C) 2007-215 by the GRASS Development Team
 *
 *               This program is free software under the GNU General Public
 *               License (>=v2). Read the file COPYING that comes with GRASS
 *               for details.
 *
 *****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>

#include <grass/gis.h>
#include <grass/fontcap.h>
#include <grass/glocale.h>

#include "local_proto.h"

#ifdef HAVE_FT2BUILD_H
#include <ft2build.h>
#include FT_FREETYPE_H

static FT_Library ftlibrary;

static void find_fonts(const char *);

#endif /* HAVE_FT2BUILD_H */

/**
 * \brief Find Freetype fonts and store them in a global GFONT_CAP struct
 *
 * The directories specified by the global variables searchdirs and
 * numsearchdirs are recursively scanned to find all Freetype-compatible
 * fonts. As each font is found, information on it is transferred into
 * the global GFONT_CAP struct, fontcap, to be used by the main program.
 **/

void find_freetype_fonts(void)
{
#ifdef HAVE_FT2BUILD_H
    int i;

    if (FT_Init_FreeType(&ftlibrary) != 0)
        G_fatal_error(_("Unable to initialise Freetype"));

    for (i = 0; i < numsearchdirs; i++)
        find_fonts(searchdirs[i]);

    FT_Done_FreeType(ftlibrary);
#endif /* HAVE_FT2BUILD_H */
    return;
}

#ifdef HAVE_FT2BUILD_H

/**
 * \brief Recursively scans a specified directory and stores information on
 *        all font files found.
 *
 * Any directories found are recursively scanned in the same way as the
 * parent. Any files found are attempted to be opened using FT_New_Face()
 * to discover if they are valid font files or not. If they are, information
 * on all the font faces in each file is stored in the global GFONT_CAP
 * struct, fontcap, to be used by the main program. Recursive structure based
 * on lib/init/clean_temp.c by Roberto Flor.
 *
 * \param dirpath String containing directory to be scanned
 **/

static void find_fonts(const char *dirpath)
{
    char filepath[GPATH_MAX];
    DIR *curdir;
    struct dirent *cur_entry;
    struct stat info;

    curdir = opendir(dirpath);
    if (curdir == NULL)
        return;

    /* loop over current dir */
    while ((cur_entry = readdir(curdir))) {
        if (cur_entry->d_name[0] == '.')
            continue; /* Skip hidden files */

        sprintf(filepath, "%s%c%s", dirpath, HOST_DIRSEP, cur_entry->d_name);

        if (stat(filepath, &info))
            continue; /* File is unreadable */

        if (S_ISDIR(info.st_mode))
            find_fonts(filepath); /* Recurse into next directory */
        else {
            /* It's a file; we'll try opening it with Freetype to see if
             * it's a valid font. */
            FT_Long index, facesinfile;
            FT_Face face;

            index = facesinfile = 0;

            do {
                if (totalfonts >= maxfonts) {
                    maxfonts += 20;
                    fontcap =
                        G_realloc(fontcap, maxfonts * sizeof(struct GFONT_CAP));
                }

                G_debug(3, "find_fonts(): file=%s", filepath);
                if (FT_New_Face(ftlibrary, filepath, index, &face) == 0) {
                    if (index == 0)
                        facesinfile = face->num_faces;

                    /* Only use scalable fonts */
                    if (face->face_flags & FT_FACE_FLAG_SCALABLE) {
                        char *buf_ptr;

                        fontcap[totalfonts].path = G_store(filepath);
                        fontcap[totalfonts].index = index;
                        fontcap[totalfonts].type = GFONT_FREETYPE;
                        fontcap[totalfonts].encoding = G_store("utf-8");

                        if (strchr(filepath, HOST_DIRSEP))
                            buf_ptr = strrchr(filepath, HOST_DIRSEP) + 1;
                        else
                            buf_ptr = filepath;
                        if (strchr(buf_ptr, '.'))
                            *(strrchr(buf_ptr, '.')) = '\0';
                        if (index > 0)
                            G_asprintf(&fontcap[totalfonts].name, "%s%d",
                                       buf_ptr, (int)index);
                        else
                            fontcap[totalfonts].name = G_store(buf_ptr);

                        if (face->family_name &&
                            face->family_name >
                                (FT_String
                                     *)31) { /* avoid segfault on cygwin */
                            /* There might not be a style name but there will
                             * always be a family name. */
                            if (face->style_name == NULL)
                                fontcap[totalfonts].longname =
                                    G_store(face->family_name);
                            else
                                G_asprintf(&fontcap[totalfonts].longname,
                                           "%s %s", face->family_name,
                                           face->style_name);
                        }
                        else {
                            fontcap[totalfonts].longname = G_store("");
                        }
                        totalfonts++;
                    }

                    /* Discard this FT_Face structure and use it again */
                    FT_Done_Face(face);
                }
            } while (++index < facesinfile);
        }
    }

    closedir(curdir);

    return;
}

#endif /* HAVE_FT2BUILD_H */
