/*  QuickReq V2.0   (c) 1990,1991 by Markus Aalto

    QuickReq.c  :   14.12.90 - 09.01.91

*/

#include "exec/types.h"
#include "exec/memory.h"
#include "intuition/intuition.h"
#include "intuition/screens.h"
#include "intuition/intuitionbase.h"
#include "graphics/text.h"
#include "graphics/gfxbase.h"
#include "graphics/gfx.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "ctype.h"
#include "proto/intuition.h"
#include "proto/exec.h"
#include "proto/dos.h"

/* No CTRL-C checking */
#ifdef LATTICE
int CXBRK(VOID) {return(0);}
#endif

/* Protos for my own functions */
int ParseCommands(int, register char *, char **), ReadNumber(char **);
char *AllocNormMem(int);
VOID main(int, char **), Print(char *), ReadRedirFile(char **);
VOID CleanUp(BOOL , char *,ULONG ), PrintUsage(VOID);
USHORT CheckParameters(int , char **), TestWidth(struct IntuiText *);
struct IntuiText *MakeIntuText(char *, USHORT, USHORT);

#define MINWINDOWWIDTH 86
#define MINWINDOWHEIGHT 54
#define INTUILIB    "intuition.library"
#define GFXLIB      "graphics.library"
#define IPOINT ((struct IntuiText *)-1)
#define MAXARG 32              /* maximum command line arguments */
#define QUOTE  '"'

struct  IntuitionBase *IntuitionBase;
struct  GfxBase *GfxBase;
struct  Remember *RememberKey;
char    *text[3];
USHORT  ForceWidth, ForceHeight, PenNumber;
ULONG   MaxCols;
BOOL    CENTER_ON = FALSE;
BOOL    BEEP_ON = FALSE;
BOOL    LARGE_ON = FALSE;
BOOL    FWIDTH_ON = FALSE;
BOOL    FHEIGHT_ON = FALSE;
BOOL    OWNPEN_ON = FALSE;

/*  Well, This is very important */

char UsageString[] = {
    'Q','u','i','c','k','R','e','q',' ','V','2','.','0',' ',169,' ','1','9',
    '9','1',' ','b','y',' ',0x9b,'1','m','M','a','r','k','u','s',' ','A','a',
    'l','t','o',0x9b,'0','m','\n',0
};

/*  This is something I may choose not to be defined here because of KS2.0 and
    it's switchable and scalable fonts, but for now I just do it in easy way.
*/
struct TextAttr MyTopaz8 = {
    "topaz.font",
    8, FS_NORMAL, FPF_ROMFONT
};

