#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <libraries/gadtools.h>

#include <stdlib.h>
#include "amigan.h"

MODULE void bizarre(void);
MODULE void updateautodocgadgets(void);
MODULE void readautodocgadgets(void);
MODULE void starify(ULONG index, STRPTR buffer);
MODULE void countfields(void);

AGLOBAL UBYTE*               StarBufferPtr[MAXELEMENTS + 1];
AGLOBAL ULONG                StarBufferSize[MAXELEMENTS + 1],
                             returncode,
                             inputs;
AGLOBAL struct AutodocStruct autodoc;

MODULE struct Gadget *ST41_Library            = NULL,
                     *ST41_Function           = NULL,
                     *ST41_Desc               = NULL,
                     *IN41_Version            = NULL,
                     *TE41_Label              = NULL,
                     *ST41_VarType[9],
                     *ST41_VarName[9],
                     *ST41_VarReg[9];

IMPORT struct NewGadget    Gadget;
IMPORT struct Window*      MainWindowPtr;
IMPORT struct SharedStruct shared;
IMPORT struct Gadget      *BU99_Right,
                          *BU99_TextEditor,
                          *GListPtr,
                          *PrevGadPtr;
IMPORT SBYTE               page;
IMPORT SWORD               y;
IMPORT TEXT                aslresult[MEDFIELD + 1],
                           IOBuffer[LONGESTFIELD + 1];
IMPORT ULONG               wbval, elements;

AGLOBAL void autodoc1(void)
{   TEXT  temp[MEDFIELD + 1], string[9][MEDFIELD + 1];
    UBYTE i;

    verynewwindow
    (   AUTODOCWIDTH, AUTODOCHEIGHT,
        "Report+: Autodocs Entry",
        BUTTONIDCMP | STRINGIDCMP
    );
    OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_NEW,    NOSUB));
    // OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_OPEN,   NOSUB));
    OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVE,   NOSUB));
    OnMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVEAS, NOSUB));

    /* library */
    setgadget(128, 24, 200, 12, "module._type:", PLACETEXT_LEFT);
    ST41_Library = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        GTST_String, autodoc.library,
        GTST_MaxChars, MEDFIELD,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );

    /* version */
    setgadget(544, 24, 64, 12, "Minimum _version:", PLACETEXT_LEFT);
    IN41_Version = PrevGadPtr = (struct Gadget *) CreateGadget
    (   INTEGER_KIND,
        PrevGadPtr,
        &Gadget,
        GTIN_Number, autodoc.version,
        GTST_MaxChars, MEDFIELD,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );

    /* function */
    setgadget(128, 38, 200, 12, "Function_Name:", PLACETEXT_LEFT);
    ST41_Function = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        GTST_String, autodoc.function,
        GTST_MaxChars, MEDFIELD,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );

    /* description */
    setgadget(128, 52, 480, 12, "_Description:", PLACETEXT_LEFT);
    ST41_Desc = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
	PrevGadPtr,
	&Gadget,
        GTST_String, autodoc.description,
	GTST_MaxChars, VLONGFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* variable type */
    setgadget(128, 72, 158, 1, "Type", PLACETEXT_BELOW);
    TE41_Label = PrevGadPtr = (struct Gadget *) CreateGadget
    (   TEXT_KIND,
	PrevGadPtr,
	&Gadget,
	TAG_DONE
    );

    strcpy(string[0], "_Return code:");
    for (i = 1; i <= 8; i++)
    {   strcpy(string[i], "Argument _");
        stci_d(temp, i);
        strcat(string[i], temp);
        strcat(string[i], ":");
    }
    for (i = 0; i <= 8; i++)
    {   setgadget(128, 88 + (i * 14), 158, 12, string[i], PLACETEXT_LEFT);
        ST41_VarType[i] = PrevGadPtr = (struct Gadget *) CreateGadget
        (   STRING_KIND,
            PrevGadPtr,
            &Gadget,
            GTST_String, &(autodoc.var[i].type),
            GTST_MaxChars, MEDFIELD,
            GA_TabCycle, TRUE,
            GT_Underscore, '_',
            TAG_DONE
        );
        if (i == 0)
            setgadget(288, 88 + (i * 14), 256, 12, "Name", PLACETEXT_ABOVE);
        else setgadget(288, 88 + (i * 14), 256, 12, NULL, NULL);
        ST41_VarName[i] = PrevGadPtr = (struct Gadget *) CreateGadget
        (   STRING_KIND,
            PrevGadPtr,
            &Gadget,
            GTST_String, &(autodoc.var[i].name),
            GTST_MaxChars, MEDFIELD,
            GA_TabCycle, TRUE,
            TAG_DONE
        );
        if (i == 0)
            setgadget(544, 88 + (i * 14), 64, 12, "Register", PLACETEXT_ABOVE);
        else setgadget(544, 88 + (i * 14), 64, 12, NULL, NULL);
        ST41_VarReg[i] = PrevGadPtr = (struct Gadget *) CreateGadget
        (   STRING_KIND,
            PrevGadPtr,
            &Gadget,
            GTST_String, &(autodoc.var[i].reg),
            GTST_MaxChars, MEDFIELD,
            GA_TabCycle, TRUE,
            TAG_DONE
        );
    }

    /* text editor... */
    setgadget(250, 220, 140, 12, "Text ed_itor...", NULL);
    BU99_TextEditor = PrevGadPtr = (struct Gadget *) CreateGadget
    (   BUTTON_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );

    /* There are 47 gadgets:
     1 BU99_Right
     1 BU99_TextEditor
     2 ST41_Library
     2 IN41_Version
     2 ST41_Function
     2 ST41_Desc
     1 TE41_Label
    18 ST41_VarType[9]
     9 ST41_VarName[9]
     9 ST41_VarReg[[9] */
    drawgadgets(47);

    loop();
    readautodocgadgets();
    closewindow();
}

