/* $Filename:    ReportPlus/Source/te.c
 * $VER:         Report+ 5.0
 * $Description: ReAction gadgets (text editor) for Report+
 *
 * © Copyright 2001 James R. Jacobs. Freely distributable.
 *        _
 *       //      -=AMIGA=-
 *      //
 * _   //
 * \\ //
 *  \X/
 *
 * Used only for functions 1 and 4. */

// system includes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <graphics/gfxbase.h>
#include <graphics/text.h>
#include <utility/tagitem.h>
#include <utility/hooks.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>

#include <proto/intuition.h>
#include <clib/graphics_protos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/utility.h>
#include <proto/wb.h>
#include <proto/icon.h>

#include <clib/alib_protos.h>
#include <clib/texteditor_protos.h>

// ReAction includes
#define ALL_REACTION_CLASSES
#define ALL_REACTION_MACROS
#include <reaction/reaction.h>

#include <gadgets/texteditor.h>
#include <pragmas/texteditor_pragmas.h>

#include "rp.h"

#define ASM    __asm
#define REG(x) register __ ## x

enum
{   GID_MAIN = 0,
    GID_TEXTEDITOR1,
    GID_TEXTEDITOR2,
    GID_TEXTEDITOR3,
    GID_TEXTEDITOR4,
    GID_TEXTEDITOR5,
    GID_TEXTEDITOR6,
    GID_TEXTEDITOR7,
    GID_TEXTEDITOR8,
    GID_TEXTEDITOR9,
    GID_TEXTEDITOR10,
    GID_TEXTEDITOR11,
    GID_TEXTEDITOR12,
    GID_TEXTEDITOR13,
    GID_TEXTEDITOR14,
    GID_DOWN,
    GID_UP,
    GID_OK,
    GID_LAST
};

enum
{   OID_MAIN = 0,
    OID_LAST
};

MODULE STRPTR               textBuffer[MAXELEMENTS + 1];

// from f4.c
IMPORT UBYTE*               StarBufferPtr[MAXELEMENTS + 1];
IMPORT ULONG                StarBufferSize[MAXELEMENTS + 1];

// from rp.c
IMPORT struct Library      *WindowBase,
                           *LayoutBase,
                           *ButtonBase,
                           *TextEditorBase,
                           *LabelBase;
IMPORT SBYTE                page;
IMPORT ULONG                elements;
IMPORT ULONG                returncode, inputs;
IMPORT APTR                 OldWindowPtr;
IMPORT struct Screen*       ScreenPtr;
IMPORT struct Process*      ProcessPtr;
IMPORT struct ReportStruct  report;
IMPORT struct AutodocStruct autodoc;
IMPORT struct NewGadget     Gadget; // only for the Gadget.ng_TextAttr field
IMPORT struct List          ResultList;

MODULE struct Gadget*       gadgets[GID_LAST];
MODULE        Object*       objects[OID_LAST];
MODULE ABOOL                done;
MODULE struct Window*       ReActionWindowPtr = NULL;

