/*
 *  New, improved Resize-Tool by Bernd Raschke
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <graphics/gfxbase.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <devices/conunit.h>

#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

/* Used for checking version */
#define VERSION     "1"
#define REVISION    "3"

struct Library *DosBase;
struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;

/* Globals initialized by findWindow() */
struct Window *conWindow;
struct Screen *conScreen;
struct RastPort *conRP;
struct ConUnit *conUnit;
struct TextFont *scTFont;
BYTE bl, bt, br, bb;
WORD cwid_p, chgt_p, cwid_c, chgt_c, ciwid_p, cihgt_p;
WORD nwid_c, nhgt_c, nwid_p, nhgt_p, fwid_p, fhgt_p;
WORD scWidth, scHeight, ctop_p, clft_p, ntop_p, nlft_p;

UBYTE Version[] = "$VER: resize " VERSION "." REVISION " ("__DATE__")";

void cleanexit(char *);
void cleanup(void);
void parseArgs(char *);
LONG findWindow(void);
void examWindow(void);
LONG sendpkt(struct MsgPort *,LONG , LONG *,LONG );
void examfont(void);
void main(int, char **);

void cleanexit(char *s)
{
    if(*s)
	printf(s);    /* Print error */
    cleanup();
    exit(0);
}

void cleanup(void)
{
    if(DosBase)
	CloseLibrary(DosBase);
    if(GfxBase)
	CloseLibrary((struct Library *) GfxBase);
    if(IntuitionBase)
	CloseLibrary((struct Library *) IntuitionBase);
}

/*
    Analyse the string we got from GEOM. I tried to make it similar to the
    '-geometry' option of the X Window System... (well, sort of :-)
    The code is a bit weird, but it works ok.

    "XSize"x"YSize"V"XOffset"V"YOffset", where size is measured in characters
    and offset in pixels. V stands for '+' (left/top) and '-' (right/bottom)
*/

void parseArgs(char *v)
{
    int i=0, j=0;
    char dx[10], dy[10], x[10], y[10], sx, sy;
    WORD xi, yi;

/*  Scan for the width. We'll only take numbers */
    while((isdigit(v[i]) != 0) && (v[i] != '\0'))
	dx[j++] = v[i++];
    dx[j]= 0;

/*  Is there a x? Do we have a height? Can birds fly? */
    j=0;
    if(v[i] == 'x')
    {
	i++;
	while((isdigit(v[i]) != 0) && (v[i] != '\0'))
	    dy[j++] = v[i++];
	dy[j]= 0;
    }

/*  Now the x-offset. sx will be the sign */
    j=0;
    sx= v[i++];
    while((isdigit(v[i]) != 0) && (v[i] != '\0'))
	x[j++] = v[i++];
    x[j]= 0;

/*  Now the y-offset. sy will be the sign */
    j=0;
    sy= v[i++];
    while((isdigit(v[i]) != 0) && (v[i] != '\0'))
	y[j++] = v[i++];

/*  Calculate the new (width|height) in characters and offsets */
    if((nwid_c= (WORD) atoi(dx)) == 0)
	nwid_c= cwid_c;
    if((nhgt_c= (WORD) atoi(dy)) == 0)
	nhgt_c= chgt_c;
    xi= (WORD) atoi(x);
    yi= (WORD) atoi(y);

/*  new width in pixels is new width in chars * font width in pixels +
    +borderleft + borderright (equivalent for height) */
    nwid_p= nwid_c * fwid_p +bl +br;
    nhgt_p= nhgt_c * fhgt_p +bt +bb;

/*  Now handle the difference between '+' and '-' */
    if(sx == '+')
	nlft_p= xi;
    else if(sx == '-')
	nlft_p= scWidth -nwid_p -xi;
    else
	nlft_p= clft_p;

    if(sy == '+')
	ntop_p= yi;
    else if(sy == '-')
	ntop_p= scHeight -nhgt_p -yi;
    else
	ntop_p= ctop_p;

    return;
}