AGLOBAL void saveautodoc(ABOOL saveas)
{   ULONG i, j;
    TEXT  temp[MEDFIELD + 1];
    SWORD size;

    readautodocgadgets();

    countfields();
    // As you can see, returncode and inputs need to be correct BEFORE
    // launcheditor() is called.

    if (wbval <= 43)
        say("Writing...", BLACK);
    else
    {   launcheditor();

        /* StarBufferPtr[]s are as follows:
        0: Function
        1: Example
        2: Notes
        3: Bugs
        4: See also
        5: Return code
     6-13: Inputs */

        for (i = 0; i <= 4; i++)
        {   starify(i, autodoc.textfield[i]);
        }
        if (returncode)
        {   starify(5, autodoc.var[0].desc);
        }
        if (inputs)
        {   for (i = 1; i <= inputs; i++)
            {   starify(5 + i, autodoc.var[i].desc);
    }   }   }
    
    strcpy(IOBuffer, "/" "****** ");        //  1:  "/###### "
    strcat(IOBuffer, autodoc.library);      //  1:  "/###### <library>"
    strcat(IOBuffer, "/");                  //  1:  "/###### <library>/"
    strcat(IOBuffer, autodoc.function);     //  1:  "/###### <library>/<function>"
    strcat(IOBuffer, " ");                  //  1:  "/###### <library>/<function> "

    size = 67 - strlen(autodoc.library) - strlen(autodoc.function);
    if (size > 0)
    {   for (i = 1; i <= size; i++)           
            strcat(IOBuffer, "*");          //  1:  "/###### <library>/<function> <stars>"
    }

    strcat(IOBuffer, "\n*\n*   NAME\n*   ");
                                            //  1:  "/###### <library>/<function> <stars>\n"
                                            //  2:  "#\n"
                                            //  3:  "#   NAME\n"
                                            //  4:  "#   "
    strcat(IOBuffer, autodoc.function);     //  4:  "#   <function>"
    strcat(IOBuffer, " -- ");               //  4:  "#   <function> -- "
    strcat(IOBuffer, autodoc.description);
                                            //  4:  "#   <function> -- <description>"
    if (autodoc.version)
    {   strcat(IOBuffer, " (V");            //  4:  "#   <function> -- <description>[ (V]"
        stcl_d(temp, autodoc.version);
        strcat(IOBuffer, temp);             //  4:  "#   <function> -- <description>[ (V<version>]"
        strcat(IOBuffer, ")");              //  4:  "#   <function> -- <description>[ (V<version>)]
    }
    strcat(IOBuffer, "\n*\n*   SYNOPSIS\n");
                                            //  4:  "#   <function> -- <description>[ (V<version>)]\n"
                                            //  5:  "#\n"
                                            //  6:  "#   SYNOPSIS\n"

    // name line
    strcat(IOBuffer, "*   ");               //  7:  "#   "
    if (autodoc.var[0].name[0])
    {   strcat(IOBuffer, autodoc.var[0].name);
                                            //  7:  "#   [<returnname>]"
        strcat(IOBuffer, " = ");            //  7:  "#   [<returnname> = ]"
    }
    strcat(IOBuffer, autodoc.function);     //  7:  "#   [<returnname> = ]<function>"
    strcat(IOBuffer, "(");                  //  7:  "#   [<returnname> = ]<function>("

    for (i = 1; i <= 8; i++)
    {   if (autodoc.var[i].name[0])
        {   if (i >= 2)
                strcat(IOBuffer, ", ");
            strcat(IOBuffer, autodoc.var[i].name);
            size = strlen(autodoc.var[i].reg) - strlen(autodoc.var[i].name);
            if (size > 0)
                for (j = 1; j <= size; j++)
                    strcat(IOBuffer, " ");
        } else break;
    }
    strcat(IOBuffer, ")\n");                //  7:  "#   [<returnname> = ]<function>([<arglist>])\n"

    // register line
    strcat(IOBuffer, "*   ");               //  8:  "#   "
    if (autodoc.var[0].reg[0] && autodoc.var[0].name[0])
    {   strcat(IOBuffer, autodoc.var[0].reg);
                                            //  8:  "#   [<returnreg>]"
        size = strlen(autodoc.var[0].name) - strlen(autodoc.var[0].reg);
        if (size > 0)
            for (i = 1; i <= size; i++)
                strcat(IOBuffer, " ");      //  8:  "#   [<returnreg><spaces>]"
        strcat(IOBuffer, "   ");            //  8:  "#   [<returnreg><spaces>   ]"
    }
    size = strlen(autodoc.function);
    if (size >= 0) // this is no mistake
        for (i = 0; i <= size; i++)
            strcat(IOBuffer, " ");          //  8:  "#   [<returnreg><spaces>   ]<spaces>"

    for (i = 1; i <= 8; i++)
    {   if (autodoc.var[i].reg[0])
        {   if (i >= 2)
                strcat(IOBuffer, "  ");
            strcat(IOBuffer, autodoc.var[i].reg);
            size = strlen(autodoc.var[i].name) - strlen(autodoc.var[i].reg);
            if (size > 0)
                for (j = 1; j <= size; j++)
                    strcat(IOBuffer, " ");
    }   }
    strcat(IOBuffer, "\n");                 //  8:  "#   [<returnreg><spaces>   ]<spaces>[<reglist>]\n"

    strcat(IOBuffer, "*\n*   ");            //  9:  "#\n"
                                            // 10:  "#   "
    if (autodoc.var[0].type[0])
    {   strcat(IOBuffer, autodoc.var[0].type);
                                            // 10a: "#   <returntype>"
        strcat(IOBuffer, " ");              // 10a: "#   <returntype> "
    } else
        strcat(IOBuffer, "void ");          // 10b: "#   void "
    strcat(IOBuffer, autodoc.function);     // 10:  "#   <returntype>|void <function>"
    strcat(IOBuffer, "(");                  // 10:  "#   <returntype>|void <function>("
    if (!(autodoc.var[1].type))             // 10:  "#   <returntype>|void <function>([void]"
        strcat(IOBuffer, "void");
    else
    {   for (i = 1; i <= 8; i++)
        {   if (autodoc.var[i].type[0])
            {   if (i >= 2)
                    strcat(IOBuffer, ", ");
                strcat(IOBuffer, autodoc.var[i].type);
            } else break;
    }   }
    strcat(IOBuffer, ");\n*\n*   FUNCTION\n*   ");
                                            // 10:  "#   <returntype>|void <function>(void|<typelist>);\n"
                                            // 11:  "#\n"
                                            // 12:  "#   FUNCTION\n"
                                            // 13:  "#   "
    if (wbval >= 44)
        strcat(IOBuffer, StarBufferPtr[0]);
    else strcat(IOBuffer, "!");             // 13:  "#   <buffer>"
    strcat(IOBuffer, "\n*\n*   INPUTS\n");  // 13:  "#   <buffer>\n"
                                            // 14:  "#\n"
                                            // 15:  "#   INPUTS\n"

    bizarre();

    strcat(IOBuffer, "*\n*   RESULT\n*   ");
                                            // 17:  "#\n"
                                            // 18:  "#   RESULT\n"
                                            // 19:  "#   "
    if (!(autodoc.var[0].name[0]))
        strcat(IOBuffer, "NONE");           // 19a: "#   NONE"
    else
    {   strcat(IOBuffer, autodoc.var[0].name);
                                            // 19b: "#   <returnname>"
        strcat(IOBuffer, " - ");            // 19b: "#   <returnname> - "
        if (wbval >= 44)
            strcat(IOBuffer, StarBufferPtr[5]);
        else strcat(IOBuffer, "!");         // 19b: "#   <returnname> - <buffer>"
    }

    strcat
    (   IOBuffer,
        "\n*\n"                             // 19a: "#   NONE\n"
                                            // 19b: "#   <returnname> - <buffer>\n"
                                            // 20:  "#\n"
        "*   EXAMPLE\n*   "                 // 21:  "#   EXAMPLE\n"
                                            // 22:  "#   "
    );

    if (wbval >= 44)
        strcat(IOBuffer, StarBufferPtr[1]);
    else strcat(IOBuffer, "!");             // 22:  "#   <buffer>"
    strcat(IOBuffer, "\n*\n*   NOTES\n*   ");
                                            // 22:  "#   <buffer>\n"
                                            // 23:  "#\n"
                                            // 24:  "#   NOTES\n"
                                            // 25:  "#   "

    if (wbval >= 44)
        strcat(IOBuffer, StarBufferPtr[2]);
    else strcat(IOBuffer, "!");             // 25:  "#   <buffer>"
    strcat(IOBuffer, "\n*\n*   BUGS\n*   ");
                                            // 25:  "#   <buffer>\n"
                                            // 26:  "#\n"
                                            // 27:  "#   BUGS\n"
                                            // 28:  "#   "
    if (wbval >= 44)
        strcat(IOBuffer, StarBufferPtr[3]);
    else strcat(IOBuffer, "!");             // 28:  "#   <buffer>"
    strcat(IOBuffer, "\n*\n*   SEE ALSO\n*   ");
                                            // 28:  "#   <buffer>\n"
                                            // 29:  "#\n"
                                            // 30:  "#   SEE ALSO\n"
                                            // 31:  "#   "

    if (wbval >= 44)
        strcat(IOBuffer, StarBufferPtr[4]);
    else strcat(IOBuffer, "!");             // 31:  "#   <buffer>"

    strcat
    (   IOBuffer,
        "\n*\n"                             // 31:  "#   <buffer>\n"
                                            // 32:  "#\n"
        "*****************************************************************************\n"
                                            // 33:  "<77 stars>\n"
        "*\n*"                              // 34:  "#\n"
                                            // 35:  "#"
        "/\n"                               // 35:  "#/\n"
    );

    // if wbval <= 43 then StarBufferPtr[]s should be NULL anyway
    for (i = 0; i <= MAXELEMENTS; i++)
    {   if (StarBufferPtr[i])
        {   FreeMem(StarBufferPtr[i], StarBufferSize[i]);
            StarBufferPtr[i] = NULL;
    }   }
    // That was done as soon as possible, and also before anything that
    // might fail.

    if (!autodoc.output[0] || saveas) // if we need a filename
    {   saveasl("Save Autodoc");
        strcpy(autodoc.output, aslresult);
    }
    if (autodoc.output[0]) // if ASL was not cancelled
    {   writeout(autodoc.output);
}   }

