#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 "launchclass.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,
    0xFFF2,
    0
};

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

    0,
    0,
    0xFFF1,
    0
};

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

    0,
    0,
    0xFFF3,
    0
};

void 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;
}

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

    if(my_text_attr=(struct TextAttr *)pAllocVec(sizeof(struct TextAttr)))
    {
	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);
	pFreeVec((ULONG *)my_text_attr);
    }
    if(!tf) if(!(tf=(struct TextFont *)OpenTopaz())) 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_IDCMP,           NULL,
	WA_MinWidth,        data->min_x_size,
	WA_Flags,           (set->win_backfront!=win_back ? 0 : WFLG_BACKDROP )|WFLG_BORDERLESS|WFLG_RMBTRAP|WFLG_REPORTMOUSE,
	WA_PubScreen,       data->scr,
	TAG_DONE)))
    {
	if(data->appport=(struct MsgPort *)CreateMsgPort()) data->appwin=(struct AppWindow *)AddAppWindow(0L, 0L, window, data->appport , 0L);
	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)
	{
	    my_drag.NextGadget=NULL;
	    my_size.NextGadget=NULL;
	    my_close.NextGadget=NULL;
	    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|IDCMP_GADGETDOWN|IDCMP_GADGETUP);
	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); data->bg_bm=0;
    if(data->bg_bm=(struct BitMap *)AllocBitMap(xs,ys,data->scr->RastPort.BitMap->Depth,0,0))
    {
	win->FirstGadget=NULL;
	if(data->appwin)  RemoveAppWindow(data->appwin);
	if(data->appport) DeleteMsgPort  (data->appport);
	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);
    }
}

Object *LoadImage(char *file, struct Screen *scr)
{
    Object              *dt_obj;

    if (dt_obj = (Object *)NewDTObject(file,
	DTA_SourceType       ,DTST_FILE,
	DTA_GroupID          ,GID_PICTURE,
	PDTA_Remap           ,TRUE,
	PDTA_Screen          ,scr,
	PDTA_FreeSourceBitMap,TRUE,
	OBP_Precision        ,PRECISION_IMAGE,
	TAG_DONE))
    {
	if ( DoDTMethod(dt_obj,NULL,NULL,DTM_PROCLAYOUT,NULL,1))
	{
	    return(dt_obj);
	}
    }
    return(NULL);
}

void 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 = LoadImage(&set->bg_picture[0],data->scr))
    {
	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);
	}
    }
}

UWORD calcXPos(UWORD i, struct tm_data *data, struct tm_sys_set *set)
{
    return((UWORD)(set->win_border_x+((i)%set->colums)*data->gauge_x_size+((i)%set->colums)*set->win_space_x));
}

UWORD calcYPos(UWORD i, struct tm_data *data, struct tm_sys_set *set)
{
    UWORD tmp,j;
    UWORD y_pos;

    tmp=i/set->colums;
    if(set->lay_falling)
    {
	y_pos=set->win_border_y+(tmp*set->win_space_y);
	for(j=(i-(tmp*set->colums));j<i;j+=set->colums) y_pos+=data->gauge_y_size_falling[j];
    }
    else
    {
	y_pos= set->win_border_y+(tmp*set->win_space_y)+((data->gauge_y_size[tmp]-data->gauge_y_size_falling[i])>>1);
	for(j=0;j<tmp;j++) y_pos+=data->gauge_y_size[j];
    }
    data->gauge_y_pos[i]=y_pos;
    return(y_pos);
}

