
#include <proto/graphics.h>
#include <proto/gadtools.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/utility.h>
#include <proto/asl.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifndef LINKLIB
    #include "proto/progargs.h"
#else
    #include "libraries/progargs.h"
    #include "clib/progargs_protos.h"
#endif

#ifdef DEBUGMODULE
    
    #include "support/debug.h"

#else

    void __stdargs kprintf(UBYTE *fmt,...);  // Serial debugging...
    void __stdargs dprintf(UBYTE *fmt,...);  // Parallel debugging...

    #ifndef bug
    #define bug Printf
    #endif

    #ifndef DEBTIME
    #define DEBTIME 0
    #endif

    #ifdef DEBUG
    #define D(x) (x); if(DEBTIME>0) Delay(DEBTIME);
    #else
    #define D(x) ;
    #endif

#endif

#define MIN_VERSION     37L             // minimum version number for our libs

long __oslibversion = MIN_VERSION;
char __stdiowin[] = "CON:0/10/640/200/ProgArgs Example 1";

#ifndef LINKLIB
struct Library *ProgArgsBase = NULL;
#endif

static void quit(UBYTE *err);
static void closedown(void);

/*********************************************
 **
 ** Routines for a clean exit, with optional error display
 **
 *********************************************/

static struct EasyStruct error_es = {
    sizeof(struct EasyStruct), 0,
    "ProgArgs Example1 Requester",
    "Problem during startup:\n%ls",
    "Quit"
};

static void quit(UBYTE *err)
{
    closedown();

    if(err != NULL) (void)EasyRequest(NULL,&error_es, NULL, err);

    _exit(0);
}

static void closedown(void)
{
    #ifndef LINKLIB
    if(ProgArgsBase) CloseLibrary(ProgArgsBase);
    #endif
}

/*********************************************
 **
 ** Identifiers for program arguments
 **
 *********************************************/

enum {
    ARG_String = (int)TAG_ARGENTRY+1,
    ARG_Number,
    ARG_Switch,
    ARG_Toggle,
    ARG_DefStr,
    ARG_DefNum,
    ARG_Multi,
    ARG_Clear
};

/*********************************************
 **
 ** Default values for a multi-argument type.
 ** (Name), (Directory lock), (Reserved)
 **
 *********************************************/

struct MultiArg DefMulti[] = {
    { "Multi1", NULL, NULL },
    { "Multi2", NULL, NULL },
    { "Multi3", NULL, NULL },
    { "Multi4", NULL, NULL },
    { NULL }
};

/*********************************************
 **
 ** Definitions of all program arguments.
 ** (ArgID), (Template), (Description),
 ** (Flags), (Default value), (Reserved)
 **
 *********************************************/

struct ArgEntry Keywords[] = {
    { ARG_String, "STRING=STR/K", "Just a silly generic string",
        0, NULL, NULL },
        
    { ARG_Number, "NUMBER=NUM/K/N", "A number, still generic",
        AEFLAG_HEXNUM, NULL, NULL },
        
    { ARG_Switch, "SWITCH=SW/K/S", "A basic switch",
        0, 0, NULL },
        
    { ARG_Toggle, "TOGGLE=TOG/K/T", "A toggle, click click click",
        AEFLAG_DEFAULT, 0, NULL },
        
    { ARG_DefStr, "DEFSTR=DSTR/K", "A string, but with a default",
        AEFLAG_DEFAULT, "DefString", NULL },
        
    { ARG_DefNum, "DEFNUM=DNUM/K/N", "A number that knows what it likes",
        AEFLAG_DEFAULT, (APTR)100, NULL },
        
    { ARG_Multi, "MULTI=MUL/M", "Expandable, flexible, ta-da!",
        AEFLAG_DEFAULT, &DefMulti[0], NULL },
        
    { ARG_Clear, "CLEAR=CLR/K/S", "Clear to default values",
        0, 0, NULL },
        
    { TAG_END }
};

/*********************************************
 **
 ** Print the values of all our argument IDs.
 ** [This should be made generic, but I'm lazy. ;)]
 **
 *********************************************/

void print_args(struct ProgArgs* pa)
{
    ULONG val;

    printf("  ARG_String = ");
    if(GetProgArgs(pa,ARG_String,&val,TAG_END)) printf("\"%ls\"\n",val);
    else printf("<nothing>\n");

    printf("  ARG_Number = ");
    if(GetProgArgs(pa,ARG_Number,&val,TAG_END)) printf("%ld\n",val);
    else printf("<nothing>\n");

    printf("  ARG_Switch = ");
    if(GetProgArgs(pa,ARG_Switch,&val,TAG_END)) printf("%ld\n",val);
    else printf("<nothing>\n");

    printf("  ARG_Toggle = ");
    if(GetProgArgs(pa,ARG_Toggle,&val,TAG_END)) printf("%ld\n",val);
    else printf("<nothing>\n");

    printf("  ARG_DefStr = ");
    if(GetProgArgs(pa,ARG_DefStr,&val,TAG_END)) printf("\"%ls\"\n",val);
    else printf("<nothing>\n");

    printf("  ARG_DefNum = ");
    if(GetProgArgs(pa,ARG_DefNum,&val,TAG_END)) printf("%ld\n",val);
    else printf("<nothing>\n");

    printf("  ARG_Clear = ");
    if(GetProgArgs(pa,ARG_Clear,&val,TAG_END)) {
        if(val) printf("%ld => Will write empty arguments.\n",val);
        else printf("%ld => Will write current values.\n",val);
    } else printf("<nothing>\n");

    printf("  ARG_Multi = ");
    if(GetProgArgs(pa,ARG_Multi,&val,TAG_END)) {
        struct MultiArg* multi = (struct MultiArg*)val;
        int i;
        
        printf("%lx\n",multi);
        i=0;
        while(multi->ma_String) {
            UBYTE buffer[512];
            printf("  #%d = (%ls)\n",i,multi->ma_String);
            NameFromLock(multi->ma_Directory,&buffer[0],500);
            printf("    CD = (%ls), Ext = %lx\n",&buffer[0],multi->ma_Ext);
            multi++;
            i++;
        }
    }
    else printf("<nothing>\n");
}