MODULE void bizarre(void)
{   // Service routine for autodoc2().

    ULONG i, j;
    SWORD size, longest = 0, thislength; // must be signed
    TEXT  line[VLONGFIELD + 1]; // better not make it too large, as it is
                                // a local (stack) variable.

    if (!inputs)
    {   strcpy(line, "*   NONE\n");         // 16:  "#   NONE\n"
    } else
    {   for (i = 1; i <= inputs; i++)
        {   thislength = strlen(autodoc.var[i].name);
            if (thislength > longest)
            {   longest = thislength;
        }   }

        for (i = 1; i <= inputs; i++)
        {   strcpy(line, "*   ");           // 16:  "#   "
            strcat(line, autodoc.var[i].name);
                                            // 16:  "#   <argname1>"
            thislength = strlen(autodoc.var[i].name);
            size = longest - thislength;
            if (size > 0)
            {   for (j = 1; j <= size; j++)
                {    strcat(line, " ");     // 16:  "#   <argname1><spaces>"
            }   }
            strcat(line, " - ");            // 16:  "#   <argname1><spaces> - "
            if (wbval >= 44)
            {   strcat(line, StarBufferPtr[5 + i]);
            } else
            {   strcat(line, "!");          // 16:  "#   <argname1><spaces> - <buffer1>"
            }
            strcat(line, "\n");             // 16:  "#   <argname1><spaces> - <buffer1>\n"
    }   }
    strcat(IOBuffer, line);
}