struct Window *openWindow(struct tm_sys_set *set,struct tm_data *data, Class *gclass, Class *lclass)
{
    UWORD               y_siz,
			line,
			i,opt1,opt2,
			tmp;
    struct tm_gau_set   *many;
    struct RastPort     *tmpras;
    BOOL                change;
    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;
    }
    data->labelpos=0;
    if(tmpras=(struct RastPort *)pAllocVec(sizeof(struct RastPort)))
    {
	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_falling[i]=(data->Font[i]->tf_YSize*(many->size_y+100))/100;
		    data->gauge_y_size[line]=MAX(data->gauge_y_size[line],data->gauge_y_size_falling[i]);
		}
		if((many->gauge_type!=typ_histmeter)&&(many->type!=typ_clock_)&&(many->type!=typ_simplelauncher))
		{
		    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;
	pFreeVec((ULONG *)tmpras);
	opt1=(set->win_space_x*(set->colums-1));
	opt2=(set->win_border_x<<1);
	data->num_of_rows   =((data->num_of_gaug-1)/set->colums)+1;
	data->min_x_size    =((data->labelpos+8)*set->colums)+opt1+opt2;
	if(data->min_x_size>set->x_siz)set->x_siz=data->min_x_size;
	data->gauge_x_size  =((set->x_siz-opt2)-opt1)/set->colums;
	allocGadgets(set,data,gclass,lclass);
	change=FALSE;
	for(i=0,many=data->list;i<data->num_of_gaug;i++)
	{
	    if(data->gdg[i])
	    {
		ULONG   height;
		line=(i/(set->colums));
		switch (many->type)
		{
		    case    typ_simplelauncher:
			    GetAttr(LAU_ImgHeight,data->gdg[i],&height);
			    data->gauge_y_size[line]        = MAX(data->gauge_y_size[line],     height + 6);
			    data->gauge_y_size_falling[i]   = MAX(data->gauge_y_size_falling[i],height + 6);
			    SetAttrs(data->gdg[i],GA_Height,data->gauge_y_size_falling[i],TAG_DONE);
			    change=TRUE;
			    break;
		    case    typ_iconlauncher:
			    {
				struct  lau_entry       *foobar;
				struct  BitMapHeader    *bmhd;
				ULONG                   height=0;
				GetAttr(LAU_List,data->gdg[i],(ULONG *)&foobar);
				if(foobar)
				{
				    do
				    {
					if(foobar->img)
					{
					    GetDTAttrs(foobar->img,PDTA_BitMapHeader,&bmhd,TAG_DONE);
					    if(bmhd)
					    {
						height=MAX(height,bmhd->bmh_Height);
					    }
					}
				    }
				    while(foobar=foobar->next);
				    data->gauge_y_size[line]        = MAX(data->gauge_y_size[line],     height);
				    data->gauge_y_size_falling[i]   = MAX(data->gauge_y_size_falling[i],height);
				    SetAttrs(data->gdg[i],GA_Height,height,TAG_DONE);
				    change=TRUE;
				}
			    }
			    break;
		}
	    }
	    many=many->next;
	}
	if(change)
	    for(i=0;i<data->num_of_gaug;i++)
		if(data->gdg[i]) SetAttrs(data->gdg[i],GA_Top,calcYPos(i,data,set),TAG_DONE);

	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))
	{
	    ULONG   list;
	    data->bg_color    =obtainPen(data->scr,&set->bg_color);
	    data->bright_color=obtainPen(data->scr,&set->bright_color);
	    data->dark_color  =obtainPen(data->scr,&set->dark_color);
	    switch (set->bg_type)
	    {
		case    bg_file:
			fileBackground(set,data);
			break;
		case    bg_snap:
			data->win=snapBackground(set,data);
			break;
	    }
	    drawBackground(set,data);
	    for(i=0;i<data->num_of_gaug;i++) if(data->gdg[i])
	    {
		GetAttr(LAU_List,data->gdg[i],&list);
		if(list) AddGList(data->win,data->gdg[i],0,1,NULL);
		else     AddGList(data->win,data->gdg[i],-1,1,NULL);
	    }
	    RefreshGList(data->gdg[i],data->win,NULL,-1);
	    return(data->win);
	}
    }
    return(0L);
}

void closeWindow(struct tm_sys_set *set,struct tm_data *data)
{
    int i;
    if(!set->bg_color.pen)     ReleasePen     (data->scr->ViewPort.ColorMap,data->bg_color);
    if(!set->bright_color.pen) ReleasePen     (data->scr->ViewPort.ColorMap,data->bright_color);
    if(!set->dark_color.pen)   ReleasePen     (data->scr->ViewPort.ColorMap,data->dark_color);
    if(data->appwin)           RemoveAppWindow(data->appwin);
    if(data->appport)          DeleteMsgPort  (data->appport);
    if(data->win)
    {
	data->win->FirstGadget=NULL;
	CloseWindow(data->win);
	data->win=0L;
    }
    removeGadgets(set,data);

    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],NULL);
	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;
    }
}