VOID main(int argc, char *argv[])
{
    struct  Screen Buffer, *MyScreen;
    struct  IntuiText *TempI, *Intu1, *Intu2, *Intu3;
    ULONG   ScreenSuccess, Success, error, IntuLock;
    USHORT  Width, MaxHeight, MaxWidth, text1width, text2width,
            text3width, textheight, i;

    /* Just for sure */
    error = 0;
    RememberKey = NULL;
    MaxCols = 1;

    IntuitionBase = (struct IntuitionBase *)OpenLibrary(INTUILIB,33L);
    if(IntuitionBase == NULL) {
        CleanUp(FALSE,"Sorry, Can't open intuition.library V33 or later!\n",20);
    }

    GfxBase = (struct GfxBase *)OpenLibrary(GFXLIB,33L);
    if(GfxBase == NULL) {
        CleanUp(FALSE,"Sorry, Can't open graphics.library V33 or later!\n",20);
    }

    ScreenSuccess = GetScreenData((char *)&Buffer,sizeof(struct Screen),
                                                       WBENCHSCREEN,NULL);
    if(ScreenSuccess == 0L) {
        CleanUp(FALSE,"Can't get Screen information!\n",20);
    }

    for(i=0; i < ((&(Buffer.BitMap))->Depth); i++) MaxCols *= 2;

    error = CheckParameters(argc, argv);
    if(error != 0) {
        CleanUp(TRUE,NULL,error);
    }

    if(text[0] == NULL) {
        CleanUp(FALSE,NULL,0);
    }
    else if(text[1] == NULL) {
        ReadRedirFile(argv);
        if(text[0] == NULL) {
            CleanUp(FALSE,NULL,0);
        }
        else if(text[1] == NULL) {
            CleanUp(FALSE,"Can't open redirection file!\n",10);
        }
        else if(text[2] == NULL) {
            text[2] = text[1];
            text[1] = NULL;
        }
    }
    else if(text[2] == NULL) {
        text[2] = text[1];
        text[1] = NULL;
    }

    MaxHeight = Buffer.Height;
    MaxWidth = Buffer.Width;

    if(!LARGE_ON) {
        if(MaxHeight > GfxBase->NormalDisplayRows) {
            MaxHeight = GfxBase->NormalDisplayRows;
        }
        if(MaxWidth > GfxBase->NormalDisplayColumns) {
            MaxWidth = GfxBase->NormalDisplayColumns;
        }
    }

    if(FWIDTH_ON) {
        if((ForceWidth > MINWINDOWWIDTH) && (ForceWidth <= MaxWidth)) {
            MaxWidth = ForceWidth;
        }
        else {
            Print("Illegal window size!\n");
            FWIDTH_ON = FALSE;
        }
    }
    if(FHEIGHT_ON) {
        if((ForceHeight > MINWINDOWHEIGHT) && (ForceHeight <= MaxHeight)) {
            MaxHeight = ForceHeight;
        }
        else {
            FHEIGHT_ON = FALSE;
            Print("Illegal window size!\n");
        }
    }

    MaxHeight -= 46;
    MaxWidth -= 38;

    Intu1 = MakeIntuText(text[0],(USHORT)(MaxHeight/9),(USHORT)(MaxWidth/8));
    Intu2 = MakeIntuText(text[1],1,(USHORT)((MaxWidth-48)/16));
    Intu3 = MakeIntuText(text[2],1,(USHORT)((MaxWidth-48)/16));
    if((Intu1 == IPOINT) || (Intu2 == IPOINT) || (Intu3 == IPOINT)) {
        CleanUp(FALSE,"Out of memory!\n",20);
    }

    if(FWIDTH_ON) {
        Width = ForceWidth;
    }
    else {
        text1width = TestWidth(Intu1);
        text2width = TestWidth(Intu2)+3;
        text3width = TestWidth(Intu3)+3;
        Width = text2width+text3width;
        if(text1width > Width) Width = text1width;
        Width = Width*8+38;
    }

    textheight = 0;
    TempI = Intu1;
    while(TempI != NULL) {
        textheight++;
        if(CENTER_ON) {
            TempI->LeftEdge += (Width - 38 - strlen(TempI->IText)*8)/2;
        }
        TempI = TempI->NextText;
    }
    if(FHEIGHT_ON) {
        textheight = ForceHeight;
    }
    else {
        textheight = textheight*9+46;
    }

    if(BEEP_ON) {
        IntuLock = LockIBase(0);
        MyScreen = IntuitionBase->ActiveScreen;
        UnlockIBase(IntuLock);
        DisplayBeep(MyScreen);   /* Flash the Active Screen, before activating
                                    AutoRequest */
    }

    Success = (USHORT)AutoRequest(NULL,Intu1,Intu2,Intu3,0,0,Width,textheight);
    if(Success == 0) error = 5;

    CleanUp(TRUE, NULL, error);
}

VOID CleanUp(BOOL SUCCESS, char *Text,ULONG Error)
{
    if(!SUCCESS) {
        PrintUsage();
        Print(Text);
    }

    FreeRemember(&RememberKey,TRUE);
    if(GfxBase) CloseLibrary((struct Library *)GfxBase);
    if(IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);

    XCEXIT(Error);
}

VOID PrintUsage()
{
    Print(UsageString);
    Print("USAGE: QuickReq\t<Question> [<True>] <False> [OPTIONS] or\n");
    Print("\t\t<Filename> [OPTIONS]\n");
    Print("OPTIONS:\n\t-C  = Text centering\n");
    Print("\t-B  = DisplayBeep\n");
    Print("\t-L  = Large view\n");
    Print("\t-W# = Width\n");
    Print("\t-H# = Height\n");
    Print("\t-P# = Pen color\n\n");
}