AGLOBAL void newautodoc(ABOOL display)
{   ULONG i;

    autodoc.version = 0;
    autodoc.loaded = FALSE;
    strcpy(autodoc.library,     "");
    strcpy(autodoc.function,    "");
    strcpy(autodoc.description, "");
    for (i = 0; i <= 8; i++)
    {   autodoc.var[i].name[0] = 0;
        autodoc.var[i].type[0] = 0;
        autodoc.var[i].reg[0]  = 0;
        autodoc.var[i].desc[0] = 0;
    }
    strcpy(autodoc.output,      "");

    if (display)
        updateautodocgadgets();
}

AGLOBAL void openautodoc(void)
{   // as you can see, this is not yet implemented!

    updateautodocgadgets();
}

AGLOBAL void autodoc_init(void)
{   ULONG i;

    // array clearing
    for (i = 0; i <= MAXELEMENTS; i++)
    {   StarBufferPtr[i] = NULL;
    }
    newautodoc(FALSE);
}

AGLOBAL void autodoc_loop(ULONG class, struct Gadget* addr, UWORD code)
{   if (class == IDCMP_VANILLAKEY)
    {   code = toupper(code);
        if (code == ESCAPE)
        {   page = 0;
        } elif (code == 'R')
        {   ActivateGadget(ST41_VarType[0], MainWindowPtr, NULL);
        } elif (code >= '1' && code <= '8')
        {   ActivateGadget(ST41_VarType[code - '1' + 1], MainWindowPtr, NULL);
        } elif (code == 'T')
        {   ActivateGadget(ST41_Library, MainWindowPtr, NULL);
        } elif (code == 'N')
        {   ActivateGadget(ST41_Function, MainWindowPtr, NULL);
        } elif (code == 'D')
        {   ActivateGadget(ST41_Desc, MainWindowPtr, NULL);
        } elif (code == 'V')
        {   ActivateGadget(IN41_Version, MainWindowPtr, NULL);
        } elif (code == 'I')
        {   if (wbval <= 43)
            {   saveautodoc(FALSE);
            }
            countfields();
            launcheditor();
    }   }
    elif (class == IDCMP_GADGETUP)
    {   if (addr == BU99_Right)
        {   page = 0;
        } elif (addr == BU99_TextEditor)
        {   if (wbval <= 43)
            {   saveautodoc(FALSE);
            }
            countfields();
            launcheditor();
}   }   }