extern struct WBStartup *_WBenchMsg;

void __stdargs __main(char *line)
{
    struct ProgArgs* args;
    struct ProgArgs* file;
    UBYTE name[512];
    
#ifndef LINKLIB
    ProgArgsBase = OpenLibrary("progargs.library", 0);
    if (!ProgArgsBase)
       quit("Can't open progargs.library.");
    D(bug("Opened the library.  Testing...\n",NULL));
#endif
    
    printf("-------------------------------------------------------------\n");
    printf("Initial program info\n");
    printf("-------------------------------------------------------------\n");
    printf("  cmdline   = %ls\n",line);
    printf("  arguments = %ls\n",GetArgStr());

    GetProgramName(&name[0],500);
    printf("  prog name = %ls\n",&name[0]);
    
    #if 0
    {
        struct CSource cs;
        cs.CS_Buffer = line;
        cs.CS_Length = strlen(line);
        cs.CS_CurChr = 0;
        ReadItem(&name[0],500,&cs);
        printf("arg1 = %ls\n",&name[0]);
    }
    #endif
    
    #if 0
    strcpy(&name[0],"KEYWORD");
    for(i=0;i<19;i++) {
        for(j=0;j<6;j++) {
            printf("%ls ",&name[0]);
            next_sequence(&name[0]);
        }
        printf("\n");
    }
    #endif
    
    printf("\n-------------------------------------------------------------\n");
    printf("Basic parse of command/workbench arguments\n");
    printf("-------------------------------------------------------------\n");

    args = AllocProgArgs(&Keywords[0],
                         PA_WBStartup,      _WBenchMsg,     // Hand in WB startup
                         RPA_WBArguments,   ARG_Multi,      // Parse WB startup
                         PA_IgnoreError,    TRUE,           // Don't fail on next err
                         RPA_ProgIcon,      !_WBenchMsg,    // If no WB startup,
                                                            // read directly from icon
                         PA_IgnoreError,    FALSE,          // Allow fail on next err
                         RPA_CmdInput,      TRUE,           // Parse command line
                         TAG_END);

    if(!args) {
        quit("Unable to parse arguments.\n");
    }
    
    printf("  new arguments = %ls\n",GetArgStr());

    printf("  Parsed arguments:\n");
    printf("  ~~~~~~~~~~~~~~~~\n");
    print_args(args);

    printf("\n-------------------------------------------------------------\n");
    printf("Parse of a text file, modified by command/workbench arguments\n");
    printf("-------------------------------------------------------------\n");

    file = AllocProgArgs(&Keywords[0],TAG_END);

    if(!file) {
        FreeProgArgs(args);
        quit("Unable to open file ProgArgs.\n");
        exit(20);
    }
    
    if( !ExecProgArgs(file,
                      PA_SetDirectory,  PADIR_CURRENT,  // Move to current dir
                      PA_IgnoreError,   TRUE,           // Ignore any errors.
                      RPA_TextFileName, "TestArgsData.txt", // Try to read file
                      RPA_CmdLine,      GetArgStr(),    // Parse cmd line, without
                                                        // any interaction
                      TAG_END) ) {
        printf("==> Unable to read file.\n");
    }
    
    printf("  Parsed arguments:\n");
    printf("  ~~~~~~~~~~~~~~~~\n");
    print_args(file);
    
    printf("\nWriting basic arguments to program icon...\n");
    if( !ExecProgArgs(args,
                       PA_AllComments, GetTagData(ARG_Clear,FALSE,args->pa_Arguments),
                       WPA_ProgIcon, TRUE,
                       TAG_END) ) printf("==> Error!\n");
    
    printf("Writing text file \"TestArgsData.txt\" to disk...\n");
    if( !ExecProgArgs(file,
                      PA_SetDirectory,  PADIR_CURRENT,
                      WPA_TextFileName, "TestArgsData.txt",
                      TAG_END) ) printf("==> Error!\n");
    
    printf("Writing defaults file \"TestDefsData.txt\" to disk...\n");
    if( !ExecProgArgs(file,
                      PA_SetDirectory,  PADIR_CURRENT,
                      PA_AllComments,   TRUE,
                      WPA_TextFileName, "TestDefsData.txt",
                      TAG_END) ) printf("==> Error!\n");
    
    printf("Writing text file \"ENV:TestDir/TestArgsData.txt\" to\n");
    printf("disk and to archive directory...\n");
    if( !ExecProgArgs(file,
                      PA_SetDirectory,  PADIR_ENVARC,
                      PA_CreateDirs,    TRUE,
                      WPA_TextFileName, "TestDir/TestArgsData.txt",
                      TAG_END) ) printf("==> Error!\n");
    
    FreeProgArgs(file);
    FreeProgArgs(args);
    
    printf("Done.\n");
    quit(NULL);
}