VOID ReadRedirFile(char *argv[])
{
    ULONG MyLock, FileSize, Success, error;
    char *line;
    struct FileInfoBlock *FIB;
    int argc;

    MyLock = Lock(text[0],ACCESS_READ);
    if(MyLock == NULL) {
        CleanUp(FALSE,"Can't open redirection file!\n",IoErr());
    }
    FIB = (struct FileInfoBlock *)AllocNormMem(sizeof(struct FileInfoBlock));
    if(FIB == NULL) {
        CleanUp(FALSE,"Out of memory!\n",10);
    }
    Success = Examine(MyLock,FIB);
    error = IoErr();
    UnLock(MyLock);
    if(Success == 0) {
        CleanUp(FALSE,"File error!\n",error);
    }
    else if(FIB->fib_DirEntryType > 0) {
        CleanUp(FALSE,"Object wrong type!\n",ERROR_OBJECT_WRONG_TYPE);
    }
    FileSize = FIB->fib_Size;
    if(FileSize != 0) {
        line = (char *)AllocNormMem(FileSize);
        if(line == NULL) {
            CleanUp(FALSE,"Out of memory!\n",10);
        }
        MyLock = Open(text[0],MODE_OLDFILE);
        if(MyLock == NULL) {
            CleanUp(FALSE,"File error!\n",IoErr());
        }
        Success = Read(MyLock,line,FileSize);
        if(Success == -1) {
            error = IoErr();
            Close(MyLock);
            CleanUp(FALSE,"File error!\n",error);
        }
        Close(MyLock);
    }
    else line = NULL;

    argc = ParseCommands(1, line, argv);
    if(argc > MAXARG) {
        CleanUp(FALSE,NULL,1);
    }
    error = CheckParameters(argc, argv);
    if(error != 0) {
        CleanUp(TRUE,NULL,error);
    }
}

USHORT TestWidth(struct IntuiText *MyIText)
{
    USHORT width, widest = 0;

    while(MyIText != NULL) {
        width = strlen(MyIText->IText);
        if(width > widest) widest = width;
        MyIText = MyIText->NextText;
    }
    return(widest);
}

VOID Print(char *String)
{
    ULONG output;

    output = Output();
    if(output != NULL) {
        Write(output,String,strlen(String));
    }
}

USHORT CheckParameters(int argc, char *argv[])
{
    char *NextStr =  NULL;
    int count, textcount;
    char Currentchar;

    count = 0;
    textcount = 0;

    while(count < argc-1) {
        NextStr = argv[count+1];
        if(*NextStr == '-') {
            NextStr++;
            while((*NextStr != '\0') && (!isspace((char)*NextStr))) {
                Currentchar = toupper(*NextStr);
                if(Currentchar == 'C') {
                    CENTER_ON = TRUE;
                }
                else if(Currentchar == 'B') {
                    BEEP_ON = TRUE;
                }
                else if(Currentchar == 'L') {
                    LARGE_ON = TRUE;
                }
                else if(Currentchar == 'W') {
                    NextStr++;
                    ForceWidth = ReadNumber(&NextStr);
                    FWIDTH_ON = TRUE;
                }
                else if(Currentchar == 'H') {
                    NextStr++;
                    ForceHeight = ReadNumber(&NextStr);
                    FHEIGHT_ON = TRUE;
                }
                else if(Currentchar == 'P') {
                    NextStr++;
                    PenNumber = ReadNumber(&NextStr);
                    OWNPEN_ON = TRUE;
                }
                else {
                    PrintUsage();
                    Print("Unknown option ");
                    Print(argv[count+1]);
                    Print(" !\n");
                    return(10);
                }
                NextStr++;
            }
        }
        else if((textcount == 0) && (*NextStr == '?')) {
            PrintUsage();
            return(1);
        }
        else if(textcount <= 2) {
            text[textcount] = NextStr;
            textcount++;
        }
        else {
            PrintUsage();
            Print("Too many arguments!\n");
            return(10);
        }
        count++;
    }
    return(0L);
}

int ReadNumber(char *line[])
{
    char *temp;
    USHORT Number = 0;

    temp = line[0];
    while((*temp != ' ') && (*temp != '\0') && (isdigit(*temp))) {
        Number = Number*10+(*temp - '0');
        temp++;
    }
    line[0] = temp-1;
    return(Number);
}