/*  This is the last remaining code from the example:
	ConPackets.c -	C. Scheppner, A. Finkel, P. Lindsay  CBM
*/
LONG findWindow(void) /* inits conWindow and conUnit (global vars) */
{
    struct InfoData *id;
    struct MsgPort  *conid;
    struct Process  *me;
    LONG myarg, res1;

   /* Alloc to insure longword alignment */
    id = (struct InfoData *)AllocMem(sizeof(struct InfoData),
				       MEMF_PUBLIC|MEMF_CLEAR);
    if(! id) return(0);
    me = (struct Process *) FindTask(NULL);
    conid = (struct MsgPort *) me->pr_ConsoleTask;

    myarg= ((ULONG)id) >> 2;
    res1 = (LONG)DoPkt(conid,ACTION_DISK_INFO, myarg, 0L, 0L, 0L, 0L);
    conWindow = (struct Window *)id->id_VolumeNode;
    conScreen= conWindow->WScreen;
    conUnit = (struct ConUnit *) ((struct IOStdReq *)id->id_InUse)->io_Unit;
    FreeMem(id,sizeof(struct InfoData));
    return(res1);
}
/* This is the End */

void examWindow(void)
{
    bl= conWindow->BorderLeft;
    bt= conWindow->BorderTop;
    br= conWindow->BorderRight;
    bb= conWindow->BorderBottom;
    conRP= conWindow->RPort;
    cwid_p= conWindow->Width;
    chgt_p= conWindow->Height;
    ciwid_p= cwid_p -bl -br;
    cihgt_p= chgt_p -bt -bb;
    scWidth= conScreen->Width;
    scHeight= conScreen->Height;
    clft_p= conWindow->LeftEdge;
    ctop_p= conWindow->TopEdge;

    return;
}
void examFont(void)
{
    scTFont= conRP->Font;
    fwid_p= scTFont->tf_XSize;
    fhgt_p= scTFont->tf_YSize;

    cwid_c= ciwid_p / fwid_p;
    chgt_c= cihgt_p / fhgt_p;
    return;
}

void main(int argc, char **argv)
{
    LONG  infile;

    if(!(DosBase=(OpenLibrary((UBYTE *) "dos.library",37L))))
	cleanexit("\nCouldn't open dos.library. This program needs at least Kickstart2.04\n");

    if(!(GfxBase=(struct GfxBase *)OpenLibrary((UBYTE *) "graphics.library", 37L)))
	cleanexit("\nCouldn't open graphics.library. This program needs at least Kickstart2.04\n");

    if(!(IntuitionBase=(struct IntuitionBase *)OpenLibrary((UBYTE *) "intuition.library", 37L)))
	cleanexit("\nCouldn't open intuition.library. This program needs at least Kickstart2.04\n");

    if((infile = Input()) <= 0)
	cleanexit("\nNo stdin ... Did you RUN this ???\n");

    if (! findWindow()) cleanexit("\nNot enough free memory\n");

    examWindow();
    examFont();

    if(argc == 1)
    {
	printf("console dimensions: %dx%d+%d+%d(%dx%d)\n", cwid_c, chgt_c,
	    conWindow->LeftEdge, conWindow->TopEdge,
	    conWindow->Width, conWindow->Height);
    } else if((argc != 2) || (strcmp(argv[1], "+help") == 0) ||
	(strcmp(argv[1], "-?") == 0) ||
	(strcmp(argv[1], "?") == 0))
    {
	puts("resize " VERSION "." REVISION " by Bernd Raschke,(" __DATE__ ")");
	puts("Usage: resize [WIIDTH][xHEIGHT]][(+|-)XOFFSET[(+|-)YOFFSET]]");
	puts("\tWIDTH and HEIGHT are measured in characters, XOFFSET and YOFFSET in");
	puts("\tpixels from the border of the screen. '+' means left or down and");
	puts("\t'-' means right and up. (Similar to the X Window System conventions.)\n");
	puts("Valid examples:");
	puts("  resize\n\treports current size and position");
	puts("  resize 80x24+0+0\n\tsets size to 80 columns and 24 rows, in the upper left");
	puts("  resize x-100-0\n\tkeeps the same size and moves window 100 pixel from right");
	puts("\tat the bottom of the screen.");
    } else
    {
	parseArgs(argv[1]);

	ChangeWindowBox(conWindow, nlft_p, ntop_p,
	    nwid_p, nhgt_p);
    }
    cleanup();
    exit(0);
}

