
/*******************************************************************************/
/* Copyright (C) 2008 Jonathan Moore Liles                                     */
/*                                                                             */
/* This program is free software; you can redistribute it and/or modify it     */
/* under the terms of the GNU General Public License as published by the       */
/* Free Software Foundation; either version 2 of the License, or (at your      */
/* option) any later version.                                                  */
/*                                                                             */
/* This program is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       */
/* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for   */
/* more details.                                                               */
/*                                                                             */
/* You should have received a copy of the GNU General Public License along     */
/* with This program; see the file COPYING.  If not,write to the Free Software */
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
/*******************************************************************************/

#include "Fl_Menu_Settings.H"

#include <string.h>

/* code to dump and restore (portions of) an Fl_Menu_ */

#define MAX_PATH 1024

void
Fl_Menu_Settings::remove_ampersands ( char *str, int n )
{
    char *d = str;
    char *s = str;

    while ( n-- )
    {
        if ( *s == '&' )
        {
            ++s;
            continue;
        }

        *(d++) = *(s++);
    }

    *d = '\0';
}

void
Fl_Menu_Settings::indent ( FILE *fp, int n )
{
    while ( n-- )
        fprintf( fp, "\t" );
}

int
Fl_Menu_Settings::item_pathname_x ( char *path, int n, const Fl_Menu_Item *item )
{
    int r = Fl_Menu_::item_pathname( path, n, item );

    remove_ampersands( path, n );

    return r;
}

/** dump options from submenu /menu/ of menubar /bar/ to file /fp/ */
const Fl_Menu_Item *
Fl_Menu_Settings::dump ( Fl_Menu_ *bar, const Fl_Menu_Item *menu, FILE *fp, int depth )
{
    static char path[256];
    const Fl_Menu_Item *m = menu;

    for ( ; m->text; ++m )
    {
        bool is_radio = false;

        if ( m->flags & FL_SUBMENU )
//      if ( m->submenu() )
        {
            strcpy( path, m->text );
            remove_ampersands( path, strlen( path ) );

            indent( fp, depth );
            fprintf( fp, "%s\n", path );

            /* recurse */
            m = dump( bar, ++m, fp, depth + 1 );

//            ++m;

//            m = dump( bar, m->flags & FL_SUBMENU_POINTER ? (Fl_Menu_Item*) m->user_data() : m, fp, depth + 1 );

            if ( ! depth )
                break;
            else
                continue;
        }

        if ( m->radio() )
            is_radio = true;

//        bar->item_pathname( path, sizeof( path ) - 1, m );
        item_pathname_x( path, sizeof( path ) - 1, m );


        if ( m->flags & FL_MENU_TOGGLE || m->flags & FL_MENU_RADIO )
        {
            if ( ! is_radio )
            {
                indent( fp, depth );

                fprintf( fp, "%s\n", rindex( path, '/' ) + 1 );

                indent( fp, depth + 1 );

                fprintf( fp, "%s\n", m->flags & FL_MENU_VALUE ? "true" : "false" );
            }
            else if ( m->flags & FL_MENU_VALUE )
            {
                *rindex( path, '/' ) = '\0';

                indent( fp, depth );

                fprintf( fp, "%s\n", path + strlen( path ) + 1  );
            }
        }

    }

    return m;
}

/** dump menu to file /name/ starting at /item. */
int
Fl_Menu_Settings::dump ( const Fl_Menu_Item *item, const char *name )
{
    FILE *fp = fopen( name, "w" );

    if ( ! fp )
        return false;

    dump( this, item, fp, 0 );

    fclose( fp );


    return true;
}

#define strlcat strncat

