#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <intuition/intuitionbase.h>
#include <intuition/classusr.h>
#include <intuition/imageclass.h>
#include <intuition/gadgetclass.h>
#include <intuition/cghooks.h>
#include <intuition/icclass.h>
#include <intuition/classes.h>
#include <intuition/sghooks.h>
#include <intuition/screens.h>
#include <datatypes/datatypesclass.h>
#include <datatypes/datatypes.h>
#include <datatypes/pictureclass.h>
#include <graphics/gfxbase.h>
#include <graphics/text.h>
#include <graphics/gfxmacros.h>
#include <utility/tagitem.h>
#include <utility/hooks.h>
#include <string.h>
#include <clib/macros.h>
#include "gaugeclass.h"
#include "tinymeter.h"

extern struct IntuitionBase *IntuitionBase;

struct Gadget my_drag=
{
    NULL,
    0,1,
    0,0,
    GFLG_GADGHNONE,
    GACT_IMMEDIATE,
    GTYP_SYSGADGET|GTYP_WDRAGGING,
    0,
    0,
    0,

    0,
    0,
    2,
    0
};

struct Gadget my_close=
{
    NULL,
    0,0,
    16,16,
    NULL,
    GACT_IMMEDIATE,
    GTYP_SYSGADGET|GTYP_CLOSE,
    0,
    0,
    0,

    0,
    0,
    1,
    0
};

struct Gadget my_size=
{
    NULL,
    0,0,
    16,16,
    GFLG_GADGHNONE,
    GACT_IMMEDIATE,
    GTYP_SYSGADGET|GTYP_SIZING,
    0,
    0,
    0,

    0,
    0,
    3,
    0
};

new_window_size(struct tm_sys_set *set,struct tm_data *data)
{
    struct Window   *win=data->win;
    my_drag.Width   =win->Width;
    my_drag.Height  =win->Height-17;
    my_size.TopEdge =win->Height-16;
    my_size.LeftEdge=win->Width -16;
}

extern struct  TextAttr topaz_font;

struct TextFont *loadFont(char *name, UWORD size)
{
    struct  TextFont     *tf;
    struct  TextAttr      my_text_attr;

    my_text_attr.ta_Name =(UBYTE *)name;
    my_text_attr.ta_YSize=(UWORD)size;
    my_text_attr.ta_Flags=FPF_DISKFONT | FPB_PROPORTIONAL;

    tf=(struct TextFont *)OpenDiskFont((struct TextAttr *)&my_text_attr);
    if(!tf)
    {
	tf=(struct TextFont *)OpenFont(&topaz_font);
	if(!tf) return(0L);
    }
    return(tf);
}

struct Window *open_new_window(struct tm_sys_set *set,struct tm_data *data, UWORD ysiz)
{
    struct Window *window;

    if((window=(struct Window *)OpenWindowTags(0,
		   WA_Left,            set->x_pos,
		   WA_Top,             set->y_pos,
		   WA_Width,           set->x_siz,
		   WA_MaxWidth,        4096,
		   WA_MaxHeight,       ysiz,
		   WA_MinHeight,       ysiz,
		   WA_Height,          ysiz,
		   WA_MinWidth,        data->min_x_size,
		   WA_Flags,           (set->win_backfront!=win_back ? 0 : WFLG_BACKDROP )|WFLG_BORDERLESS|WFLG_RMBTRAP,
		   WA_PubScreen,       data->scr,
		   TAG_DONE)))
    {
	my_drag.Width=   window->Width;
	my_drag.Height=  window->Height-17;
	my_size.TopEdge= window->Height-16;
	my_size.LeftEdge=window->Width -16;
	if(set->win_move==win_normal)
	{
	    AddGadget(window,&my_drag, (UWORD)0);
	    AddGadget(window,&my_size, (UWORD)0);
	    AddGadget(window,&my_close,(UWORD)0);
	}
	ModifyIDCMP(window,IDCMP_NEWSIZE|IDCMP_CLOSEWINDOW|IDCMP_CHANGEWINDOW|IDCMP_SIZEVERIFY|IDCMP_VANILLAKEY|IDCMP_MOUSEBUTTONS);
	return(window);
    }
    return(0L);
}