MODULE void updateautodocgadgets(void)
{   ULONG i;

    GT_SetGadgetAttrs
    (   ST41_Library,
        MainWindowPtr,
        NULL,
        GTST_String, autodoc.library,
        TAG_DONE
    );
    GT_SetGadgetAttrs
    (   ST41_Function,
        MainWindowPtr,
        NULL,
        GTST_String, autodoc.function,
        TAG_DONE
    );
    GT_SetGadgetAttrs
    (   ST41_Desc,
        MainWindowPtr,
        NULL,
        GTST_String, autodoc.description,
        TAG_DONE
    );
    GT_SetGadgetAttrs
    (   IN41_Version,
        MainWindowPtr,
        NULL,
        GTIN_Number, autodoc.version,
        TAG_DONE
    );
    for (i = 0; i <= 8; i++)
    {   GT_SetGadgetAttrs
        (   ST41_VarType[i],
            MainWindowPtr,
            NULL,
            GTST_String, autodoc.var[i].type,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST41_VarName[i],
            MainWindowPtr,
            NULL,
            GTST_String, autodoc.var[i].name,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST41_VarReg[i],
            MainWindowPtr,
            NULL,
            GTST_String, autodoc.var[i].reg,
            TAG_DONE
        );
}   }

MODULE void readautodocgadgets(void)
{   ULONG i;

    strcpy
    (   autodoc.library,
        ((struct StringInfo *) ST41_Library->SpecialInfo)->Buffer
    );
    strcpy
    (   autodoc.function,
        ((struct StringInfo *) ST41_Function->SpecialInfo)->Buffer
    );
    strcpy
    (   autodoc.description,
        ((struct StringInfo *) ST41_Desc->SpecialInfo)->Buffer
    );
    autodoc.version = ((struct StringInfo *) IN41_Version->SpecialInfo)->LongInt;
    for (i = 0; i <= 8; i++)
    {   strcpy
        (   autodoc.var[i].type,
            ((struct StringInfo *) ST41_VarType[i]->SpecialInfo)->Buffer
        );
        strcpy
        (   autodoc.var[i].name,
            ((struct StringInfo *) ST41_VarName[i]->SpecialInfo)->Buffer
        );
        strcpy
        (   autodoc.var[i].reg,
            ((struct StringInfo *) ST41_VarReg[i]->SpecialInfo)->Buffer
        );
}   }