/* taken from Fl_Menu_.cxx and modified to ignore hotkeys and case */
const Fl_Menu_Item *
Fl_Menu_Settings::find_item_x ( const char *name, const Fl_Menu_Item *item )
{
    char menupath [ MAX_PATH ] = "";			// File/Export

    const Fl_Menu_Item *m = item ? item : menu();

    int depth = 0;

    while ( depth >= 0 )
        for ( ;m ; ++m )
        {
            if ( m->flags & FL_SUBMENU )
            {
                // IT'S A SUBMENU
                // we do not support searches through FL_SUBMENU_POINTER links
                if ( menupath[0] )
                    strlcat( menupath, "/", sizeof( menupath ) );

                strlcat( menupath, m->label(), sizeof( menupath ) );

                remove_ampersands( menupath, strlen( menupath ) );

                if ( ! strcasecmp( menupath, name ) )
                    return m;
                else
                {
                    ++depth;
                    continue;
                }
            }
            else
            {
                if ( ! m->label() )
                {
                    // END OF SUBMENU? Pop back one level.
                    char *ss = strrchr( menupath, '/' );
                    if ( ss )
                        *ss = 0;
                    else
                        menupath[0] = '\0';

                    --depth;
                    ++m;

                    break;
                }

                // IT'S A MENU ITEM
                char itempath[ MAX_PATH ];                // eg. Edit/Copy
                strcpy( itempath, menupath );

                if ( itempath[0] )
                    strlcat( itempath, "/", sizeof( itempath ) );

                strlcat( itempath, m->label(), sizeof( itempath ) );

                remove_ampersands( itempath, strlen( itempath ) );

                if ( !strcasecmp( itempath, name ) )
                    return m;
            }
        }

    return ( Fl_Menu_Item * )0;
}


static void
path_push ( char *path, const char *s )
{
    strcat( path, s );
    strcat( path, "/" );
}

static void
path_pop ( char *path )
{
    char *s;

    int l = strlen( path );

    if ( ! l )
        return;

    if ( path[ l - 1 ] == '/' )
        path[ l - 1 ] = '\0';

    s = rindex( path, '/' );

    if ( s )
        *(s + 1) = '\0';
    else
        *path = '\0';
}

void
Fl_Menu_Settings::load ( Fl_Menu_ *bar, const Fl_Menu_Item *item, FILE *fp, int depth, char *path, int pmax )
{
    char line[256];

    while ( ! feof( fp ) )
    {
        *line = '\0';

        fgets( line, sizeof( line ), fp );

        if ( *line == '#' )
            continue;

        line[ strlen( line ) - 1 ] = '\0';

        int ld = strspn( line, "\t" );

        if ( ld > depth )
        {
            path_push( path, line + ld );

            ++depth;

//            load( bar, item, fp, depth + 1, path, pmax );
            /*  */;
        }
        else if ( ld < depth )
        {
            /* we should know the path and the value now */

            // path_pop( path );
            *rindex( path, '/' ) = '\0';

//            printf( "%s = %s\n", path, path + strlen( path ) + 1 );

            const Fl_Menu_Item *it = find_item_x( path, item + 1 );

            if ( it && it->radio() )                            /* radio button */
            {
                bar->picked( it );

                path_pop( path );
            }
            else                                                /* toggle */
            {
                *rindex( path, '/' ) = '\0';

                if ( ( it = find_item_x( path, item + 1 ) ) && it->checkbox() )
                {
                    int v = 0 == strcasecmp( "true", (path + strlen( path ) + 1 ) );

                    if ( v != ( it->value() != 0 ) /* grr, FLTK */ )
                        bar->picked( it );
                }

            }

            while ( ld < depth )
            {
                path_pop( path );
                depth--;
            }

            path_push( path, line + ld );
        }
        else                                          /* d == depth */
        {
            /* doesn't apply? */
        }
    }
}

/** load settings from file /name/ into menu starting at /item */
int
Fl_Menu_Settings::load ( const Fl_Menu_Item *item, const char *name )
{
    FILE *fp = fopen( name, "r" );

    if ( ! fp )
        return false;

    char path[ MAX_PATH ];
    path[0] = '\0';

    load( this, item, fp, 0, path, sizeof( path ) );

    fclose( fp );

    return true;
}