struct Window *snapBackground(struct tm_sys_set *set,struct tm_data *data)
{
    struct Window *win=data->win;
    UWORD x,y,xs,ys;

    x=win->LeftEdge;
    y=win->TopEdge;
    xs=win->Width;
    ys=win->Height;
    set->x_pos=x;
    set->y_pos=y;
    set->x_siz=xs;

    if(data->bg_bm) FreeBitMap(data->bg_bm);
    if(data->bg_bm=(struct BitMap *)AllocBitMap(xs,ys,data->scr->RastPort.BitMap->Depth,0,0))
    {
	RemoveGList(win,win->FirstGadget,-1);
	CloseWindow(win);
	BltBitMap(data->scr->RastPort.BitMap,x,y,data->bg_bm,0,0,xs,ys,0xc0,0xff,0);
	return((struct Window *)open_new_window(set,data,ys));
    }
    return(0L);
}

void CopyTiledBitMap(struct BitMap *Src,WORD SrcSizeX,WORD SrcSizeY,WORD DstSizeX,WORD DstSizeY ,struct BitMap *Dst)
{
    WORD PosX,
	 PosY;
    WORD SizeX,
	 SizeY;
    for (PosX = 0,SizeX = MIN(SrcSizeX,DstSizeX);PosX<DstSizeX;)
    {
	for (PosY = 0,SizeY = MIN(SrcSizeY,DstSizeY);PosY<DstSizeY;)
	{
		BltBitMap(Src,0,0,Dst,PosX,PosY,SizeX,SizeY,0xC0,0xff,0L);
		PosY += MIN(SizeY,DstSizeY-PosY);
		SizeY = MIN(SizeY,DstSizeY-PosY);
	}
	PosX += MIN(SizeX,DstSizeX-PosX);
	SizeX = MIN(SizeX,DstSizeX-PosX);
    }
}

fileBackground(struct tm_sys_set *set,struct tm_data *data)
{
    struct Window       *win=data->win;
    struct BitMap       *work;
    struct BitMapHeader *header;
    UWORD xs,ys;

    if (data->bg_bm){ FreeBitMap(data->bg_bm); data->bg_bm=0L; }
    if (data->dt_object = (Object *)NewDTObject(&set->bg_picture[0],
					    DTA_SourceType       ,DTST_FILE,
					    DTA_GroupID          ,GID_PICTURE,
					    PDTA_Remap           ,TRUE,
					    PDTA_Screen          ,data->scr,
					    PDTA_FreeSourceBitMap,TRUE,
					    OBP_Precision        ,PRECISION_IMAGE,
					    TAG_DONE))
    {
	if ( DoDTMethod(data->dt_object,NULL,NULL,DTM_PROCLAYOUT,NULL,1))
	{
	    GetDTAttrs(data->dt_object,PDTA_BitMapHeader,&header,PDTA_DestBitMap,&work,TAG_DONE);
	    if (work==FALSE) GetDTAttrs(data->dt_object,PDTA_BitMap,&work,TAG_DONE);

	    xs=win->Width;
	    ys=win->Height;
	    if(data->bg_bm=(struct BitMap *)AllocBitMap(xs,ys,work->Depth,0,0))
	    {
		CopyTiledBitMap(work,header->bmh_Width,header->bmh_Height,xs,ys,data->bg_bm);
	    }
	}
    }
}

ULONG obtainPen( struct tm_data *data, struct GAU_Color *scr)
{
    return(scr->pen ? scr->red : ObtainBestPenA(data->scr->ViewPort.ColorMap, scr->red, scr->green, scr->blue, 0L) );
}

struct Window *openWindow(struct tm_sys_set *set,struct tm_data *data)
{
    UWORD               y_siz,
			line,
			i,
			tmp;
    struct tm_gau_set   *many;
    struct RastPort     *tmpras;