struct IntuiText *MakeIntuText(char *text, USHORT height, USHORT width)
{
    struct IntuiText *FirstText, *CurrentText, *OldText = 0;
    USHORT curheight = 0, curwidth, i;
    char *writechar, *readchar, *oldreadchar;

    if(text == NULL) return(NULL);

    FirstText = (struct IntuiText *)AllocNormMem(sizeof(struct IntuiText));
    if(FirstText == NULL) {
        return(IPOINT);
    }

    writechar = (char *)AllocNormMem(height*(width+1));
    if(writechar == NULL) {
        return(IPOINT);
    }

    CurrentText = FirstText;
    readchar = text;

    while((CurrentText != NULL) && (curheight < height)) {
        if(OldText != NULL) {
            OldText->NextText = CurrentText;
        }
        if(OWNPEN_ON) {
            CurrentText->FrontPen = PenNumber % MaxCols;
        }
        else {
            CurrentText->FrontPen = AUTOFRONTPEN;
        }
        if(CurrentText->FrontPen == AUTOBACKPEN) {
            CurrentText->BackPen = (PenNumber+1) % MaxCols;
        }
        else {
            CurrentText->BackPen = AUTOBACKPEN;
        }
        CurrentText->DrawMode = AUTODRAWMODE;
        CurrentText->LeftEdge = AUTOLEFTEDGE;
        CurrentText->TopEdge = AUTOTOPEDGE + (curheight * 9);
        CurrentText->ITextFont = &MyTopaz8;
        CurrentText->IText = (UBYTE *)writechar;

        oldreadchar = readchar;
        curwidth = 0;
        while((*readchar != '\\') && (curwidth < width)) {
            if((*readchar == 0x0a) || (*readchar == 0x09)) {
                *readchar = ' ';
            }
            *writechar++ = *readchar;
            if(*readchar++ == '\0') return(FirstText);
            curwidth++;
        }
        if(*readchar == '\\') {
            *writechar++ = '\0';
            readchar++;
        }
        else if(curwidth >= width) {
            i = 0;
            while((*readchar != ' ') && (readchar != oldreadchar)) {
                --readchar;
                i++;
            }
            if(*readchar == ' ') {
                writechar -= i;
                *writechar++ = '\0';
                readchar++;
            }
            else {
                readchar += i;
                *writechar++ = '\0';
            }
        }
        curheight++;
        OldText = CurrentText;
        CurrentText = (struct IntuiText *)AllocNormMem(sizeof(struct IntuiText));
        if(CurrentText == NULL) {
            return(IPOINT);
        }
    }
    return(FirstText);
}

char *AllocNormMem(int Size)
{
    char *MemPointer;

    MemPointer = (char *)AllocRemember(&RememberKey, Size,MEMF_PUBLIC|MEMF_CLEAR);

    return(MemPointer);
}

/* ------------------------------------------ */
/*   These are my modified startup routines   */
/* ------------------------------------------ */

VOID _main(line)
register char *line;
{
    int argc = 0;                    /* arg count */
    char *argv[MAXARG];              /* arg pointers */

    argc = ParseCommands(0, line, argv);
    if(argc > MAXARG) {
        PrintUsage();
        XCEXIT(1);
    }

    main(argc, argv);
    XCEXIT(0);
}

/* I have separated this to own routine, because I also use this to parse
   redirection file.
*/

int ParseCommands(int Start, register char *line, char *args[])
{
    register char **pargv;
    int argc;

    argc = Start;

    while (argc < MAXARG)
    {
        while (isspace(*line))  line++;
        if (*line == '\0')      break;
        pargv = &args[argc++];
        if (*line == QUOTE)
            {
            *pargv = ++line;  /* ptr inside quoted string */
            while ((*line != '\0') && (*line != QUOTE)) line++;
            if (*line == '\0') {
                return(MAXARG+1);
            }
            else                *line++ = '\0';  /* terminate arg */
        }
        else            /* non-quoted arg */
        {
            *pargv = line;
            while ((*line != '\0') && (!isspace(*line))) line++;
            if (*line == '\0')  break;
            else                *line++ = '\0';  /* terminate arg */
        }
    }  /* while */

    return(argc);
}