AGLOBAL void textedit(void)
{   struct MsgPort* AppPort;

    TEXT            GadTitle[MAXELEMENTS + 1][VLONGFIELD + 1];
    ULONG           i, theindex, wrapsize;

    struct TagItem  windowtag[12],
                    rootlayouttag[7],
                    bothlayouttag[8],
                    supercaptiontag[8],
                    subcaptiontag[3],
                    texteditortag[4],
                    buttontag[4],
                     leftlayouttag[4 + (3 * (MAXELEMENTS + 1))],
                    rightlayouttag[4 + (3 * (MAXELEMENTS + 1))];

    if (page == 11)
    {   wrapsize = 75;
        switch(report.type)
        {
        case BUG:
            strcpy(GadTitle[0], "Brief bug description:");
            strcpy(GadTitle[1], "Bug generation procedure or example:");
            strcpy(GadTitle[2], "If this works differently on other versions or hardware, explain:");
            strcpy(GadTitle[3], "Related problems:");
            elements = 3;
        break;
        case COM:
            if (report.severity == 3)
            {   strcpy(GadTitle[0], "If this works differently on other versions or hardware, explain:");
                elements = 0;
            } else
            {   strcpy(GadTitle[0], "Brief bug description:");
                strcpy(GadTitle[1], "Bug generation procedure or example:");
                strcpy(GadTitle[2], "If this works differently on other versions or hardware, explain:");
                strcpy(GadTitle[3], "What developer is doing in that area of software or hardware:");
                strcpy(GadTitle[4], "Related problems:");
                elements = 4;
            }
        break;
        case ENH:
            strcpy(GadTitle[0], "Enhancement request:");
            elements = 0;
        break;
        default:
        break;
    }   }
    else
    {   // assert(page == 41);
        strcpy(GadTitle[0], "Function:");

        if (inputs)
        {   for (i = 1; i <= inputs; i++)
            {   strcpy(GadTitle[i], autodoc.var[i].name);
                strcat(GadTitle[i], ":");
        }   }
        if (returncode)
        {   strcpy(GadTitle[inputs + 1], "Result:");
        }
        strcpy(GadTitle[inputs + 1 + returncode], "Example:");
        strcpy(GadTitle[inputs + 2 + returncode], "Notes:");
        strcpy(GadTitle[inputs + 3 + returncode], "Bugs:");
        strcpy(GadTitle[inputs + 4 + returncode], "See Also:");
        elements =      inputs + 4 + returncode;
        wrapsize = 72;
    }

    /* window
        root-layout
         both-layout
          left-layout
           super-caption
            sub-caption
           texteditor
          [right-layout
           super-caption
            sub-caption
           texteditor]
         button */

    if (AppPort = CreateMsgPort())
    {   /* Create the window object. */

        subcaptiontag[0].ti_Tag     = LABEL_Text;
        // subcaptiontag[0].ti_Data filled later
        subcaptiontag[1].ti_Tag     = LABEL_Justification;
        subcaptiontag[1].ti_Data    = LJ_CENTRE;
        subcaptiontag[2].ti_Tag     = TAG_END;

        texteditortag[0].ti_Tag  = GA_ID;
        // texteditortag[0].ti_Data filled later
        texteditortag[1].ti_Tag  = GA_RelVerify;
        texteditortag[1].ti_Data = TRUE;
        texteditortag[2].ti_Tag  = GA_TEXTEDITOR_ExportWrap;
        texteditortag[2].ti_Data = wrapsize;
        texteditortag[3].ti_Tag  = TAG_END;

        buttontag[0].ti_Tag      = GA_ID;
        buttontag[0].ti_Data     = GID_OK;
        buttontag[1].ti_Tag      = GA_RelVerify;
        buttontag[1].ti_Data     = TRUE;
        buttontag[2].ti_Tag      = GA_Text;
        buttontag[2].ti_Data     = (ULONG) "_OK";
        buttontag[3].ti_Tag      = TAG_END;

        supercaptiontag[0].ti_Tag  = LAYOUT_Orientation;
        supercaptiontag[0].ti_Data = LAYOUT_ORIENT_VERT;
        supercaptiontag[1].ti_Tag  = GA_BackFill;
        supercaptiontag[1].ti_Data = NULL;
        supercaptiontag[2].ti_Tag  = LAYOUT_SpaceOuter;
        supercaptiontag[2].ti_Data = TRUE;
        supercaptiontag[3].ti_Tag  = LAYOUT_VertAlignment;
        supercaptiontag[3].ti_Data = LALIGN_CENTER;
        supercaptiontag[4].ti_Tag  = LAYOUT_HorizAlignment;
        supercaptiontag[4].ti_Data = LALIGN_CENTER;
        supercaptiontag[5].ti_Tag  = LAYOUT_BevelStyle;
        supercaptiontag[5].ti_Data = BVS_FIELD;
        supercaptiontag[6].ti_Tag  = LAYOUT_AddImage;
        // supercaptiontag[6].ti_Data filled later
        supercaptiontag[7].ti_Tag  = TAG_END;

    leftlayouttag[0].ti_Tag  = LAYOUT_Orientation;
    leftlayouttag[0].ti_Data = LAYOUT_ORIENT_VERT;
    leftlayouttag[1].ti_Tag  = LAYOUT_SpaceOuter;
    leftlayouttag[1].ti_Data = TRUE;
    leftlayouttag[2].ti_Tag  = LAYOUT_DeferLayout;
    leftlayouttag[2].ti_Data = TRUE;
    theindex = 3;

    if (page == 41)
    {   for (i = 0; i <= elements / 2; i++)
        {   subcaptiontag[0].ti_Data          = (ULONG) GadTitle[i];
            texteditortag[0].ti_Data          = GID_TEXTEDITOR1 + i;
            supercaptiontag[6].ti_Data        = (ULONG) NewObjectA(LABEL_GetClass(), NULL, subcaptiontag);
            leftlayouttag[theindex].ti_Tag    = LAYOUT_AddChild;
            leftlayouttag[theindex++].ti_Data = (ULONG) NewObjectA(LAYOUT_GetClass(), NULL, supercaptiontag);
            leftlayouttag[theindex].ti_Tag    = CHILD_WeightedHeight;
            leftlayouttag[theindex++].ti_Data = 0;
            leftlayouttag[theindex].ti_Tag    = LAYOUT_AddChild;
            gadgets[GID_TEXTEDITOR1 + i]      = NewObjectA(TEXTEDITOR_GetClass(), NULL, texteditortag);
            leftlayouttag[theindex++].ti_Data = (ULONG) gadgets[GID_TEXTEDITOR1 + i];
        }
        leftlayouttag[theindex].ti_Tag        = TAG_END;

        rightlayouttag[0].ti_Tag  = LAYOUT_Orientation;
        rightlayouttag[0].ti_Data = LAYOUT_ORIENT_VERT;
        rightlayouttag[1].ti_Tag  = LAYOUT_SpaceOuter;
        rightlayouttag[1].ti_Data = TRUE;
        rightlayouttag[2].ti_Tag  = LAYOUT_DeferLayout;
        rightlayouttag[2].ti_Data = TRUE;
        theindex = 3;
        for (i = (elements / 2) + 1; i <= elements; i++)
        {   subcaptiontag[0].ti_Data           = (ULONG) GadTitle[i];
            texteditortag[0].ti_Data           = GID_TEXTEDITOR1 + i;
            supercaptiontag[6].ti_Data         = (ULONG) NewObjectA(LABEL_GetClass(), NULL, subcaptiontag);
            rightlayouttag[theindex].ti_Tag    = LAYOUT_AddChild;
            rightlayouttag[theindex++].ti_Data = (ULONG) NewObjectA(LAYOUT_GetClass(), NULL, supercaptiontag);
            rightlayouttag[theindex].ti_Tag    = CHILD_WeightedHeight;
            rightlayouttag[theindex++].ti_Data = 0;
            rightlayouttag[theindex].ti_Tag    = LAYOUT_AddChild;
            gadgets[GID_TEXTEDITOR1 + i]       = NewObjectA(TEXTEDITOR_GetClass(), NULL, texteditortag);
            rightlayouttag[theindex++].ti_Data = (ULONG) gadgets[GID_TEXTEDITOR1 + i];
        }
        rightlayouttag[theindex].ti_Tag        = TAG_END;
    } else
    {   for (i = 0; i <= elements; i++)
        {   subcaptiontag[0].ti_Data          = (ULONG) GadTitle[i];
            texteditortag[0].ti_Data          = GID_TEXTEDITOR1 + i;
            supercaptiontag[6].ti_Data        = (ULONG) NewObjectA(LABEL_GetClass(), NULL, subcaptiontag);
            leftlayouttag[theindex].ti_Tag    = LAYOUT_AddChild;
            leftlayouttag[theindex++].ti_Data = (ULONG) NewObjectA(LAYOUT_GetClass(), NULL, supercaptiontag);
            leftlayouttag[theindex].ti_Tag    = CHILD_WeightedHeight;
            leftlayouttag[theindex++].ti_Data = 0;
            leftlayouttag[theindex].ti_Tag    = LAYOUT_AddChild;
            gadgets[GID_TEXTEDITOR1 + i]      = NewObjectA(TEXTEDITOR_GetClass(), NULL, texteditortag);
            leftlayouttag[theindex++].ti_Data = (ULONG) gadgets[GID_TEXTEDITOR1 + i];
        }
        leftlayouttag[theindex].ti_Tag        = TAG_END;
    }

    /* The captions are as wide as required to hold the entire caption on
    one line. In many cases this means that `double-column' mode cannot be
    used, as the right column would be pushed out too far to the right,
    and partially offscreen. */

    bothlayouttag[0].ti_Tag  = LAYOUT_Orientation;
    bothlayouttag[0].ti_Data = LAYOUT_ORIENT_HORIZ;
    bothlayouttag[1].ti_Tag  = LAYOUT_SpaceOuter;
    bothlayouttag[1].ti_Data = TRUE;
    bothlayouttag[2].ti_Tag  = LAYOUT_DeferLayout;
    bothlayouttag[2].ti_Data = TRUE;

    bothlayouttag[3].ti_Tag  = LAYOUT_AddChild;
    bothlayouttag[3].ti_Data = (ULONG) NewObjectA(LAYOUT_GetClass(), NULL, leftlayouttag);
    bothlayouttag[4].ti_Tag  = CHILD_WeightedWidth;
    bothlayouttag[4].ti_Data = 50;
    if (page == 41)
    {   bothlayouttag[5].ti_Tag  = LAYOUT_AddChild;
        bothlayouttag[5].ti_Data = (ULONG) NewObjectA(LAYOUT_GetClass(), NULL, rightlayouttag);
        bothlayouttag[6].ti_Tag  = CHILD_WeightedWidth;
        bothlayouttag[6].ti_Data = 50;
        bothlayouttag[7].ti_Tag  = TAG_END;
    } else
        bothlayouttag[5].ti_Tag  = TAG_END;

        rootlayouttag[0].ti_Tag  = LAYOUT_Orientation;
        rootlayouttag[0].ti_Data = LAYOUT_ORIENT_VERT;
        rootlayouttag[1].ti_Tag  = LAYOUT_SpaceOuter;
        rootlayouttag[1].ti_Data = TRUE;
        rootlayouttag[2].ti_Tag  = LAYOUT_DeferLayout;
        rootlayouttag[2].ti_Data = TRUE;
        rootlayouttag[3].ti_Tag  = LAYOUT_AddChild;
        rootlayouttag[3].ti_Data = (ULONG) NewObjectA(LAYOUT_GetClass(), NULL, bothlayouttag);
        rootlayouttag[4].ti_Tag  = LAYOUT_AddChild;
        rootlayouttag[4].ti_Data = (ULONG) NewObjectA(NULL, "button.gadget", buttontag);
        rootlayouttag[5].ti_Tag  = CHILD_WeightedHeight;
        rootlayouttag[5].ti_Data = 0;
        rootlayouttag[6].ti_Tag  = TAG_END;

        lockscreen();
        windowtag[0].ti_Tag   = WA_PubScreen;
        windowtag[0].ti_Data  = (ULONG) ScreenPtr;
        windowtag[1].ti_Tag   = WA_ScreenTitle;
        windowtag[1].ti_Data  = (ULONG) "Report+";
        windowtag[2].ti_Tag   = WA_Title;
        windowtag[2].ti_Data  = (ULONG) "Report+: Text Editor";
        windowtag[3].ti_Tag   = WA_Activate;
        windowtag[3].ti_Data  = TRUE;
        windowtag[4].ti_Tag   = WA_DepthGadget;
        windowtag[4].ti_Data  = TRUE;
        windowtag[5].ti_Tag   = WA_DragBar;
        windowtag[5].ti_Data  = TRUE;
        windowtag[6].ti_Tag   = WA_CloseGadget;
        windowtag[6].ti_Data  = TRUE;
        windowtag[7].ti_Tag   = WA_SizeGadget;
        windowtag[7].ti_Data  = TRUE;
        windowtag[8].ti_Tag   = WINDOW_AppPort;
        windowtag[8].ti_Data  = (ULONG) AppPort;
        windowtag[9].ti_Tag   = WINDOW_Position;
        windowtag[9].ti_Data  = WPOS_FULLSCREEN;
        windowtag[10].ti_Tag  = WINDOW_ParentGroup;
        gadgets[GID_MAIN]     = NewObjectA(LAYOUT_GetClass(), NULL, rootlayouttag);
        windowtag[10].ti_Data = (ULONG) gadgets[GID_MAIN];
        windowtag[11].ti_Tag  = TAG_END;

        objects[OID_MAIN] = NewObjectA(WINDOW_GetClass(), NULL, windowtag);
        unlockscreen();

        // Object creation successful?
        if (objects[OID_MAIN])
        {   // Open the window.
            if (ReActionWindowPtr = (struct Window *) DoMethod(objects[OID_MAIN], WM_OPEN, NULL))
            {   ULONG wait, signal, app = (1L << AppPort->mp_SigBit);
                ULONG result;
                UWORD code;

                done = FALSE;

                // Obtain the window wait signal mask.
                GetAttr(WINDOW_SigMask, objects[OID_MAIN], &signal);

                // Do any necessary imports.
                if (page == 11)
                {   switch(report.type)
                    {
                    case BUG:
                        SetGadgetAttrs
                        (   gadgets[GID_TEXTEDITOR1],       ReActionWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,         report.textfield[0]
                        ); // brief bug description
                        SetGadgetAttrs
                        (   gadgets[GID_TEXTEDITOR1 + 1],   ReActionWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,         report.textfield[1]
                        ); // bug generation procedure or example
                        SetGadgetAttrs
                        (   gadgets[GID_TEXTEDITOR1 + 2],   ReActionWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,         report.textfield[2]
                        ); // if this works differently...
                        SetGadgetAttrs
                        (   gadgets[GID_TEXTEDITOR1 + 3],   ReActionWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,         report.textfield[3]
                        ); // related problems
                    break;
                    case COM:
                        if (report.severity == 0)
                        {   SetGadgetAttrs
                            (   gadgets[GID_TEXTEDITOR1],   ReActionWindowPtr, NULL,
                                GA_TEXTEDITOR_Contents,     report.textfield[2]
                            ); // if this works differently...
                        } else
                        {   for (i = 0; i <= 4; i++)
                            {   SetGadgetAttrs
                                (   gadgets[GID_TEXTEDITOR1 + i], ReActionWindowPtr, NULL,
                                    GA_TEXTEDITOR_Contents,       report.textfield[i]
                                );
                        }   }
                        /* brief bug description
                           bug generation procedure or example
                           if this works differently...
                           what developer is doing...
                           related problems */
                    break;
                    case ENH:
                        SetGadgetAttrs
                        (   gadgets[GID_TEXTEDITOR1],       ReActionWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,         report.textfield[5]
                        ); // enhancement request
                    break;
                    default:
                        ; // assert(0);
                    break;
                }   }
                else
                {   // assert(page == 41);
                    /* Autodoc text fields are as follows:
                     0 Function
                     1 Example
                     2 Notes
                     3 Bugs
                     4 See also
                     5 Result   (mirrors autodoc.var[0].desc)
                  6-13 Inputs   (

                    Whereas the gadgets go Function, inputs, Result, others

                    */

                    SetGadgetAttrs
                    (   gadgets[GID_TEXTEDITOR1],       ReActionWindowPtr, NULL,
                        GA_TEXTEDITOR_Contents,         autodoc.textfield[0]
                    );

                    if (inputs)
                    {   for (i = 1; i < inputs; i++)
                        {   SetGadgetAttrs
                            (   gadgets[GID_TEXTEDITOR1 + i], ReActionWindowPtr, NULL,
                                GA_TEXTEDITOR_Contents, autodoc.var[i].desc
                            );
                    }   }
                    if (returncode)
                    {   SetGadgetAttrs
                        (   gadgets[GID_TEXTEDITOR1 + inputs + 1], ReActionWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,     autodoc.var[0].desc
                        ); // return code
                    }
                    for (i = 1; i <= 4; i++)
                    {   SetGadgetAttrs
                        (   gadgets[GID_TEXTEDITOR1 + inputs + returncode + i], ReActionWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,     autodoc.textfield[i]
                        );
                }   }

                // Activate the first texteditor gadget.
                ActivateLayoutGadget(gadgets[GID_MAIN], ReActionWindowPtr, NULL, (Object) gadgets[GID_TEXTEDITOR1]);

                // Input Event Loop
                while (!done)
                {   wait = Wait( signal | SIGBREAKF_CTRL_C | app );

                    if ( wait & SIGBREAKF_CTRL_C )
                        done = TRUE;
                    else
                    {   while ( (result = RA_HandleInput(objects[OID_MAIN], &code) ) != WMHI_LASTMSG )
                        {   switch (result & WMHI_CLASSMASK)
                            {
                            case WMHI_CLOSEWINDOW:
                                ReActionWindowPtr = NULL;
                                done = TRUE;
                            break;
                            case WMHI_GADGETUP:
                                switch (result & WMHI_GADGETMASK)
                                {
                                case GID_OK:
                                    done = TRUE;
                                break;
                                default:
                                break;
                                }
                            break;
                            default:
                            break;
            }   }   }   }   }

            for (i = 0; i <= elements; i++)
                textBuffer[i] = (STRPTR) DoGadgetMethod(gadgets[GID_TEXTEDITOR1 + i], ReActionWindowPtr, NULL, GM_TEXTEDITOR_ExportText, NULL);

            if (page == 11)
            {   switch(report.type)
                {
                case BUG:
                    strcpy(report.textfield[0], textBuffer[0]); // brief bug description
                    strcpy(report.textfield[1], textBuffer[1]); // bug generation procedure or example
                    strcpy(report.textfield[2], textBuffer[2]); // if this works differently...
                    strcpy(report.textfield[4], textBuffer[3]); // related problems
                break;
                case COM:
                    if (report.severity == 0)
                    {   strcpy(report.textfield[2], textBuffer[0]); // if this works differently...
                    } else
                    {   strcpy(report.textfield[0], textBuffer[0]); // brief bug description
                        strcpy(report.textfield[1], textBuffer[1]); // bug generation procedure or example
                        strcpy(report.textfield[2], textBuffer[2]); // if this works differently...
                        strcpy(report.textfield[3], textBuffer[3]); // what developer is doing...
                        strcpy(report.textfield[4], textBuffer[4]); // related problems
                    }
                break;
                case ENH:
                    strcpy(report.textfield[5], textBuffer[0]); // enhancement request
                break;
                default:
                    ; // assert(0);
                break;
            }   }
            else
            {   // assert(page == 41);
                strcpy(autodoc.textfield[0], textBuffer[0]); // function
                if (inputs)
                {   for (i = 1; i <= inputs; i++)
                    {   strcpy(autodoc.var[i].desc, textBuffer[i]);
                }   }
                if (returncode)
                {   strcpy(autodoc.var[0].desc, textBuffer[inputs + 1]);
                }
                for (i = 1; i <= 4; i++)
                {   strcpy(autodoc.textfield[i], textBuffer[inputs + returncode + i]);
                }

                /* Qty  Field type
                     1  Function field
                   0-8  Input # fields
                0 or 1  Return code field
                     1  Example field
                     1  Notes field
                     1  Bugs field
                     1  See also field */
            }

            for (i = 0; i <= elements; i++)
            {   FreeVec((APTR) textBuffer[i]);
                textBuffer[i] = NULL;
            }
    
            /* Disposing of the window object will also close the window if it is
             * already opened, and it will dispose of the layout object attached to it.
             */
            DisposeObject(objects[OID_MAIN]);
        } else rq("Report+: Can't create ReAction objects!");
        DeleteMsgPort(AppPort);
    } else rq("Report+: Can't create window message port!");

    return;
}

