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

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

MODULE void starify(void);
MODULE void bizarre(void);

AGLOBAL UBYTE* StarBufferPtr[MAXELEMENTS + 1];
AGLOBAL ULONG  StarBufferSize[MAXELEMENTS + 1];

AGLOBAL struct AutodocStruct autodoc =
{   0, "", "", "",
  { { "", "", "" },
    { "", "", "" },
    { "", "", "" },
    { "", "", "" },
    { "", "", "" },
    { "", "", "" },
    { "", "", "" },
    { "", "", "" },
    { "", "", "" }
} };

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];
AGLOBAL ULONG         returncode, inputs;

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

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

    navigate();

    /* 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
        );
    }

    /* output */
    if (!(shared.output[0]))
        strcpy(shared.output, "RAM:.autodoc");
    setgadget(242, 220, 240, 12, "_Output pathname:", NULL);
    ST99_Output = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        GTST_String, &(shared.output),
        GTST_MaxChars, LONGFIELD,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );
    /* output... */
    setgadget(484, 220, 28, 12, "_...", NULL);
    BU99_OutputASL = PrevGadPtr = (struct Gadget *) CreateGadget
    (   BUTTON_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );

    newwindow
    (   640, AUTODOC1HEIGHT,
        "Report+: Autodocs Entry",
        BUTTONIDCMP | STRINGIDCMP
    );
    loop();
    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
        );
    }
    strcpy
    (   shared.output,
        ((struct StringInfo *) ST99_Output->SpecialInfo)->Buffer
    );
    closewindow();
}

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

    navigate();
    newwindow
    (   640, AUTODOC2HEIGHT,
        "Report+: Autodocs Finished",
        BUTTONIDCMP
    );

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

    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;

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

    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[inputs + 1]);
        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[inputs + returncode + 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[inputs + returncode + 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[inputs + returncode + 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[inputs + returncode + 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"
    );

    autodoc_exit();
    writeout(shared.output);
    if (wbval <= 43)
        launcheditor();

    strcpy(temp, "Completed autodoc is ");
    strcat(temp, shared.output);
    strcat(temp, ".");
    say(temp, WHITE);

    loop();
    closewindow();
}

MODULE void starify(void)
{   ULONG i, j, length, where;
    ABOOL done;

    for (i = 0; i <= elements; i++)
    {   // 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 (*(textBuffer[i] + length) == LF)
                StarBufferSize[i] += 4;
            elif (*(textBuffer[i] + length) == 0)
                done = TRUE;
            StarBufferSize[i]++;
            length++;
        }

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

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

AGLOBAL void autodoc_exit(void)
{   ULONG i;

    for (i = 0; i <= MAXELEMENTS; i++)
        if (StarBufferPtr[i])
        {   FreeMem(StarBufferPtr[i], StarBufferSize[i]);
            StarBufferPtr[i] = NULL;
        }
    for (i = 0; i <= elements; i++)
    {   if (textBuffer[i])
            FreeVec((APTR) textBuffer[i]);
        textBuffer[i] = NULL;
}   }

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, textBuffer[i]);
            } else
            {   strcat(line, "!");          // 16:  "#   <argname1><spaces> - <buffer1>"
            }
            strcat(line, "\n");             // 16:  "#   <argname1><spaces> - <buffer1>\n"
    }   }
    strcat(IOBuffer, line);
}

AGLOBAL void autodoc_init(void)
{   ULONG i;

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

AGLOBAL void autodoc_loop(ULONG class, struct Gadget* addr, UWORD code)
{   if (page == 41)
    {   if (class == IDCMP_VANILLAKEY)
        {   code = toupper(code);
            if (code == ESCAPE)
            {   page = 0;
            } elif (code == 'F')
            {   page = 42;
            } elif (code == 'O')
            {   ActivateGadget(ST99_Output, MainWindowPtr, NULL);
            } elif (code == '.')
            {   asl();
                GT_SetGadgetAttrs
                (   ST99_Output,
                    MainWindowPtr,
                    NULL,
                    GTST_String, aslresult,
                    TAG_DONE
                );
            } 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 (class == IDCMP_GADGETUP)
        {   if (addr == BU99_Left)
            {   page = 0;
            } elif (addr == BU99_Right)
            {   page = 42;
            } elif (addr == BU99_OutputASL)
            {   asl();
                GT_SetGadgetAttrs
                (   ST99_Output,
                    MainWindowPtr,
                    NULL,
                    GTST_String, aslresult,
                    TAG_DONE
                );
            } elif (addr == ST99_Output)
            {   strcpy
                (   shared.output,
                    ((struct StringInfo *) ST99_Output->SpecialInfo)->Buffer
                );
    }   }   }
    elif (page == 42)
    {   if (class == IDCMP_GADGETUP)
        {   if (addr == BU99_Right)
            {   page = 0;
        }   }
        elif (class == ESCAPE)
        {   page = 0;
}   }   }
