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

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

IMPORT ULONG               elements, // for ReAction texteditor.gadget
                           offset;
IMPORT TEXT                aslresult[MEDFIELD + 1];
IMPORT TEXT                weekdaystring[10],
                           datestring[10],
                           timestring[9];
IMPORT struct SharedStruct shared;
IMPORT struct NewGadget    Gadget;
IMPORT struct Gadget      *BU99_Right,
                          *BU99_TextEditor,
                          *GListPtr,
                          *PrevGadPtr;
IMPORT ULONG               wbval;
IMPORT TEXT                IOBuffer[LONGESTFIELD + 1];
IMPORT SBYTE               page;
IMPORT ABOOL               certified, fillwindows;

/* report.textfield[] are:
   0: brief bug description
   1: bug generation procedure or example
   2: if this works differently on other versions or hardware, explain
   3: what developer is doing in that area of HW or SW
   4: related problems
   5: enhancement request */

#define SUBSYSTEMS 127

IMPORT TEXT                string[VLONGFIELD + 1];
MODULE struct List*        SubsystemListPtr = NULL;
MODULE struct
{   STRPTR friendly;
    STRPTR unfriendly;
} subsystems[SUBSYSTEMS + 1] =
{   {"3D Look",                "new.look"        },
    {"A590",                   "A2091.A590"      },
    {"A2013",                  "A2013"           },
    {"A2065",                  "A2065"           },
    {"A2090",                  "A2090.A2090A"    },
    {"A2090A",                 "A2090.A2090A"    },
    {"A2091",                  "A2091"           },
    {"A2232",                  "A2232"           },
    {"A2300",                  "A2300"           },
    {"A2410",                  "A2410"           },
    {"A2620",                  "A2620"           },
    {"A2630",                  "A2630"           },
    {"A3000",                  "A3000"           },
    {"A4091",                  "A4091"           },
    {"AmigaBASIC",             "AmigaBasic"      },
    {"AGA chipset",            "aa.chips"        },
    {"ALink",                  "alink"           },
    {"amiga.lib",              "amiga.lib"       },
    {"AmigaGuide",             "amigaguide"      },
    {"AmigaTerm",              "amigaterm"       },
    {"AmigaVision",            "amigavision"     },
    {"AppShell",               "appshell"        },
    {"ARexx",                  "arexx"           },
    {"Art",                    "art"             },
    {"AS225",                  "as225"           },
    {"ASL.library",            "asl.library"     },
    {"audio.device",           "audio.device"    },
    {"AUTOCONFIG",             "autoconfig"      },
    {"Battery-backed clock",   "battclock"       },
    {"Battery-backed memory",  "battmem"         },
    {"Bootstrap",              "strap"           },
    {"BridgeBoard",            "bridgeboard"     },
    {"BRU",                    "bru"             },
    {"bullet.library",         "bullet"          },
    {"C: programs",            "cdos.command"    },
    {"CD.device",              "cd.device"       },
    {"CD32 hardware",          "cdgs"            },
    {"CDFileSystem",           "cdfilesystem"    },
    {"CDTV",                   "cdtv"            },
    {"CDTV.device",            "cdtv.device"     },
    {"cdui",                   "cdui"            },
    {"CIA.resource",           "cia.resource"    },
    {"CLI",                    "shell"           },
    {"clipboard.device",       "clipboard"       },
    {"Commodities",            "commodities"     },
    {"CON-Handler",            "con-handler"     },
    {"console.device",         "console.device"  },
    {"Custom chipset",         "custom.chips"    },
    {"Datatypes",              "datatypes"       },
    {"debug.lib",              "debug.lib"       },
    {"Developer support",      "devsupport"      },
    {"disk.resource",          "disk.resource"   },
    {"diskfont.library",       "diskfont"        },
    {"DOS.library",            "dos.library"     },
    {"Early Startup Control",  "bootmenu"        },
    {"Envoy",                  "envoy"           },
    {"Exec.library",           "exec"            },
    {"expansion.library",      "expansion"       },
    {"filesystem",             "filesystem"      },
    {"filesystem.resource",    "filesysres"      },
    {"Fonts",                  "fonts"           },
    {"Fountain",               "fountain"        },
    {"gadget.classes",         "gadget.classes"  },
    {"GadTools.library",       "gadtools"        },
    {"gameport.device",        "gameport"        },
    {"Genlock",                "genlock"         },
    {"Graphics",               "graphics"        },
    {"Hardware",               "hardware"        },
    {"HDBackup",               "hdbackup"        },
    {"HDToolBox",              "hdtoolbox"       },
    {"icon.library",           "icon.library"    },
    {"IconEdit",               "iconedit"        },
    {"IDE.device",             "ide.device"      },
    {"IFFParse.library",       "iffparse"        },
    {"input.device",           "input.device"    },
    {"Installer",              "installer"       },
    {"IntelliFont",            "fountain"        },
    {"Intuition.library",      "intuition"       },
    {"IPrefs",                 "iprefs"          },
    {"Keyboard",               "keyboard"        },
    {"keymap.library",         "keymap"          },
    {"Keymaps",                "keymaps"         },
    {"layers.library",         "layers"          },
    {"locale.library",         "locale.library"  },
    {"lowlevel.library",       "lowlevel"        },
    {"Maths: FFP",             "mathffp"         },
    {"Maths: IEEE Dbl Prcsn",  "mathieeedoub"    },
    {"Maths: IEEE Sngl Prcsn", "mathieeesing"    },
    {"Maths: IEEE",            "mathieee"        },
    {"MicroEMACS",             "microemacs"      },
    {"Monitors",               "monitors"        },
    {"MultiView",              "multiview"       },
    {"nonvolatile",            "nonvolatile"     },
    {"parallel.device",        "parallel.device" },
    {"PCMCIA",                 "creditcard"      },
    {"PORT-Handler",           "port-handler"    },
    {"potgo.resource",         "potgo.resource"  },
    {"Preferences",            "preferences"     },
    {"Printer drivers",        "printer.driver"  },
    {"printer.device",         "printer.device"  },
    {"QUEUE-Handler",          "queue-handler"   },
    {"RAM-Handler",            "ram-handler"     },
    {"ramlib",                 "ramlib"          },
    {"realtime",               "realtime"        },
    {"Report+",                "report+"         },
    {"Resources",              "resource"        },
    {"ROM Kernel Manuals",     "rkm"             },
    {"ROMWack",                "wack"            },
    {"SANA-2",                 "sana2"           },
    {"Scripts",                "script"          },
    {"SCSI.device",            "scsi.device"     },
    {"serial.device",          "serial.device"   },
    {"Shell",                  "shell"           },
    {"Startup",                "startup"         },
    {"System/ programs",       "system.command"  },
    {"TCP/IP",                 "as225"           },
    {"timer.device",           "timer.device"    },
    {"ToolMaker",              "toolmaker"       },
    {"Tools/ programs",        "tools"           },
    {"trackdisk.device",       "trackdisk"       },
    {"UNIX",                   "unix"            },
    {"Unsure",                 ""                },
    {"User manuals",           "userdocs"        },
    {"Utilities/ programs",    "util.command"    },
    {"utility.library",        "utility.library" },
    {"Wack",                   "wack"            },
    {"Workbench",              "workbench"       },
    {"Worm Wars",              "wormwars"        }
};

MODULE void refreshpv(void);
MODULE void updatereportgadgets(void);
MODULE void readreportgadgets(void);

AGLOBAL struct ReportStruct report;