    if( data->scr=(struct Screen *)LockPubScreen((char *)&set->pub_name[0]))
    {
	data->on_public=TRUE;
    }
    else
    {
	data->scr=(struct Screen *)IntuitionBase->FirstScreen;
	data->on_public=FALSE;
    }

    /* Calc Height of lines, labelpos (starting point of gauges) and open fonts for that... */

    data->labelpos=0;
    if(tmpras=(struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_CLEAR))
    {
	InitRastPort(tmpras);
	for(i=0;i<data->num_of_gaug;i++)
	{
	    data->gauge_y_size[i]=0;
	    data->gauge_y_size_falling[i]=0;
	}
	for(i=0,many=data->list;i<data->num_of_gaug;i++)
	{
	    if(many->type!=typ_none)
	    {
		line=(i/(set->colums));
		if(data->Font[i]=loadFont(many->font,many->font_size))
		    data->gauge_y_size[line]=MAX(data->gauge_y_size[line],data->gauge_y_size_falling[i]=(data->Font[i]->tf_YSize*(many->size_y+100))/100);
		if((many->gauge_type!=typ_histmeter)&&(many->type!=typ_clock_))
		{
		    SetFont(tmpras,data->Font[i]);
		    tmp=TextLength(tmpras,many->label,my_strlen(many->label));
		    if(tmp>data->labelpos)data->labelpos=tmp;
		}
	    }
	    else data->Font[i]=0;
	    many=many->next;
	}
	data->labelpos+=4; FreeVec(tmpras);

	/* Setup used lines and gauge_x_size */
	data->num_of_rows   =((data->num_of_gaug-1)/set->colums)+1;
	data->min_x_size    =((data->labelpos+8)*set->colums)+(set->win_space_x*(set->colums-1))+(set->win_border_x<<1);
	if(data->min_x_size>set->x_siz)set->x_siz=data->min_x_size;
	data->gauge_x_size  =(set->x_siz-(set->win_border_x<<1)-((set->colums-1)*set->win_space_x))/set->colums;

	/* Setup Window Height */
	if(set->lay_falling)
	{
	    UWORD old_siz,j;
	    for(i=0,y_siz=0;i<set->colums;i++)
	    {
		old_siz=y_siz;
		for(j=i,y_siz=0;j<data->num_of_gaug;j+=set->colums) y_siz+=data->gauge_y_size_falling[j];
		if(y_siz>old_siz) old_siz=y_siz;
	    }
	    y_siz=old_siz;
	}
	else for(i=0,y_siz=0;i<data->num_of_rows;i++)y_siz+=data->gauge_y_size[i];
	y_siz+=(set->win_border_y<<1)+(set->win_space_y*(data->num_of_rows-1));


	if(data->win=(struct Window *)open_new_window(set,data,y_siz))
	{
	    data->bg_color      =obtainPen(data,&set->bg_color);
	    data->bright_color  =obtainPen(data,&set->bright_color);
	    data->dark_color    =obtainPen(data,&set->dark_color);
	    switch (set->bg_type)
	    {
		case    bg_file:
			fileBackground(set,data);
			return(data->win);
			break;
		case    bg_snap:
			return(data->win=snapBackground(set,data));
			break;
		default:
			return(data->win);
			break;
	    }
	}
    }
    return(0L);
}

closeWindow(struct tm_sys_set *set,struct tm_data *data)
{
    int i;

    if(data->win)
    {
	RemoveGList(data->win,data->win->FirstGadget,-1);
	CloseWindow(data->win);
	data->win=0L;
    }

    for(i=0;i<data->num_of_gaug;i++)
	if(data->Font[i])
	{
	    CloseFont(data->Font[i]);
	    data->Font[i]=0L;
	}

    if(data->on_public)
    {
	UnlockPubScreen((char *)&set->pub_name[0]);
	data->on_public=FALSE;
    }

    if(data->dt_object)
    {
	DisposeDTObject((Object *)data->dt_object);
	data->dt_object=0L;
    }

    if(data->bg_bm)
    {
	FreeBitMap(data->bg_bm);
	data->bg_bm=0L;
    }
}