MODULE void starify(ULONG index, STRPTR buffer)
{   ULONG j, length, where;
    ABOOL done;

    // first we count the number of LFs in the source buffer, and the
    // length of the source buffer.
    length = 0;
    done = FALSE;
    while (!done)
    {   if (*(buffer + length) == LF)
            StarBufferSize[index] += 4;
        elif (*(buffer + length) == 0)
            done = TRUE;
        StarBufferSize[index]++;
        length++;
    }

    // now we allocate the buffer
    if (!(StarBufferPtr[index] = AllocMem(StarBufferSize[index], MEMF_PUBLIC)))
        rq("Out of memory!");

    // now we translate into new buffer
    where = 0;
    for (j = 0; j <= length; j++)
    {   *(StarBufferPtr[index] + where) = *(buffer + j);
        if (*(buffer + j) == LF)
        {   *(StarBufferPtr[index] + where + 1) = '*';
            *(StarBufferPtr[index] + where + 2) = ' ';
            *(StarBufferPtr[index] + where + 3) = ' ';
            *(StarBufferPtr[index] + where + 4) = ' ';
            where += 4;
        }
        where++;
}   }

MODULE void countfields(void)
{   ULONG i;

    readautodocgadgets();

    if (autodoc.var[0].name[0])
        returncode = 1; // non-boolean as it's used mathematically
    else returncode = 0;

    inputs = 0;
    for (i = 1; i <= 8; i++)
    {   if (autodoc.var[i].name[0])
            inputs++;
        else break;
}   }