MODULE STRPTR TypeOptions[4] =
{   (STRPTR) "System Software/Hardware Bug",
    (STRPTR) "3rd Party Product Compatibility",
    (STRPTR) "Enhancement Request",
    NULL
};
MODULE STRPTR SeverityOptions[5] =
{   (STRPTR) "Crashes, hangs or corrupts data",
    (STRPTR) "Behaves incorrectly",
    (STRPTR) "Cosmetic problem",
    (STRPTR) "Works correctly",
    NULL
};
MODULE STRPTR AgnusOptions[6] =
{   (STRPTR) "AGA",
    (STRPTR) "ECS PAL",
    (STRPTR) "ECS NTSC",
    (STRPTR) "OCS PAL",
    (STRPTR) "OCS NTSC",
    NULL
};
MODULE STRPTR DeniseOptions[4] =
{   (STRPTR) "AGA",
    (STRPTR) "ECS",
    (STRPTR) "OCS",
    NULL
};
#define CPUS 6
MODULE STRPTR CPUOptions[CPUS + 2] =
{   (STRPTR) "68000",
    (STRPTR) "68010",
    (STRPTR) "68020",
    (STRPTR) "68030",
    (STRPTR) "68040",
    (STRPTR) "68060",
    (STRPTR) "PowerPC",
    NULL
};
#define MODELS 13
MODULE STRPTR ModelOptions[MODELS + 2] =
{   (STRPTR) "A500",
    (STRPTR) "A500+",
    (STRPTR) "A600",
    (STRPTR) "A1000",
    (STRPTR) "A1200",
    (STRPTR) "A1500",
    (STRPTR) "A2000",
    (STRPTR) "A2500",
    (STRPTR) "A3000",
    (STRPTR) "A4000",
    (STRPTR) "CDTV",
    (STRPTR) "CD32",
    (STRPTR) "DraCo",
    (STRPTR) "Emulator",
    NULL
};
IMPORT struct Window*  MainWindowPtr;
MODULE struct Gadget  *CY11_Type               = NULL,
                      *ST11_Summary            = NULL,
                      *BU11_PathnameASL        = NULL,
                      *LV11_Subsystem          = NULL,
                      *CY11_Severity           = NULL,
                      *ST11_Debug              = NULL,
                      *ST11_KS                 = NULL,
                      *ST11_WB                 = NULL,
                      *ST11_Pathname           = NULL,
                      *ST11_Version            = NULL,
                      *TE11_3rdLabel           = NULL,
                      *ST11_3rdName            = NULL,
                      *ST11_3rdVer             = NULL,
                      *ST11_3rdManuf           = NULL,
                      *BU11_Sender             = NULL,
                      *BU11_Config             = NULL,
                      *TE11_EMailTo            = NULL,
                      *ST12_Company            = NULL,
                      *ST12_Developer          = NULL,
                      *ST12_EMail              = NULL,
                      *ST12_FirstName          = NULL,
                      *ST12_LastName           = NULL,
                      *ST12_Phone              = NULL,
                      *MX13_Model              = NULL,
                      *TE13_ModelText          = NULL,
                      *MX13_Agnus              = NULL,
                      *TE13_AgnusText          = NULL,
                      *MX13_CPU                = NULL,
                      *TE13_CPUText            = NULL,
                      *MX13_Denise             = NULL,
                      *TE13_DeniseText         = NULL,
                      *IN13_Floppies           = NULL,
                      *ST13_Chip               = NULL,
                      *TE13_ChipText           = NULL,
                      *ST13_Fast               = NULL,
                      *TE13_FastText           = NULL,
                      *ST13_Hard               = NULL,
                      *ST13_Expansion          = NULL;

AGLOBAL void report1(void)
{  /* PAGE 11 ************************************************************ */

    verynewwindow
    (   REPORTWIDTH, REPORTHEIGHT,
        "Report+: Report Details",
        BUTTONIDCMP | LISTVIEWIDCMP | STRINGIDCMP | CYCLEIDCMP
    );
    if (fillwindows)
    {   SetAPen(MainWindowPtr->RPort, 0);
        RectFill(MainWindowPtr->RPort,  10, 144,  10 + 174, 144 + 87 - 4); // LV11_Subsystem
        RectFill(MainWindowPtr->RPort, 182,  32, 182 + 312,  32 + 12);     // TE11_EMailTo
    }
    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));

    /* summary */
    setgadget(182, 20, 448, 12, "_Summary:", PLACETEXT_LEFT);
    ST11_Summary = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        STRINGA_Justification, GACT_STRINGLEFT,
        GTST_String, &(report.summary),
        GTST_MaxChars, LONGFIELD,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );
    /* email to */
    setgadget(182, 32, 312, 12, "EMail to:", PLACETEXT_LEFT);
    TE11_EMailTo = PrevGadPtr = (struct Gadget *) CreateGadget
    (   TEXT_KIND,
        PrevGadPtr,
        &Gadget,
        GTTX_Border, TRUE,
        TAG_DONE
    );

    /* sender... */
    setgadget(10,  86, 140, 12, "Sende_r...", NULL);
    BU11_Sender = PrevGadPtr = (struct Gadget *) CreateGadget
    (   BUTTON_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );
    /* configuration... */
    setgadget(10,  98, 140, 12, "Confi_guration...", NULL);
    BU11_Config = PrevGadPtr = (struct Gadget *) CreateGadget
    (   BUTTON_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );
    /* text editor... */
    setgadget(10, 110, 140, 12, "Te_xt editor...", NULL);
    BU99_TextEditor = PrevGadPtr = (struct Gadget *) CreateGadget
    (   BUTTON_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );

    /* type */
    setgadget(100, 54, 284, 12, "_Type:", PLACETEXT_LEFT);
    CY11_Type = PrevGadPtr = (struct Gadget *) CreateGadget
    (   CYCLE_KIND,
        PrevGadPtr,
        &Gadget,
        GTCY_Labels, TypeOptions,
        GTCY_Active, report.type,
        GT_Underscore, '_',
        TAG_DONE
    );

    /* classification */
    setgadget(100, 66, 284, 12, "Sever_ity:", PLACETEXT_LEFT);
    CY11_Severity = PrevGadPtr = (struct Gadget *) CreateGadget
    (   CYCLE_KIND,
        PrevGadPtr,
        &Gadget,
        GTCY_Labels, SeverityOptions,
        GTCY_Active, report.severity,
        GT_Underscore, '_',
        TAG_DONE
    );

    setgadget(10, 144, 174, 87, "Subsystem:", NULL);
    LV11_Subsystem = PrevGadPtr = (struct Gadget *) CreateGadget
    (   LISTVIEW_KIND,
        PrevGadPtr,
        &Gadget,
        GTLV_Labels, SubsystemListPtr,
        GTLV_ShowSelected, NULL,
        GTLV_Selected, report.subsystem,
        GT_Underscore, '_',
        TAG_DONE
    );

    /* 3rd party product */
    setgadget(400, 190, 100, 1, "3rd Party Product:", PLACETEXT_ABOVE);
    TE11_3rdLabel = PrevGadPtr = (struct Gadget *) CreateGadget
    (   TEXT_KIND,
        PrevGadPtr,
        &Gadget,
        TAG_DONE
    );
    /* 3rd party product name */
    setgadget(400, 190, 200, 12, "N_ame:", NULL);
    ST11_3rdName = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        GTST_String, &(report.thirdname),
        GTST_MaxChars, MEDFIELD,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );
    /* 3rd party product version */
    setgadget(400, 202, 100, 12, "_Version:", NULL);
    ST11_3rdVer = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        GTST_String, &(report.thirdver),
        GTST_MaxChars, MEDFIELD,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );
    /* 3rd party product manufacturer */
    setgadget(400, 214, 200, 12, "_Manufacturer:", NULL);
    ST11_3rdManuf = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        GTST_String, &(report.thirdmanuf),
        GTST_MaxChars, MEDFIELD,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );

    /* debug tools and wedges */
    setgadget(400, 78, 196, 12, "_Debug tools and wedges:", PLACETEXT_ABOVE);
    ST11_Debug = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        STRINGA_Justification, GACT_STRINGLEFT,
        GTST_String, &(report.debug),
        GTST_MaxChars, LONGFIELD,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );

    /* kickstart version */
    if (report.ks[0] == 0)
        if (GetVar("Kickstart", &(report.ks), 6, NULL) == -1)
            report.ks[0] = 0;
    setgadget(400, 102, 60, 12, "_Kickstart version:", NULL);
    ST11_KS = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        GTST_String, &(report.ks),
        GTST_MaxChars, 6,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        STRINGA_Justification, GACT_STRINGRIGHT,
        TAG_DONE
    );
    /* workbench version */
    if (report.wb[0] == 0)
        if (GetVar("Workbench", &(report.wb), 6, NULL) == -1)
            report.wb[0] = 0;
    setgadget(400, 114, 60, 12, "_Workbench version:", NULL);
    ST11_WB = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        GTST_String, &(report.wb),
        GTST_MaxChars, 6,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        STRINGA_Justification, GACT_STRINGRIGHT,
        TAG_DONE
    );

    /* program pathname */
    setgadget(400, 138, 196, 12, "P_rogram pathname:", NULL);
    ST11_Pathname = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        GTST_String, &(report.pp),
        GTST_MaxChars, LONGFIELD,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );
    /* program... */
    setgadget(598, 138, 28, 12, "...", NULL);
    BU11_PathnameASL = PrevGadPtr = (struct Gadget *) CreateGadget
    (   BUTTON_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );
    /* program version */
    setgadget(400, 150, 196, 12, "Program v_ersion:", NULL);
    ST11_Version = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        GTST_String, &(report.pv),
        GTST_MaxChars, LONGFIELD,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );

    /* There are 30 gadgets:
       1 BU99_Right
       4 LV11_Subsystem
       1 TE11_3rdLabel
       2 ST11_3rdName
       2 ST11_3rdVer
       2 ST11_3rdManuf
       2 ST11_Debug
       2 CY11_Severity
       2 ST11_Pathname
       1 BU11_PathnameASL
       2 ST11_Version
       2 ST11_KS
       2 ST11_WB
       2 CY11_Type
       1 BU11_Sender
       1 BU11_Config
       1 BU99_TextEditor
       2 TE11_EMailTo */
    drawgadgets(30);

    updatereportgadgets(); // we do need this here, so that gadgets are
                           // ghosted as appropriate
    ActivateGadget(ST11_Summary, MainWindowPtr, NULL);

    loop();
    readreportgadgets();
    closewindow();
}

