/*
**
** This is a small example using ini.library. It allows you to support
** user-configurable (gadtools) pulldown menus.
**
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <intuition/intuition.h>

#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>

#include "libraries/ini.h"
#include "clib/ini_protos.h"
#include "pragmas/ini_pragmas.h"

// small macro to loop through all entrys of a logical section
#define ini_Loop( HEADER, INFO ) for( INFO = (INILINEINFO *) (HEADER->node.ln_Succ); INFO->node.ln_Succ && INFO->flags != INIFLAG_HEADER; INFO = (INILINEINFO *) (INFO->node.ln_Succ) )

// built-in-commands descriptor
typedef struct BuiltInCommand
    {
        STRPTR name;
        LONG id;
        VOID (*function)(VOID);
    } COMMAND;

// example function
void about(void)
{
    printf("ini.library example for making menus configurable\n" );
}

// example commands
COMMAND BuiltIns[] =   
    {
        { "about", 1, about },
        { "quit", -1, 0 },
        { NULL, 0, NULL }
    };

// some global stuff
struct NewMenu *MenuDefinition = NULL;
struct Library *GadToolsBase = NULL;
struct GfxBase *GfxBase = NULL;
struct IniBase *IniBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;
struct Screen *screen = NULL;
struct Window *window = NULL;
struct Menu *menu = NULL;

ULONG sizeOfMenus;

// add title entry
void config_SetMenuTitle( struct NewMenu *nm, int offset, STRPTR string )
{
    nm[offset].nm_Type = NM_TITLE;
    nm[offset].nm_Label = strdup( string );
    nm[offset].nm_CommKey = NULL;
    nm[offset].nm_Flags = 0;
    nm[offset].nm_MutualExclude = 0L;
    nm[offset].nm_UserData = 0L;
} // config_AddMenuTitle()

// add item entry
void config_SetMenuItem( struct NewMenu *nm, int offset, STRPTR string, STRPTR hotkey, ULONG userID )
{
    nm[offset].nm_Type = NM_ITEM;
    nm[offset].nm_Label = strdup( string );
    nm[offset].nm_CommKey = hotkey ? strdup( hotkey ) : NULL;
    nm[offset].nm_Flags = 0;
    nm[offset].nm_MutualExclude = 0L;
    nm[offset].nm_UserData = (void *)userID;
} // config_SetMenuItem()

// add barlabel entry
void config_SetBarLabel( struct NewMenu *nm, int offset )
{
    nm[offset].nm_Type = NM_ITEM;
    nm[offset].nm_Label = NM_BARLABEL;
    nm[offset].nm_CommKey = NULL;
    nm[offset].nm_Flags = 0;
    nm[offset].nm_MutualExclude = 0L;
    nm[offset].nm_UserData = 0L;
} // config_SetBarLabel()

// add end-entry
void config_SetMenuEnd( struct NewMenu *nm, int offset )
{
    nm[offset].nm_Type = NM_END;
    nm[offset].nm_Label = NULL;
    nm[offset].nm_CommKey = NULL;
    nm[offset].nm_Flags = 0;
    nm[offset].nm_MutualExclude = 0L;
    nm[offset].nm_UserData = 0L;
} // config_SetMenuEnd()

// analyse item-entry syntax
BOOL syntax_MenuItem( STRPTR contents, STRPTR *string, STRPTR *hotkey, ULONG *id )
{
    char *cp; int i;

    *string = contents;
    if( ( cp = strchr( contents, ',' ) ) == NULL )
    {
        printf("Syntax error: missing string in \"%s\"\n", contents );
        return FALSE;    
    }
    *cp = 0;

    *hotkey = ++cp;
    if( ( cp = strchr( *hotkey, ',' ) ) == NULL )
    {
        printf("Syntax error: missing hotkey in \"%s\"\n", contents );
        return FALSE;            
    }
    *(cp++) = 0;

    for( i=0; BuiltIns[i].name; i++ )
    {
        if( !stricmp( BuiltIns[i].name, cp ) )
        {
            *id = BuiltIns[i].id;
            return TRUE;
        }
    }
    printf( "Syntax error: invalid function in \"%s\"\n", contents );
    return FALSE;
} // syntax_MenuItem()

// build menu
BOOL config_BuildMenus( char *iniName )
{
    INIPARSER parser;
    INILINEINFO *header,*info;
    int nrOfMenus = 20,i;
    
    sizeOfMenus = nrOfMenus * sizeof( struct NewMenu );

    // Allocate memory for NewMenus
    if( !( MenuDefinition = (struct NewMenu *) AllocMem( sizeOfMenus, MEMF_CLEAR ) ) )
        return FALSE;

    // try to load ini-file
    if( ini_New( iniName, &parser ) != INIERROR_NONE )
        return FALSE;

    // find header
    if( ( header = ini_GetHeader( &parser, "menus" ) ) == NULL )
    {
        // use default menu or (in our case) just fail
        printf("Sorry, header not found\n" );
        return FALSE;
    }
    else
    {
        i = 0;

        // loop through section
        ini_Loop( header, info )        
        {
            if( info->flags == INIFLAG_VARIABLE )
            {
                if( !stricmp( info->variable, "title" ) ) 
                {
                    config_SetMenuTitle( MenuDefinition,i++, info->contents );
                }
                else if( !stricmp( info->variable, "item" ) )
                {
                    char *string,*hotkey;
                    ULONG id;
                    
                    if( syntax_MenuItem( info->contents, &string, &hotkey, &id ) )
                        config_SetMenuItem( MenuDefinition, i++, string,hotkey,id );
                }
                else if( !stricmp( info->variable, "label" ) )
                {
                    config_SetBarLabel( MenuDefinition, i++ );
                }
            }
        }
        config_SetMenuEnd( MenuDefinition, i++ );
    }
    return TRUE;
} // BuildMenus()

void CloseLibrarys( void )
{
    if( IntuitionBase )
        CloseLibrary( (struct Library *)IntuitionBase );

    if( GfxBase )
        CloseLibrary( (struct Library *)GfxBase );

    if( GadToolsBase )
        CloseLibrary( (struct Library *)GadToolsBase );
     
    if( IniBase )
        CloseLibrary( (struct Library *)IniBase );
     
} // CloseLibrarys()

BOOL OpenLibrarys( void )
{
    if( (GadToolsBase = OpenLibrary("gadtools.library", 36L) ) != NULL )
    {
        if( (GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 36L) ) != NULL )
        {
            if( (IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 36L) ) != NULL )
            {
                if( (IniBase = (struct IniBase *) OpenLibrary("ini.library", 0L) ) != NULL )
                {
                    return TRUE;
                }
            }
        }
    }
    CloseLibrarys();
    return FALSE;
} // OpenLibrarys()

int main( void )
{
    struct IntuiMessage *imsg;
    APTR vi;

    if( OpenLibrarys() )
    {
        if( !config_BuildMenus( "config.ini" ) )
        {
            printf("SORRY, NO MENUS\n");
            return FALSE;
        }

        if( ( screen = LockPubScreen( NULL ) ) != NULL )
        {
            if( ( menu = CreateMenus( MenuDefinition,
                                        GTMN_FrontPen, 0, TAG_DONE ) ) != NULL )
            {
                vi = GetVisualInfo( screen, TAG_DONE );
                
                LayoutMenus( menu, vi, TAG_DONE );
    
                if( ( window = OpenWindowTags( NULL,
                                               WA_Width, 500, 
                                               WA_Height, 100,
                                               WA_Activate, TRUE,
                                               WA_DragBar, TRUE,
                                               WA_CloseGadget, TRUE,
                                               WA_DepthGadget, TRUE,
                                               WA_SmartRefresh, TRUE,
                                               WA_IDCMP, IDCMP_CLOSEWINDOW|IDCMP_MENUPICK,
                                               WA_Title, "INI-CONFIG",
                                               TAG_DONE ) ) != NULL )
                {
                    BOOL terminated = FALSE;
                    
                    SetMenuStrip( window, menu );
                    
                    while( !terminated )
                    {
                        Wait( 1<<window->UserPort->mp_SigBit );
                    
                        while( !terminated &&
                                   ( imsg = (struct IntuiMessage *)GetMsg( window->UserPort ) ) )
                        {
                            ULONG imsgClass = imsg->Class;
                            UWORD imsgCode = imsg->Code;
                            ReplyMsg( (struct Message *)imsg );
                                
                            if( imsgClass == CLOSEWINDOW ) terminated = TRUE;
                            else if( imsgClass == IDCMP_MENUPICK )
                            {
                                int i;
                                LONG id;
                                struct MenuItem *item;
                                
                                item = ItemAddress( menu, imsgCode );
                                id = (LONG)GTMENUITEM_USERDATA( item );

                                if( id == -1 )
                                    terminated = TRUE;
                                else
                                {
                                    for( i=0; BuiltIns[i].name; i++ )
                                    {
                                        if( BuiltIns[i].id == id )
                                        {
                                            printf("Found function %ld\n", id );
                                            if( BuiltIns[i].function )
                                                (*(BuiltIns[i].function))();
                                        }
                                    }
                                }
                            }
                        }
                    }
                    ClearMenuStrip( window );
                    CloseWindow( window );
                }
                FreeMenus( menu );
                FreeVisualInfo( vi );            
            }
            UnlockPubScreen( NULL, screen );
        }
        CloseLibrarys();
    }
    return 0;
}