MODULE void readreportgadgets(void)
{   strcpy
    (   report.summary,
        ((struct StringInfo *) ST11_Summary->SpecialInfo)->Buffer
    );
    if (report.type == COM)
    {   strcpy
        (   report.thirdver,
            ((struct StringInfo *) ST11_3rdVer->SpecialInfo)->Buffer
        );
        strcpy
        (   report.thirdname,
            ((struct StringInfo *) ST11_3rdName->SpecialInfo)->Buffer
        );
        strcpy
        (   report.thirdmanuf,
            ((struct StringInfo *) ST11_3rdManuf->SpecialInfo)->Buffer
        );
    } elif (report.type == BUG)
    {   strcpy
        (   report.pp,
            ((struct StringInfo *) ST11_Pathname->SpecialInfo)->Buffer
        );
        strcpy
        (   report.pv,
            ((struct StringInfo *) ST11_Version->SpecialInfo)->Buffer
        );
    }
    if (report.type != ENH)
    {   strcpy
        (   report.ks,
            ((struct StringInfo *) ST11_KS->SpecialInfo)->Buffer
        );
        strcpy
        (   report.wb,
            ((struct StringInfo *) ST11_WB->SpecialInfo)->Buffer
        );
        strcpy
        (   report.debug,
            ((struct StringInfo *) ST11_Debug->SpecialInfo)->Buffer
        );
}   }

AGLOBAL void savereport(ABOOL saveas)
{ /*    # Subject: <subject><LF>
        # Type: bug|compat|enhancement<LF>
1,3     # Subsystem: <subsystem><LF>
2       # ProductName: <name> (vers=<version>)
2       # ProductInfo: :<manufacturer>:
        # Severity: a|b|c|ok|e
1       # Release: KS=<version>,WB=<version>,Program=<version>
2       # Release: KS=<version>,WB=<version>
        # Date: <weekday> dd-Mon-yy hh:mm:ss
        # Refer: <refer>
        # Path: <path>
        # ReferID: <referid>
        # Config: <config>
1,2a-c	### BRIEF BUG DESCRIPTION:
1,2a-c	### BUG GENERATION PROCEDURE OR EXAMPLE:
1,2     ### ALSO RUNNING:
        <debug>
1,2     ### IF THIS WORKS DIFFERENTLY ON OTHER VERSIONS OR HARDWARE,
        EXPLAIN:
2a-c	### WHAT DEVELOPER IS DOING IN THAT AREA OF SW OR HW:	
1,2a-c	### RELATED PROBLEMS:
3       ### ENHANCEMENT REQUEST: */

    readreportgadgets();

    strcpy(IOBuffer, "# Subject: ");
    strcat(IOBuffer, report.summary);
    strcat(IOBuffer, "\n# Type: ");
    if (report.type == BUG)
	strcat(IOBuffer, "bug");
    elif (report.type == COM)
    	strcat(IOBuffer, "compat");
    else /* assumes (report.type == ENH) */
    	strcat(IOBuffer, "enhancement");
    strcat(IOBuffer, "\n");
    if (report.type == BUG || report.type == ENH)
    {	strcat(IOBuffer, "# Subsystem: ");
    	strcat(IOBuffer, subsystems[report.subsystem].unfriendly);
	strcat(IOBuffer, "\n");
    } else
    {	strcat(IOBuffer, "# ProductName: ");
	strcat(IOBuffer, report.thirdname);
    	strcat(IOBuffer, " (vers=");
    	strcat(IOBuffer, report.thirdver);
    	strcat(IOBuffer, ")\n# ProductInfo: :");
    	strcat(IOBuffer, report.thirdmanuf);
        strcat(IOBuffer, ":\n");
    }
    strcat(IOBuffer, "# Severity: ");
    if (report.type == ENH)
    	strcat(IOBuffer, "e");
    elif (report.severity == 0)
    	strcat(IOBuffer, "a");
    elif (report.severity == 1)
    	strcat(IOBuffer, "b");
    elif (report.severity == 2)
    	strcat(IOBuffer, "c");
    else /* assumes report.severity == 3 */
	strcat(IOBuffer, "ok");
    strcat(IOBuffer, "\n");
    if (report.type == BUG || report.type == COM)
    {	strcat(IOBuffer, "# Release: KS=");
    	strcat(IOBuffer, report.ks);
		strcat(IOBuffer, ",WB=");
    	strcat(IOBuffer, report.wb);
    	if (report.type == BUG)
    	{	strcat(IOBuffer, ",Program=");
    		strcat(IOBuffer, report.pv);
    	}
    	strcat(IOBuffer, "\n");
    }
    
    getdate();
    strcat(IOBuffer, "# Date: ");
    strcat(IOBuffer, weekdaystring);
    strcat(IOBuffer, " ");
    strcat(IOBuffer, datestring);
    strcat(IOBuffer, " ");
    strcat(IOBuffer, timestring);
    strcat(IOBuffer, "\n");
    strcat(IOBuffer, report.refer);
    strcat(IOBuffer, report.path);
    strcat(IOBuffer, report.referid);
    strcat(IOBuffer, report.config);
    strcat(IOBuffer, "\n");

    if (report.type == BUG || (report.type == COM && report.severity != 3))
    {   strcat
        (   IOBuffer,
	        "### BRIEF BUG DESCRIPTION:\n"
        );
        strcat(IOBuffer, report.textfield[0]);
        strcat
        (   IOBuffer,
            "\n\n### BUG GENERATION PROCEDURE OR EXAMPLE:\n"
	);
        strcat(IOBuffer, report.textfield[1]);
        strcat(IOBuffer, "\n\n");
    }
    if (report.type == BUG || report.type == COM)
    {   strcat(IOBuffer, "### ALSO RUNNING:\n");
        strcat(IOBuffer, report.debug);
        strcat
        (   IOBuffer,
            "\n\n### IF THIS WORKS DIFFERENTLY ON "
            "OTHER VERSIONS OR HARDWARE, EXPLAIN:\n"
        );
        strcat(IOBuffer, report.textfield[2]);
        strcat(IOBuffer, "\n\n");
    }
    if (report.type == COM && report.severity != 3)
    {   strcat
        (   IOBuffer,
            "### WHAT DEVELOPER IS DOING IN THAT AREA OF HW OR SW:\n"
        );
        strcat(IOBuffer, report.textfield[3]);
        strcat(IOBuffer, "\n\n");
    }
    if (report.type == BUG || (report.type == COM && report.severity != 3))
    {   strcat(IOBuffer, "### RELATED PROBLEMS:\n");
        strcat(IOBuffer, report.textfield[4]);
        strcat(IOBuffer, "\n\n");
    } elif (report.type == ENH)
    {   strcat(IOBuffer, "### ENHANCEMENT REQUEST:\n");
        strcat(IOBuffer, report.textfield[5]);
        strcat(IOBuffer, "\n\n");
    }

    if (!report.output[0] || saveas) // if we need a filename
    {   saveasl("Save Bug Report");
        strcpy(report.output, aslresult);
    }
    if (report.output[0]) // if ASL was not cancelled
    {   writeout(report.output);
}   }
    
AGLOBAL void report_loop(ULONG class, struct Gadget* addr, UWORD code, UWORD qual)
{   if (page == 11)
    {   if (class == IDCMP_RAWKEY && report.type != COM)
        {   if (qual & IEQUALIFIER_CONTROL)
            {   if (code == SCAN_UP)
                {   GT_SetGadgetAttrs
                    (   LV11_Subsystem,
                        MainWindowPtr,
                        NULL,
                        GTLV_Top, 0,
                        TAG_DONE
                    );
                } elif (code == SCAN_DOWN)
                {   GT_SetGadgetAttrs
                    (   LV11_Subsystem,
                        MainWindowPtr,
                        NULL,
                        GTLV_Top, SUBSYSTEMS - 10 + 1,
                        // this must change according to height of listview
                        TAG_DONE
                    );
        }   }   }
        elif (class == IDCMP_VANILLAKEY)
        {   code = toupper(code);
            if (code == ESCAPE)
            {   page = 0;
            } elif (code == 'N')
            {   page = 12;
            } elif (code == 'T')
            {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                {   if (report.type == 0)
                    {   report.type = 2;
                    } else report.type--;
                } else
                {   if (report.type == 2)
                    {   report.type = 0;
                    } else report.type++;
                }
                updatereportgadgets();
            } elif (code == 'S')
            {   ActivateGadget(ST11_Summary, MainWindowPtr, NULL);
            } elif (code == 'X')
            {   if (wbval <= 43)
                {   savereport(FALSE);
                }
                launcheditor();
            } elif (code == 'R')
            {   page = 12;
            } elif (code == 'G')
            {   page = 13;
            } elif (report.type != ENH)
            {   if (code == 'K')
                {   ActivateGadget(ST11_KS, MainWindowPtr, NULL);
                } elif (code == 'W')
                {   ActivateGadget(ST11_WB, MainWindowPtr, NULL);
                } elif (code == 'D')
                {   ActivateGadget(ST11_Debug, MainWindowPtr, NULL);
                } elif (code == 'I')
                {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                    {   if (report.severity == 0)
                        {   report.severity = 3;
                        } else report.severity--;
                    } else
                    {   if (report.severity == 3)
                        {   report.severity = 0;
                        } else report.severity++;
                    }
                    if (report.type == BUG && report.severity == 3)
                    {   report.severity = 0;
                    }
                    GT_SetGadgetAttrs
                    (   CY11_Severity,
                        MainWindowPtr,
                        NULL,
                        GTCY_Active, report.severity,
                        TAG_DONE
                    );
                } elif (report.type == BUG)
                {   if (code == 'P')
                    {   ActivateGadget(ST11_Pathname, MainWindowPtr, NULL);
                    } elif (code == 'E')
                    {   ActivateGadget(ST11_Version, MainWindowPtr, NULL);
                }   }
                else
                {   // assert(report.type == COM);
                    if (code == 'A')
                    {   ActivateGadget(ST11_3rdName, MainWindowPtr, NULL);
                    } elif (code == 'V')
                    {   ActivateGadget(ST11_3rdVer, MainWindowPtr, NULL);
                    } elif (code == 'M')
                    {   ActivateGadget(ST11_3rdManuf, MainWindowPtr, NULL);
        }   }   }   }
        elif (class == IDCMP_GADGETUP)
        {   if (addr == BU99_Right)
            {   page = 0;
            } elif (addr == BU11_Sender)
            {   page = 12;
            } elif (addr == BU11_Config)
            {   page = 13;
            } elif (addr == BU99_TextEditor)
            {   if (wbval <= 43)
                {   savereport(FALSE);
                }
                launcheditor();
            }
            elif (addr == CY11_Type)
            {   report.type = code;
                updatereportgadgets();
            } elif (report.type != COM && addr == LV11_Subsystem)
            {   // code is the position within the list.
                report.subsystem = code;
            } elif (report.type != ENH)
            {   if (addr == CY11_Severity)
                {   report.severity = code;
                    if (report.type == BUG && report.severity == 3)
                    {   report.severity = 0;
                        GT_SetGadgetAttrs
                        (   CY11_Severity,
                            MainWindowPtr,
                            NULL,
                            GTCY_Active, report.severity,
                            TAG_DONE
                        );
                }   }
                elif (report.type == BUG)
                {   if (addr == ST11_Pathname)
                    {   refreshpv();
                    } elif (addr == BU11_PathnameASL)
                    {   asl();
                        GT_SetGadgetAttrs
                        (   ST11_Pathname,
                            MainWindowPtr,
                            NULL,
                            GTST_String, aslresult,
                            TAG_DONE
                        );
                        refreshpv();
    }   }   }   }   }
    elif (page == 12)
    {   if (class == IDCMP_GADGETUP)
        {   if (addr == BU99_Right)
            {   if (certified)
                    page = 33;
                else page = 11;
        }   }
        elif (class == IDCMP_VANILLAKEY)
        {   code = toupper(code);
            if (code == ESCAPE)
            {   if (certified)
                    page = 33;
                else page = 11;
            } elif (code == 'F')
            {   ActivateGadget(ST12_FirstName, MainWindowPtr, NULL);
            } elif (code == 'L')
            {   ActivateGadget(ST12_LastName,  MainWindowPtr, NULL);
            } elif (code == 'C')
            {   ActivateGadget(ST12_Company,   MainWindowPtr, NULL);
            } elif (code == 'D')
            {   ActivateGadget(ST12_Developer, MainWindowPtr, NULL);
            } elif (code == 'P')
            {   ActivateGadget(ST12_Phone,     MainWindowPtr, NULL);
            } elif (code == 'E')
            {   ActivateGadget(ST12_EMail,     MainWindowPtr, NULL);
    }   }   }
    elif (page == 13)
    {   if (class == IDCMP_VANILLAKEY)
        {   code = toupper(code);
            if (code == ESCAPE)
            {   page = 11;
            } elif (code == 'A')
            {   if ((code & IEQUALIFIER_LSHIFT) || (code & IEQUALIFIER_RSHIFT))
                {   if (report.agnus == 0)
                        report.agnus = 5;
                    else report.agnus--;
                } else
                {   if (report.agnus == 5)
                        report.agnus = 0;
                    else report.agnus++;
                }
                if (report.agnus == 0)
                    report.denise = 0;
                elif (report.agnus == 1 || report.agnus == 2)
                    report.denise = 1;
                else
                {   /* assert(report.agnus == 3 || report.agnus == 4); */
                    report.denise = 2;
                }
                GT_SetGadgetAttrs
                (   MX13_Agnus,
                    MainWindowPtr,
                    NULL,
                    GTMX_Active, report.agnus,
                    TAG_DONE
                );
                GT_SetGadgetAttrs
                (   MX13_Denise,
                    MainWindowPtr,
                    NULL,
                    GTMX_Active, report.denise,
                    TAG_DONE
                );
            } elif (code == 'C')
            {   ActivateGadget(ST13_Chip, MainWindowPtr, NULL);
            } elif (code == 'E')
            {   ActivateGadget(ST13_Expansion, MainWindowPtr, NULL);
            } elif (code == 'H')
            {   ActivateGadget(ST13_Hard, MainWindowPtr, NULL);
            } elif (code == 'L')
            {   if ((code & IEQUALIFIER_LSHIFT) || (code & IEQUALIFIER_RSHIFT))
                {   if (report.denise == 0)
                        report.denise = 3;
                    else report.denise--;
                } else
                {   if (report.denise == 3)
                        report.denise = 0;
                    else report.denise++;
                }
                GT_SetGadgetAttrs
                (   MX13_Denise,
                    MainWindowPtr,
                    NULL,
                    GTMX_Active, report.denise,
                    TAG_DONE
                );
            } elif (code == 'M')
            {   if ((code & IEQUALIFIER_LSHIFT) || (code & IEQUALIFIER_RSHIFT))
                {   if (report.model == 0)
                        report.model = MODELS;
                    else report.model--;
                } else
                {   if (report.model == CPUS)
                        report.model = 0;
                    else report.model++;
                }
                GT_SetGadgetAttrs
                (   MX13_Model,
                    MainWindowPtr,
                    NULL,
                    GTMX_Active, report.model,
                    TAG_DONE
                );
            } elif (code == 'N')
            {   ActivateGadget(IN13_Floppies, MainWindowPtr, NULL);
            } elif (code == 'P')
            {   if ((code & IEQUALIFIER_LSHIFT) || (code & IEQUALIFIER_RSHIFT))
                {   if (report.cpu == 0)
                        report.cpu = CPUS;
                    else report.cpu--;
                } else
                {   if (report.cpu == CPUS)
                        report.cpu = 0;
                    else report.cpu++;
                }
                GT_SetGadgetAttrs
                (   MX13_CPU,
                    MainWindowPtr,
                    NULL,
                    GTMX_Active, report.cpu,
                    TAG_DONE
                );
            } elif (code == 'S')
            {   ActivateGadget(ST13_Fast, MainWindowPtr, NULL);
        }   }
        elif (class == IDCMP_GADGETUP)
        {   if (addr == BU99_Right)
                page = 11;
            elif (addr == IN13_Floppies)
            {   report.floppies = ((struct StringInfo *) IN13_Floppies->SpecialInfo)->LongInt;
                if (report.floppies < 0)
                {   report.floppies = 0;
                    GT_SetGadgetAttrs
                    (   IN13_Floppies,
                        MainWindowPtr,
                        NULL,
                        GTIN_Number, report.floppies,
                        TAG_DONE
                    );
                } elif (report.floppies > 3)
                {   report.floppies = 3;
                    GT_SetGadgetAttrs
                    (   IN13_Floppies,
                        MainWindowPtr,
                        NULL,
                        GTIN_Number, report.floppies,
                        TAG_DONE
                    );
        }   }   }
        elif (class == IDCMP_GADGETDOWN)
        {   if (addr == MX13_Model)
                report.model = code;
            elif (addr == MX13_CPU)
                report.cpu = code;
            elif (addr == MX13_Denise)
                report.denise = code;
            elif (addr == MX13_Agnus)
            {   report.agnus = code;
                if (code == 0)
                    report.denise = 0;
                elif (code == 1 || code == 2)
                    report.denise = 1;
                else
                {   /* assert(code == 3 || code == 4); */
                    report.denise = 2;
                }
                GT_SetGadgetAttrs
                (   MX13_Denise,
                    MainWindowPtr,
                    NULL,
                    GTMX_Active, report.denise,
                    TAG_DONE
                );
}   }   }   }

MODULE void refreshpv(void)
{	UBYTE	i;
	BPTR	FileHandle;

	strcpy(string, "C:Version ");
	strcat
	(   string,
            ((struct StringInfo *) ST11_Pathname->SpecialInfo)->Buffer
	);
        if (!(FileHandle = (BPTR) Open("T:ReportPlus.temp", MODE_NEWFILE)))
	    rq("Can't open T:ReportPlus.temp for writing!");
	if (!Execute(string, NULL, FileHandle))
	    rq("Can't execute C:Version!");
	if (!Close(FileHandle))
	    rq("Can't close T:ReportPlus.temp for writing!");

        readordie("T:ReportPlus.temp");

	DeleteFile("T:ReportPlus.temp"); /* returns FALSE for failure */
	for (i = 0; i <= MEDFIELD; i++)
            if (IOBuffer[i] == LF)
            {   IOBuffer[i] = 0;
                break;
            }
	GT_SetGadgetAttrs
        (   ST11_Version,
	    MainWindowPtr,
	    NULL,
	    GTST_String, IOBuffer,
	    TAG_DONE
	);
}

AGLOBAL void report_exit(void)
{   if (SubsystemListPtr)
    {   FreeNameNodes(SubsystemListPtr);
        FreeMem(SubsystemListPtr, sizeof(struct List));
        SubsystemListPtr = NULL;
}   }

AGLOBAL void report_init(void)
{   ULONG i;

    if (!(SubsystemListPtr = AllocMem(sizeof(struct List), MEMF_CLEAR)))
        rq("Out of memory!");
    NewList(SubsystemListPtr);
    for (i = 0; i <= SUBSYSTEMS; i++)
        AddNameToTail(SubsystemListPtr, subsystems[i].friendly);

    newreport(FALSE);
}

AGLOBAL void sender(void)
{   /* PAGE 12 *************************************************************/

    verynewwindow
    (   SENDERWIDTH, SENDERHEIGHT,
        "Report+: Sender Details",
        BUTTONIDCMP | STRINGIDCMP
    );

    if ((!report.loaded) && readin("S:Report.sender"))
    {   /* # Refer: <last>,<first> (<company> ,phone <phone>)<LF>
           # Path: <email><LF>
           # ReferID: <developer><LF> */

        offset = 0;
        parse("# Refer: ");
        parse(",");
        strcpy(report.lastname,  string);
        parse(" (");
        strcpy(report.firstname, string);
        parse(" ,phone ");
        strcpy(report.company,   string);
        parse(")\n# Path: ");
        strcpy(report.phone,     string);
        parse("\n# ReferID: ");
        strcpy(report.email,     string);
        parse("\n");
        strcpy(report.developer, string);
    }

    /* first name */
    setgadget(166, 22, 128, 12, "_First name:", NULL);
    ST12_FirstName = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
	PrevGadPtr,
	&Gadget,
	GTST_String, &(report.firstname),
	GTST_MaxChars, MEDFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* last name */
    setgadget(166, 34, 128, 12, "_Last name:", NULL);
    ST12_LastName = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
	PrevGadPtr,
	&Gadget,
	GTST_String, &(report.lastname),
	GTST_MaxChars, MEDFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* company name */
    setgadget(166, 46, 128, 12, "_Company:", NULL);
    ST12_Company = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
	PrevGadPtr,
	&Gadget,
	GTST_String, &(report.company),
	GTST_MaxChars, MEDFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* phone */
    setgadget(166, 58, 128, 12, "_Phone number:", NULL);
    ST12_Phone = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
	PrevGadPtr,
	&Gadget,
	GTST_String, &(report.phone),
	GTST_MaxChars, MEDFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* developer number */
    setgadget(166, 70, 128, 12, "_Developer number:", NULL);
    ST12_Developer = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
	PrevGadPtr,
	&Gadget,
        GTST_String, &(report.developer),
        GTST_MaxChars, LONGFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* email */
    setgadget(166, 82, 256, 12, "_EMail:", NULL);
    ST12_EMail = PrevGadPtr = (struct Gadget *) CreateGadget
    (	STRING_KIND,
	PrevGadPtr,
	&Gadget,
	GTST_String, &(report.email),
	GTST_MaxChars, MEDFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* There are 14 gadgets:
       BU99_Right
       BU99_TextEditor
       ST12_FirstName (2 subgadgets)
       ST12_LastName (2 subgadgets)
       ST12_Company (2 subgadgets)
       ST12_Phone (2 subgadgets)
       ST12_Developer (2 subgadgets)
       ST12_EMail (2 subgadgets) */
    drawgadgets(14);

    ActivateGadget(ST12_FirstName, MainWindowPtr, NULL);
    loop();

    if (!report.loaded)
    {   /* write out S:Report.sender
        # Refer: <last>,<first> (<company> ,phone <phone>)<LF>
        # Path: <email><LF>
        # ReferID: <developer><LF> */

        strcpy(report.refer, "# Refer: ");
        strcat
        (   report.refer,
            ((struct StringInfo *) ST12_LastName->SpecialInfo)->Buffer
        );
        strcat(report.refer, ",");
        strcat
        (   report.refer,
            ((struct StringInfo *) ST12_FirstName->SpecialInfo)->Buffer
        );
        strcat(report.refer, " (");
        strcat
        (   report.refer,
            ((struct StringInfo *) ST12_Company->SpecialInfo)->Buffer
        );
        strcat(report.refer, " ,phone ");
        strcat
        (   report.refer,
            ((struct StringInfo *) ST12_Phone->SpecialInfo)->Buffer
        );
        strcat(report.refer, ")\n");

        strcpy(report.path, "# Path: ");
        strcat
        (	report.path,
            ((struct StringInfo *) ST12_EMail->SpecialInfo)->Buffer
        );
        strcat(report.path, "\n");

        strcpy(report.referid, "# ReferID: ");
        strcat
        (   report.referid,
            ((struct StringInfo *) ST12_Developer->SpecialInfo)->Buffer
        );
        strcat(report.referid, "\n");

        strcpy(IOBuffer, report.refer);
        strcat(IOBuffer, report.path);
        strcat(IOBuffer, report.referid);
    
        writeout("S:Report.sender");
    }
    closewindow();
}
    
AGLOBAL void config(void)
{   /* PAGE 13 ************************************************************** */
    
    UBYTE i;
    	
    verynewwindow
    (   CONFIGWIDTH, CONFIGHEIGHT,
        "Report+: Configuration Details",
        BUTTONIDCMP | STRINGIDCMP | MXIDCMP
    );
    
    if ((!report.loaded) && readin("S:Report.config"))
    {   /*  # Config: <model>,<cpu>,A=AA|ECS-pal|ECS|old-pal|old,
            D=AA|ECS|old,RAM=<chip>megC/<fast>megF,TD=<floppies>,
            HD=<controller>,<cards><LF> */

        offset = 0;
        parse("# Config: ");
	parse(",");
        report.model = 4;
	for (i = 0; i <= MODELS; i++)
	{   if (!stricmp(string, ModelOptions[i]))
	    {   report.model = i;
                break; // for speed
	}   }
        parse(",A=");
	report.cpu = 1;
	for (i = 0; i <= CPUS; i++)
	{   if (!stricmp(string, CPUOptions[i]))
	    {   report.cpu = i;
                break; // for speed
        }   }

	parse(",D=");
	if (!stricmp(string, "AA"))
	    report.agnus = 0;
	elif (!stricmp(string, "ECS-pal"))
	    report.agnus = 1;
	elif (!stricmp(string, "ECS"))
	    report.agnus = 2;
	elif (!stricmp(string, "old-pal"))
	    report.agnus = 3;
	else /* if (!stricmp(string, "old")) */
	    report.agnus = 4;

	parse(",RAM=");
	if (!stricmp(string, "AA"))
	    report.denise = 0;
	elif (!stricmp(string, "ECS"))
	    report.denise = 1;
	else /* if (!stricmp(string, "old")) */
	    report.denise = 2;

	parse("megC/");
	strcpy(report.chipram, string);

	parse("megF,TD=");
	strcpy(report.fastram, string);

	parse(",HD=");
	report.floppies = atol(string);

	parse(",");
	strcpy(report.hard, string);

	parse("\n");
	strcpy(report.expansion, string);
    }

    /* These formal coordinates of these text gadgets must not overlap any
    other gadgets, otherwise any such overlapped gadgets will not be
    selectable, with the mouse at least. This definitely applies to radio
    and string gadgets, and most likely other types.

    model */
    setgadget(64, 30, 6 * FONTX, 0, "_Model:", PLACETEXT_ABOVE);
    TE13_ModelText = PrevGadPtr = (struct Gadget *) CreateGadget
    (   TEXT_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );
    setgadget(64, 30, 0, 0, NULL, PLACETEXT_RIGHT);
    MX13_Model = PrevGadPtr = (struct Gadget *) CreateGadget
    (   MX_KIND,
        PrevGadPtr,
        &Gadget,
        GTMX_Labels, &ModelOptions,
        GTMX_Active, report.model,
        TAG_DONE
    );

    /* Agnus */
    setgadget(192, 30, 17 * FONTX, 0, "_Agnus/Alice Type:", PLACETEXT_ABOVE);
    TE13_AgnusText = PrevGadPtr = (struct Gadget *) CreateGadget
    (   TEXT_KIND,
	PrevGadPtr,
	&Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );
    setgadget(192, 30, 0, 0, NULL, PLACETEXT_RIGHT);
    MX13_Agnus = PrevGadPtr = (struct Gadget *) CreateGadget
    (   MX_KIND,
	PrevGadPtr,
	&Gadget,
	GTMX_Labels, &AgnusOptions,
	GTMX_Active, report.agnus,
	TAG_DONE
    );

    /* Denise */
    setgadget(352, 30, 17 * FONTX, 0, "Denise/_Lisa Type:", PLACETEXT_ABOVE);
    TE13_DeniseText = PrevGadPtr = (struct Gadget *) CreateGadget
    (   TEXT_KIND,
	PrevGadPtr,
	&Gadget,
        GT_Underscore, '_',
	TAG_DONE
    );
    setgadget(352, 30, 0, 0, NULL, PLACETEXT_RIGHT);
    MX13_Denise = PrevGadPtr = (struct Gadget *) CreateGadget
    (   MX_KIND,
        PrevGadPtr,
        &Gadget,
        GTMX_Labels, &DeniseOptions,
        GTMX_Active, report.denise,
        TAG_DONE
    );

    /* CPU */
    setgadget(512, 30, 10 * FONTX, 0, "_Processor:", PLACETEXT_ABOVE);
    // extra spaces ensure consistent centring
    TE13_CPUText = PrevGadPtr = (struct Gadget *) CreateGadget
    (   TEXT_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );
    setgadget(512, 30, 0, 0, NULL, PLACETEXT_RIGHT);
    MX13_CPU = PrevGadPtr = (struct Gadget *) CreateGadget
    (   MX_KIND,
        PrevGadPtr,
        &Gadget,
        GTMX_Labels, &CPUOptions,
        GTMX_Active, report.cpu,
        TAG_DONE
    );

    /* chip RAM */
    setgadget(465, 110, 1, 12, "Mb", PLACETEXT_RIGHT);
    TE13_ChipText = PrevGadPtr = (struct Gadget *) CreateGadget
    (   TEXT_KIND,
        PrevGadPtr,
        &Gadget,
        TAG_DONE
    );
    setgadget(400, 110, 64, 12, "_Chip RAM:", NULL);
    ST13_Chip = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        GTST_String, &(report.chipram),
        GTST_MaxChars, 4,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );

    // slow/fast RAM
    setgadget(465, 122, 1, 12, "Mb", PLACETEXT_RIGHT);
    TE13_FastText = PrevGadPtr = (struct Gadget *) CreateGadget
    (   TEXT_KIND,
        PrevGadPtr,
        &Gadget,
        TAG_DONE
    );
    setgadget(400, 122, 64, 12, "_Slow/fast RAM:", NULL);
    ST13_Fast = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        GTST_String, &(report.fastram),
        GTST_MaxChars, 4,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );

    /* floppies */
    setgadget(400, 134, 64, 12, "_Number of floppies:", NULL);
    IN13_Floppies = PrevGadPtr = (struct Gadget *) CreateGadget
    (   INTEGER_KIND,
	PrevGadPtr,
	&Gadget,
	GTIN_Number, report.floppies,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* hard disk controller */
    setgadget(400, 146, 128, 12, "_Hard disk controller:", NULL);
    ST13_Hard = PrevGadPtr = (struct Gadget *) CreateGadget
    (	STRING_KIND,
	PrevGadPtr,
	&Gadget,
	GTST_String, &(report.hard),
	GTST_MaxChars, MEDFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* expansion cards */
    setgadget(400, 158, 228, 12, "_Expansion cards:", NULL);
    ST13_Expansion = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
	GTST_String, &(report.expansion),
	GTST_MaxChars, LONGFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* There are 47 gadgets:
       BU99_Right      ( 1) = 1
       TE13_ModelText  ( 1) = 3
       MX13_Model      (14) =17
                            =18
       TE13_AgnusText  ( 1) =19
       MX13_Agnus      ( 5) =24
       TE13_DeniseText ( 1) =25
       MX13_Denise     ( 3) =28
       TE13_CPUText    ( 1) =29
       MX13_CPU        ( 7) =36
       TE13_ChipText   ( 1) =37
       ST13_Chip       ( 2) =39
       TE13_FastText   ( 1) =40
       ST13_Fast       ( 2) =42
       IN13_Floppies   ( 2) =44
       ST13_Hard       ( 2) =46
       ST13_Expansion  ( 2) =48 */
    drawgadgets(47);
    ActivateGadget(ST13_Chip, MainWindowPtr, NULL);
    loop();

    strcpy(report.chipram,   ((struct StringInfo *) ST13_Chip->SpecialInfo)->Buffer);
    strcpy(report.fastram,   ((struct StringInfo *) ST13_Fast->SpecialInfo)->Buffer);
    strcpy(report.hard,      ((struct StringInfo *) ST13_Hard->SpecialInfo)->Buffer);
    report.floppies        = ((struct StringInfo *) IN13_Floppies->SpecialInfo)->LongInt;
    if (report.floppies < 0)
    {   report.floppies = 0;
    } elif (report.floppies > 3)
    {   report.floppies = 3;
    }
    strcpy(report.expansion, ((struct StringInfo *) ST13_Expansion->SpecialInfo)->Buffer);

    if (!report.loaded)
    {   strcpy(report.config, "# Config: ");
        strcpy(string, ModelOptions[report.model]);
        strlwr(string);
        strcat(report.config, string);
        strcat(report.config, ",");
        strcpy(string, CPUOptions[report.cpu]);
        strlwr(string);
        strcat(report.config, string);
        strcat(report.config, ",A=");
        switch(report.agnus)
        {
        case 0:
            strcat(report.config, "AA");
        break;
        case 1:
            strcat(report.config, "ECS-pal");
        break;
        case 2:
            strcat(report.config, "ECS");
        break;
        case 3:
            strcat(report.config, "old-pal");
        break;
        default:
            strcat(report.config, "old");
        break;
        }
        strcat(report.config, ",D=");
        switch(report.denise)
        {
        case 0:
            strcat(report.config, "AA");
        break;
        case 1:
            strcat(report.config, "ECS");
        break;
        default:
            strcat(report.config, "old");
        break;
        }
        strcat(report.config, ",RAM=");
        strcat(report.config, report.chipram);
        strcat(report.config, "megC/");
        strcat(report.config, report.fastram);
        strcat(report.config, "megF,TD=");
        stcl_d(string, report.floppies);
        strcat(report.config, string);
        strcat(report.config, ",HD=");
        strcat(report.config, report.hard);
        strcat(report.config, ",");
        strcat(report.config, report.expansion);
        strcat(report.config, "\n");
        strcpy(IOBuffer, report.config);
        writeout("S:Report.config");
    }
    closewindow();
}

MODULE void updatereportgadgets(void)
{   // the following command is only needed when New or Open... is the
    // cause of the update.
    GT_SetGadgetAttrs
    (   ST11_Summary,
        MainWindowPtr,
        NULL,
        GTST_String, &(report.summary),
        TAG_DONE
    );

    if (report.type == BUG && report.severity == 3)
    {   report.severity = 0;
    }

    GT_SetGadgetAttrs
    (   CY11_Type,
        MainWindowPtr,
        NULL,
        GTCY_Active, report.type,
        TAG_DONE
    );
    GT_SetGadgetAttrs
    (   LV11_Subsystem,
        MainWindowPtr,
        NULL,
        GTLV_Selected, report.subsystem,
        TAG_DONE
    );
    if
    (   (!strcmp(subsystems[report.subsystem].unfriendly, "wormwars"))
     || (!strcmp(subsystems[report.subsystem].unfriendly, "report+"))
    )
    {   GT_SetGadgetAttrs
        (   TE11_EMailTo,
            MainWindowPtr,
            NULL,
            GTTX_Text, "amigansoftware@altavista.com",
            TAG_DONE
        );
    } else
    {   GT_SetGadgetAttrs
        (   TE11_EMailTo,
            MainWindowPtr,
            NULL,
            GTTX_Text, "support@haage-partner.com",
            TAG_DONE
        );
    }

    if (report.type == BUG)
    {   GT_SetGadgetAttrs
        (   ST11_Pathname,
            MainWindowPtr,
            NULL,
            GTST_String, report.pp,
            GA_Disabled, FALSE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   BU11_PathnameASL,
            MainWindowPtr,
            NULL,
            GA_Disabled, FALSE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST11_Version,
            MainWindowPtr,
            NULL,
            GTST_String, report.pv,
            GA_Disabled, FALSE,
            TAG_DONE
        );
    } else
    {   GT_SetGadgetAttrs
        (   ST11_Pathname,
            MainWindowPtr,
            NULL,
            GTST_String, report.pp,
            GA_Disabled, TRUE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   BU11_PathnameASL,
            MainWindowPtr,
            NULL,
            GA_Disabled, TRUE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST11_Version,
            MainWindowPtr,
            NULL,
            GTST_String, report.pv,
            GA_Disabled, TRUE,
            TAG_DONE
        );
    }
    if (report.type == COM)
    {   GT_SetGadgetAttrs
        (   LV11_Subsystem,
            MainWindowPtr,
            NULL,
            GA_Disabled, TRUE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST11_3rdName,
            MainWindowPtr,
            NULL,
            GTST_String, report.thirdname,
            GA_Disabled, FALSE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST11_3rdVer,
            MainWindowPtr,
            NULL,
            GTST_String, report.thirdver,
            GA_Disabled, FALSE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST11_3rdManuf,
            MainWindowPtr,
            NULL,
            GTST_String, report.thirdmanuf,
            GA_Disabled, FALSE,
            TAG_DONE
        );
    } else
    {   GT_SetGadgetAttrs
        (   LV11_Subsystem,
            MainWindowPtr,
            NULL,
            GA_Disabled, FALSE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST11_3rdName,
            MainWindowPtr,
            NULL,
            GTST_String, report.thirdname,
            GA_Disabled, TRUE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST11_3rdVer,
            MainWindowPtr,
            NULL,
            GTST_String, report.thirdver,
            GA_Disabled, TRUE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST11_3rdManuf,
            MainWindowPtr,
            NULL,
            GTST_String, report.thirdmanuf,
            GA_Disabled, TRUE,
            TAG_DONE
        );
    }
    if (report.type == ENH)
    {   GT_SetGadgetAttrs
        (   ST11_Debug,
            MainWindowPtr,
            NULL,
            GTST_String, report.debug,
            GA_Disabled, TRUE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   CY11_Severity,
            MainWindowPtr,
            NULL,
            GA_Disabled, TRUE,
            GTCY_Active, report.severity,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST11_KS,
            MainWindowPtr,
            NULL,
            GTST_String, report.ks,
            GA_Disabled, TRUE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST11_WB,
            MainWindowPtr,
            NULL,
            GTST_String, report.wb,
            GA_Disabled, TRUE,
            TAG_DONE
        );
    } else
    {   GT_SetGadgetAttrs
        (   ST11_Debug,
            MainWindowPtr,
            NULL,
            GTST_String, report.debug,
            GA_Disabled, FALSE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   CY11_Severity,
            MainWindowPtr,
            NULL,
            GA_Disabled, FALSE,
            GTCY_Active, report.severity,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST11_KS,
            MainWindowPtr,
            NULL,
            GTST_String, report.ks,
            GA_Disabled, FALSE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   ST11_WB,
            MainWindowPtr,
            NULL,
            GTST_String, report.wb,
            GA_Disabled, FALSE,
            TAG_DONE
        );
}   }

AGLOBAL void newreport(ABOOL display)
{   ULONG i;

    report.floppies  = 1;
    report.agnus     = 0;
    report.denise    = 0;
    report.cpu       = 2;
    report.model     = 4;
    report.type      = 0;
    report.severity  = 0;
    report.subsystem = 0;
    strcpy(report.chipram,    "2");
    strcpy(report.fastram,    "6");
    strcpy(report.hard,       "");
    strcpy(report.debug,      "");
    strcpy(report.developer,  "");
    strcpy(report.expansion,  "");
    strcpy(report.summary,    "");
    if (GetVar("Kickstart", &(report.ks), 6, NULL) == -1)
        report.ks[0] = 0;
    if (GetVar("Workbench", &(report.wb), 6, NULL) == -1)
        report.wb[0] = 0;
    strcpy(report.pv,         "");
    strcpy(report.pp,         "");
    strcpy(report.thirdname,  "");
    strcpy(report.thirdver,   "");
    strcpy(report.thirdmanuf, "");
    strcpy(report.lastname,   "");
    strcpy(report.firstname,  "");
    strcpy(report.company,    "");
    strcpy(report.phone,      "");
    strcpy(report.email,      "");
    strcpy(report.refer,      "");
    strcpy(report.referid,    "");
    strcpy(report.path,       "");
    strcpy(report.config,     "");
    strcpy(report.output,     "");
    for (i = 0; i <= 5; i++)
    {   report.textfield[i][0] = 0;
    }
    report.loaded = FALSE;

    /* Quicker than strcpy(report.foo, ""); is report.foo[0] = 0;

    Consider linking bug report generator with ID database to
    automatically generate the list of expansion cards. */

    if (display)
    {   updatereportgadgets();
}   }

AGLOBAL void openreport(void)
{   asl();
    if (aslresult[0])
    {   loadreport();
        updatereportgadgets();
    } else DisplayBeep(NULL);
}

AGLOBAL void loadreport(void)
{   ULONG i;

    /* parse() returns when it has moved along and found the specified
       `ending string'. The contents, since last parse(), before the
       `ending string' are returned in string. */

    if (readin(aslresult))
    {   strcpy(report.output, aslresult);
        report.loaded = TRUE;

        offset = 0;
        parse("# Subject: ");           // skip '# Subject: '
        parse("\n# Type: ");            // goto end of '\n# Type: '
        strcpy(report.summary, string);
        parse("\n# ");
        if (!strcmp(string, "bug"))
        {   report.type = BUG;
        } elif (!strcmp(string, "compat"))
        {   report.type = COM;
        } elif (!strcmp(string, "enhancement"))
        {   report.type = ENH;
        }
        if (report.type != COM)
        {   parse("Subsystem: ");
            parse("\n");
            for (i = 0; i <= SUBSYSTEMS; i++)
            {   if (!strcmp(string, subsystems[i].unfriendly))
                {   report.subsystem = i;
                    break;
        }   }   }
        else
        {   parse("ProductName: ");
            parse(" (vers=");
            strcpy(report.thirdname,  string);
            parse(")\n# ProductInfo: :");
            strcpy(report.thirdver,   string);
            parse(":\n");
            strcpy(report.thirdmanuf, string);
        }
        parse("# Severity: ");
        parse("\n# ");
        if (!strcmp(string, "a"))
        {   report.severity = 0;
        } elif (!strcmp(string, "b"))
        {   report.severity = 1;
        } elif (!strcmp(string, "c"))
        {   report.severity = 2;
        } elif (!strcmp(string, "ok"))
        {   report.severity = 3;
        } elif (!strcmp(string, "e"))
        {   report.type     = ENH;
        }

        if (report.type != ENH)
        {   parse("Release: KS=");
            parse(",WB=");
            strcpy(report.ks, string);
            if (report.type == BUG)
            {   parse(",Program=");
                strcpy(report.wb, string);
                parse("\n");
                strcpy(report.pv, string);
            } else
            {   // assert(report.type == COM);
                parse("\n");
                strcpy(report.wb, string);
                report.pv[0] = 0;
            }
        } else report.pv[0] = 0;
        parse("# Date: ");

        // now sender fields
        parse("# Refer: ");
        parse(",");
        strcpy(report.lastname, string);
        parse(" (");
        strcpy(report.firstname, string);
        parse(" ,phone ");
        strcpy(report.company, string);
        parse(")\n# Path: ");
        strcpy(report.phone, string);
        parse("\n# ReferID: ");
        strcpy(report.email, string);
        parse("\n");
        strcpy(report.developer, string);

        // now config fields
        parse("# Config: ");
	parse(",");
	report.model = 4;
	for (i = 0; i <= MODELS; i++)
	{   if (!stricmp(string, ModelOptions[i]))
	    {   report.model = i;
                break; // for speed
	}   }
        parse(",A=");
	report.cpu = 1;
	for (i = 0; i <= CPUS; i++)
	{   if (!stricmp(string, CPUOptions[i]))
	    {   report.cpu = i;
                break; // for speed
        }   }

	parse(",D=");
	if (!stricmp(string, "AA"))
	    report.agnus = 0;
	elif (!stricmp(string, "ECS-pal"))
	    report.agnus = 1;
	elif (!stricmp(string, "ECS"))
	    report.agnus = 2;
	elif (!stricmp(string, "old-pal"))
	    report.agnus = 3;
	else /* if (!stricmp(string, "old")) */
	    report.agnus = 4;

	parse(",RAM=");
	if (!stricmp(string, "AA"))
	    report.denise = 0;
	elif (!stricmp(string, "ECS"))
	    report.denise = 1;
	else /* if (!stricmp(string, "old")) */
	    report.denise = 2;

	parse("megC/");
	strcpy(report.chipram, string);

	parse("megF,TD=");
	strcpy(report.fastram, string);

	parse(",HD=");
	report.floppies = atol(string);

	parse(",");
	strcpy(report.hard, string);

	parse("\n");
        strcpy(report.expansion, string);

        report.pp[0] = 0;

        if (report.type == BUG)
        {   parse("### BRIEF BUG DESCRIPTION:\n");
            parse("\n### BUG GENERATION PROCEDURE OR EXAMPLE:\n");
            strcpy(report.textfield[0], string);     // bug description
            parse("\n### ALSO RUNNING:\n");
            strcpy(report.textfield[1], string);     // bug procedure
            parse("\n### IF THIS WORKS DIFFERENTLY ON OTHER VERSIONS "
                  "OR HARDWARE, EXPLAIN:\n");
            strcpy(report.debug, string);            // also running
            parse("\n### RELATED PROBLEMS:\n");
            strcpy(report.textfield[2], string);     // explain differently
            parsetoend();
            strcpy(report.textfield[3], string);     // related problems
        } elif (report.type == COM)
        {   if (report.severity != 3)
            {   parse("### BRIEF BUG DESCRIPTION:\n");
                parse("\n### BUG GENERATION PROCEDURE OR EXAMPLE:\n");
                strcpy(report.textfield[0], string); // bug description
                parse("\n### ALSO RUNNING:\n");
                strcpy(report.textfield[1], string); // bug procedure
                parse("\n### IF THIS WORKS DIFFERENTLY ON OTHER VERSIONS "
                      "OR HARDWARE, EXPLAIN:\n");
                strcpy(report.debug, string);        // also running
                parse("\n### WHAT DEVELOPER IS DOING IN THAT AREA OF SW "
                      "OR HW:\n");
                strcpy(report.textfield[2], string); // explain differently
                parse("\n### RELATED PROBLEMS:\n");
                strcpy(report.textfield[3], string); // what doing?
                parsetoend();
                strcpy(report.textfield[4], string); // related problems
            } else
            {   parse("### BRIEF BUG DESCRIPTION:\n");
                parse("\n### BUG GENERATION PROCEDURE OR EXAMPLE:\n");
                strcpy(report.textfield[0], string); // bug description
                parse("\n### WHAT DEVELOPER IS DOING IN THAT AREA OF SW "
                      "OR HW:\n");
                strcpy(report.textfield[1], string); // explain differently
                parse("\n### RELATED PROBLEMS:\n");
                strcpy(report.textfield[2], string); // what doing?
                parsetoend();
                strcpy(report.textfield[3], string); // related problems
        }   }
        else
        {   // assert(report.type == ENH);
            parse("### ENHANCEMENT REQUEST:\n");
            parsetoend();
            strcpy(report.textfield[0], string);
        }
        updatereportgadgets();
}   }

/*          # Subject: <subject><LF>
            # Type: bug|compat|enhancement<LF>
BUG,ENH     # Subsystem: <subsystem><LF>
COM         # ProductName: <name> (vers=<version>)
COM         # ProductInfo: :<manufacturer>:
            # Severity: a|b|c|ok|e
BUG         # Release: KS=<version>,WB=<version>,Program=<version>
COM         # Release: KS=<version>,WB=<version>
            # Date: <weekday> dd-Mon-yy hh:mm:ss
            # Refer: <refer>
            # Path: <path>
            # ReferID: <referid>
            # Config: <config>
BUG,COMa-c  ### BRIEF BUG DESCRIPTION:
BUG,COMa-c  ### BUG GENERATION PROCEDURE OR EXAMPLE:
BUG,COM     ### ALSO RUNNING:
            <debug>
BUG,COM     ### IF THIS WORKS DIFFERENTLY ON OTHER VERSIONS OR HARDWARE,
            EXPLAIN:
COMa-c	    ### WHAT DEVELOPER IS DOING IN THAT AREA OF SW OR HW:	
BUG,COMa-c  ### RELATED PROBLEMS:
ENH         ### ENHANCEMENT REQUEST: */

