/* analysisPanel.c 
*
*  defines the GUIFront characteristics of the analysis panel
*/

#include <math.h>  
#include <libraries/guifront.h>
#include <intuition/gadgetclass.h>
#include <exec/memory.h>
#include <clib/graphics_protos.h>
#include <clib/exec_protos.h>
#include <clib/diskfont_protos.h>
#include <intuition/screens.h>
#include <clib/intuition_protos.h>
#include <graphics/gfxmacros.h>
#include <graphics/gfxbase.h>

#include "amiCheck.h"
#include "database.h"
#include "regGadget.h"
#include "analysisPanel.h"

extern struct GfxBase *GfxBase;

#define ANAREA_SIZE	200

#define CTRLLEFT	0
#define CTRLRIGHT	1
#define SHIFTLEFT	2
#define SHIFTRIGHT	3
#define LEFT		4
#define RIGHT		5

extern struct TextFont *regFont;
GUIFront *analGUI;
struct Window *anWin;

static char anBalance[80];
static ULONG anFinalSel;
static int graphtype=0;
static long barScale;
static int andepth;
static ULONG anSelBar = -1;
static ULONG anTopBar;
float  anBarScale;
static ULONG anNumBars;
static long anTopScale;
static int anBarHeight, anBarWidth, anBarMax;
static struct RastPort anWorkRP, *anRP = NULL;
static chip struct BitMap anbuffer;
static chip struct AreaInfo anarea;
static chip struct TmpRas antmp;
static chip void *antmprp = NULL;
static chip UWORD anAreaBuffer[ANAREA_SIZE];
LONG anHeight, anWidth, anTop, anWidth, anLeft;

BOOL AnHandleGadget(struct IntuiMessage *);
BOOL AnHandleGadgetDown (struct IntuiMessage *);
void AnHandleMouseMove (struct IntuiMessage *);
BOOL AnalysisCreate(void);
void AnGraphInit(void);
void AnRenderBars(int);
void AnRefresh(void);
BOOL AnHitTest(ULONG,ULONG,ULONG,ULONG);
void AnSelect(int,BOOL);
void AnBalance(void);
BOOL AnProcessRawkeys(struct IntuiMessage *);
void AnKeyScroll(char);
void AnKeyScale(char);
void AnScrollBars(long,long,long,long);
balanceType AnFilterBal(void);

/* define imagery tags */

struct TagItem getGraphScrollTypes[] =
{
        {PGA_Freedom, LORIENT_HORIZ},          
	{GA_Immediate, TRUE},
        {TAG_DONE},
};


STRPTR graphlabels[] =
{
	"Running Balance",
	"Filter's Balance",
	"Amounts",
	NULL,
};

struct TagItem graphCycleTags[] =
{
	{GTCY_Labels, graphlabels},
	{TAG_DONE},
};


/* define gadgetspec */
GadgetSpec an_gadgetspecs[] = 
{
                
        {TEXT_KIND, 50,12,{0,0,0,0, NULL,NULL,GID_ANFIELD,
                PLACETEXT_IN}, TxtBorder, GS_DefaultTags},

	{TEXT_KIND,10 ,1, {0,0,0,0,NULL,NULL,GID_ANBAL,
		PLACETEXT_IN}, TxtBorder, GS_DefaultTags},

        {SCROLLER_KIND,10,1,{0,0,0,0, "Scroll X:",NULL,GID_ANSCROL,
                PLACETEXT_LEFT}, getGraphScrollTypes, GS_DefaultTags},

        {SCROLLER_KIND,10,1,{0,0,0,0, "Scale Y:",NULL,GID_ANSCALE,
                PLACETEXT_LEFT}, getGraphScrollTypes, GS_DefaultTags},

        {CYCLE_KIND,10,1,{0,0,0,0,"_Graph Type:",NULL, GID_ANTYPE,
               PLACETEXT_LEFT}, graphCycleTags, GS_DefaultTags},    

	{BUTTON_KIND,6,0,{0,0,0,0,"_OK",NULL,GID_ANOK,
		PLACETEXT_IN}, NULL, GS_DefaultTags},
};


/* set up array of pointers to our specs */
GadgetSpec *AN_MainSpecs[] =
{
        &an_gadgetspecs[0],
        &an_gadgetspecs[1],
        &an_gadgetspecs[2],
	&an_gadgetspecs[3],
	&an_gadgetspecs[4],
	&an_gadgetspecs[5],
        NULL,
};


/* define the layout of this panel */
ULONG AN_MainPanel[] =
{
   GUIL_Flags, GUILF_PropShare | GUILF_EqualWidth,
   
    GUIL_HorizGroup, 1,
/*	GUIL_FrameType, GUILFT_Recess,*/

        GUIL_VertGroup,1,
        
		GUIL_HorizGroup, 1,
			GUIL_Flags, GUILF_PropShare,
                	GUIL_GadgetSpecID, GID_ANTYPE,
			GUIL_GadgetSpecID, GID_ANBAL,
		TAG_DONE,

		GUIL_VertGroup, 1,
			GUIL_Flags, GUILF_PropShare | GUILF_EqualWidth,
			GUIL_GadgetSpecID, GID_ANFIELD,

			GUIL_VertGroup,1,
				GUIL_Flags, GUILF_EqualWidth|GUILF_LabelAlign,
				GUIL_GadgetSpecID, GID_ANSCROL,
				GUIL_GadgetSpecID, GID_ANSCALE,
			TAG_DONE,

		TAG_DONE,
              
        TAG_DONE,
 
   TAG_DONE,
    
#if 0
    GUIL_HorizGroup,1,
        GUIL_Flags, GUILF_EqualSize | GUILF_EqualWidth,
        
           GUIL_GadgetSpecID, GID_ANOK,
           
    TAG_DONE,   
#endif
  
  TAG_DONE,
};



/***********************************************************************/
BOOL AnalysisGUI(void)
{
 BOOL done = FALSE;
 BOOL reply = TRUE;
 filterNode *filt;
 ULONG signal;
 
 AmiLock();

 GF_SetGUIAttr(analGUI, GUI_OpenGUI, TRUE, TAG_DONE);
 GF_GetGUIAttr(analGUI, GUI_Window, &anWin, TAG_DONE);

 /* initialize stuff real quick */
 AnGraphInit();

 /* Process input events */
 while (!done)
                {
                    struct IntuiMessage *imsg;

                    /* Wait for an event to occur */

                    signal = GF_Wait(guiapp,AmigaGuideSignal(agc));
		    if (signal & AmigaGuideSignal(agc)) {
			AmiHelpMsg();
			continue;
		    }

                    /* We only bother to listen for CLOSEWINDOW events.
                     * Of course, in a real application, you would be
                     * examining the Class field for IDCMP_GADGETUP
                     * messages and act accordingly.
                     */

                    while (imsg = GF_GetIMsg(guiapp))
                    {
			reply = TRUE;
                        switch (imsg->Class) {
                                case IDCMP_CLOSEWINDOW:
					done = TRUE;
                                        break;

				case IDCMP_RAWKEY:
					done = AnProcessRawkeys(imsg);
					break;

				case IDCMP_MOUSEMOVE:
					AnHandleMouseMove(imsg);
					break;

				case IDCMP_GADGETUP:
					reply = FALSE;
					done=AnHandleGadget(imsg);
					break;

				case IDCMP_GADGETDOWN:
					done = AnHandleGadgetDown(imsg);
					break;

				case IDCMP_REFRESHWINDOW:
					AnRefresh();
					RegRefresh(TRUE);
					break;

				default:
					AnRefresh();
					break;
                        }
                                     
                              
	 		if (reply)
				GF_ReplyIMsg(imsg);
                    }
                }


 GF_SetGUIAttr(analGUI, GUI_OpenGUI, FALSE, TAG_DONE);               
 AmiUnlock();

 if (anFinalSel != -1) {
	selRow = anFinalSel;
	filt = (filterNode *)DataOrd2Node((struct List *)&filtered,anFinalSel);	
	RegMoveToSel(&filtered);
	return (TRUE);
 }
 return (FALSE);
}

/*******************************************************/
BOOL AnProcessRawkeys(struct IntuiMessage *imsg)
{
BOOL done = FALSE;
static BOOL upevent = FALSE;
static long upval;
static BOOL shift = FALSE, ctrl = FALSE;


if (upevent && imsg->Code != upval)
	return done;


upevent = FALSE;

/* for now, use raw keys */
switch (imsg->Code) {

	case 0x44:
		if (anSelBar != -1) {
			anFinalSel = anSelBar;
			done = TRUE;
		}
		break;

	case 0xe1:
	case 0xe0:
		shift = FALSE;
		break;

	case 0x61:
	case 0x60:
		shift = TRUE;
		break;

	case 0xe3:
		ctrl = FALSE;
		break;
	
	case 0x63:
		ctrl = TRUE;
		break;

	case 0x4f:
		upevent = TRUE;
		upval = imsg->Code | 0x80;
		if (shift)
			AnKeyScroll(SHIFTLEFT);
		else if (ctrl)
			AnKeyScroll(CTRLLEFT);
		else
			AnKeyScroll(LEFT);
		break;

	case 0x4e:
		upevent = TRUE;
		upval = imsg->Code | 0x80;
		if (shift)
			AnKeyScroll(SHIFTRIGHT);
		else if (ctrl)
			AnKeyScroll(CTRLRIGHT);
		else
			AnKeyScroll(RIGHT);
		break;

	case 0x4c:

		upevent = TRUE;
		upval = imsg->Code | 0x80;
		if (shift) 
			AnKeyScale(SHIFTUP);
		else if (ctrl)
			AnKeyScale(CTRLUP);
		else 
			AnKeyScale(UP);
		break;

	case 0x4d:
		upevent = TRUE;
		upval = imsg->Code | 0x80;

		if (shift) 
			AnKeyScale(SHIFTDOWN);
		else if (ctrl)
			AnKeyScale(CTRLDOWN);
		else 
			AnKeyScale(DOWN);
		break;

	default:
		AmiHelpKey(imsg,ANALYSIS_PANEL);	
		break;
}

 return (done);
}

/*******************************************************/
void AnKeyScale(char code)
{
 long visual = anTopScale;

 switch (code) {
	case CTRLUP:		
		visual = anBarHeight*20;
		break;

	case CTRLDOWN:
		visual = 0;
		break;

	case SHIFTUP:
		if (visual > anBarHeight*20)
			visual = anBarHeight*20;
		else	visual += anBarHeight;
		break;

	case SHIFTDOWN:
		if (visual < anBarHeight)
			visual = 0;
		else 	visual -= anBarHeight;
		break;

	case UP:
		if (visual < anBarHeight*20)
			visual++;
		break;

	case DOWN:
		if (visual > 0)
			visual--;
		break;
 }

 anBarScale = (float)visual/(float)barScale;
 anTopScale = visual;
 AnScrollBars(GID_ANSCALE,visual,anBarHeight*20,anBarHeight);
 AnRenderBars(anTopBar);
 AnRefresh();
}

/*******************************************************/
void AnKeyScroll(char code)
{
 long col;

 switch (code) {
	case CTRLLEFT:
		/* jump to beginning */
		anTopBar = 0;

		/* select first */
		AnSelect(0,FALSE);

		AnRenderBars(anTopBar);
		AnRefresh();
		break;

	case CTRLRIGHT:
		/* jump to end */
		if (anNumBars > anBarMax) {
			anTopBar = anNumBars-anBarMax;
			/* select last */
			AnSelect(anBarMax-1,FALSE);
		}
		else {
			/* select last */
			AnSelect(anNumBars-1,FALSE);
		}
		
		AnRenderBars(anTopBar);
		AnRefresh();
		break;

	case SHIFTLEFT:
		if (anSelBar == -1)
			AnSelect(0,TRUE);
		else if (anTopBar < anBarMax) {
			anTopBar=0;
			AnSelect(0,FALSE);
			AnRenderBars(anTopBar);
			AnRefresh();
		}
		else {
			col = anSelBar-anTopBar;
			anTopBar -= anBarMax-1;
			AnSelect(col,FALSE);
			AnRenderBars(anTopBar);
			AnRefresh();
		}
		break;

	case SHIFTRIGHT:
		if (anSelBar == -1)
			AnSelect(0,TRUE);
		else if (anNumBars <= anBarMax) {
			AnSelect(anNumBars-1,TRUE);
		}
		else if (anTopBar == anNumBars-anBarMax) 
			AnSelect(anBarMax-1,TRUE);
		else if (anNumBars - (anTopBar + anBarMax) < anBarMax) {
			anTopBar = anNumBars-anBarMax;
			AnSelect(anBarMax-1,FALSE);
			AnRenderBars(anTopBar);
			AnRefresh();
		}
		else {
			col = anSelBar-anTopBar;
			anTopBar += anBarMax-1;
			AnSelect(col,FALSE);
			AnRenderBars(anTopBar);
			AnRefresh();
		}
		break;

	case LEFT:
		if (anSelBar == -1)
			AnSelect(0,TRUE);
		else if (anSelBar == 0)
			break;
		else if (anSelBar == anTopBar) {
			if (anTopBar > 0) {
				anTopBar--;
				AnSelect(0,FALSE);
				AnRenderBars(anTopBar);
				AnRefresh();
			}
		}
		else AnSelect(anSelBar-anTopBar-1,TRUE);
		break;

	case RIGHT:
		if (anSelBar == -1)
			AnSelect(0,TRUE);
		else if (anSelBar == anNumBars-1)
			break;
		else if (anSelBar == anTopBar + anBarMax-1) {
			if (anTopBar+anBarMax < anNumBars) {
				anTopBar++;
				AnSelect(anBarMax-1,FALSE);
				AnRenderBars(anTopBar);
				AnRefresh();
			}
		}
		else AnSelect(anSelBar-anTopBar+1,TRUE);

		break;
 }

 AnScrollBars(GID_ANSCROL,anTopBar,anNumBars,anBarMax);
 AnBalance(); 
}

/*******************************************************/
BOOL AnHandleGadget(struct IntuiMessage *imsg)
{
 BOOL done = FALSE;
 struct Gadget *gad = (struct Gadget *)(imsg->IAddress);
 UWORD code = imsg->Code;

 switch (gad->GadgetID) {
	case GID_ANTYPE:
		graphtype = code;
		AnRenderBars(anTopBar);
		AnRefresh();
		AnBalance();
		break;

	case GID_ANOK:
		done=TRUE;
		break;
 }

 GF_ReplyIMsg(imsg);
 return (done);
}

/********************************************************/
BOOL AnHandleGadgetDown(struct IntuiMessage *imsg)
{
 struct Gadget *gad = (struct Gadget *)(imsg->IAddress);
 UWORD code = imsg->Code;
 BOOL done = FALSE;

 switch (gad->GadgetID) {
	case GID_ANFIELD:
		if (AnHitTest(imsg->Micros, imsg->Seconds, imsg->MouseX,imsg->MouseY)) {
			anFinalSel = anSelBar;
			done = TRUE;
		}
		else AnBalance();
		break;

	case GID_ANSCROL:
		anTopBar = code;
		AnRenderBars(anTopBar);
		AnRefresh();
		break;

	case GID_ANSCALE:
		/*anBarHeight = code;*/
		anBarScale = (float)code/(float)barScale;
		AnRenderBars(anTopBar);
		AnRefresh();
		break;
 }

 return (done);
}


/********************************************************/
void AnHandleMouseMove(struct IntuiMessage *imsg)
{
 struct Gadget *gad = (struct Gadget *)(imsg->IAddress);
 UWORD code = imsg->Code;

 switch (gad->GadgetID) {
	case GID_ANSCROL:
		anTopBar = code;
		AnRenderBars(anTopBar);
		AnRefresh();
		break;

	case GID_ANSCALE:
		/*barScale = code;*/
		anBarScale = (float)code/(float)barScale;
		AnRenderBars(anTopBar);
		AnRefresh();
		break;
 }

}

/*******************************************************/
void AnBalance(void)
{
 filterNode *filt;
 amountType zero =0;
 balanceType bal;
 
 if (anSelBar == -1)
	return;

 /* calculate the balance */
 filt = (filterNode *)DataOrd2Node((struct List *)&filtered,anSelBar);
 switch (graphtype) {
	case 0: memcpy(&bal,&filt->runningBal, sizeof(balanceType));
		break;

	case 1: memcpy(&bal,&filt->filterBal, sizeof(balanceType));
		break;

	case 2:	if (filt->entry->flags & VOIDED && filt->entry->type == CHECKTYPE)
			DataInitBal(DEPOSITTYPE,&zero,&bal);
		else	{
			DataInitBal(filt->entry->type,&filt->entry->amount,&bal);
		}
		break;
 }

 DataBuildBal(usrAccount.decimal,&bal,anBalance);
 GF_SetGadgetAttrs(analGUI,an_gadgetspecs[GID_ANBAL].gs_Gadget,
	GTTX_Text,anBalance,
	TAG_DONE);
}

/*******************************************************/
void AnGraphInit(void)
{
 balanceType runbal;

 anBalance[0] = 0;
 GF_SetGadgetAttrs(analGUI,an_gadgetspecs[GID_ANBAL].gs_Gadget,
	GTTX_Text,anBalance,
	TAG_DONE);

 /* grab window RP */
 GF_GetGUIAttr(analGUI, GUI_Window, &anWin, TAG_DONE);
 anRP = anWin->RPort;

 /* reset state vars */
 anSelBar = selRow;
 anNumBars = entryCount;
 anFinalSel = -1;
 
 /* turn on mouse clicks in field */
 AN_MainSpecs[GID_ANFIELD]->gs_Gadget->Activation |= GACT_IMMEDIATE;
 
 /* running balances and barmax */
 runbal = DataRunningBals(&entries,&filtered);
 barScale = runbal.dollar; /* round off cents */
 anBarScale = (float)anBarHeight / (float)barScale;

 AnFilterBal();

 /* if selrow, render around selrow in middle */
 if (anSelBar != -1) {
	if (anSelBar < anBarMax)
		anTopBar = 0;
	else if (anNumBars - anSelBar <= anBarMax)
		anTopBar = anNumBars - anBarMax;
	else	anTopBar = anSelBar - (anBarMax/2);
	
 }
 else {
 	/* render from rightmost */
	if (anBarMax > anNumBars)
  		anTopBar = 0;
	else
		anTopBar = anNumBars-anBarMax;
 }

 /* prep scroll bars */
 anTopScale = anBarHeight;
 AnScrollBars(GID_ANSCROL,anTopBar,anNumBars,anBarMax);
 AnScrollBars(GID_ANSCALE,anBarHeight,anBarHeight*20,anBarHeight);

 AnRenderBars(anTopBar);

 /* refresh display */
 AnRefresh();

 if (anSelBar != -1)
	AnBalance();
}

/********************************************************/
void AnScrollBars(long bar, long top, long total, long visible)
{
  GF_SetGadgetAttrs(analGUI,AN_MainSpecs[bar]->gs_Gadget,
	GTSC_Top, top,
	GTSC_Total, total,
	GTSC_Visible, visible,
	TAG_DONE);
}

/********************************************************/
void AnDeselect(BOOL towin)
{
 BYTE oldmode, oldmask;
 ULONG height,top, row = anSelBar;

 if (anSelBar == -1) return;
;
 anSelBar = -1;

 /* if not visible, skip graphical rendering */
 if (row < anTopBar || row > anTopBar+anBarMax-1)
		return; 

 /* make zero based */
 row -= anTopBar;
 
 /* vert color over bar */
 if (towin) {
	oldmode = anRP->DrawMode;
	oldmask = anRP->Mask;
	SetDrMd(anRP,COMPLEMENT);
	SafeSetWriteMask(anRP,0x2);
 
	RectFill(anRP,
        	anLeft + anBarWidth*row, anTop,
        	anLeft + anBarWidth*(row+1)-1,anTop+anHeight-1 );

	WaitBlit();

	SetDrMd(anRP,oldmode);
	SafeSetWriteMask(anRP,oldmask);

}

/* now render it in the real buffer */
oldmode = anWorkRP.DrawMode;
oldmask = anWorkRP.Mask;
SetDrMd(&anWorkRP,COMPLEMENT);
SafeSetWriteMask(&anWorkRP,0x2);

RectFill(&anWorkRP,
        	anBarWidth*row, 0,
        	anBarWidth*(row+1)-1,anHeight-1 );

WaitBlit();

SetDrMd(&anWorkRP,oldmode);
SafeSetWriteMask(&anWorkRP,oldmask);

anSelBar = -1;

}

/********************************************************/
void AnSelect(int row, BOOL towin)
{
BYTE oldmode,oldmask;
ULONG height,top;

if (anSelBar == row + anTopBar)
	return;

AnDeselect(towin);

/* vert color over bar */
if (towin) {
	oldmode = anRP->DrawMode;
	oldmask = anRP->Mask;
	SetDrMd(anRP,COMPLEMENT);
	SafeSetWriteMask(anRP,0x2);
 
	RectFill(anRP,
        	anLeft + anBarWidth*row, anTop,
        	anLeft + anBarWidth*(row+1)-1,anTop+anHeight-1 );

	WaitBlit();

	SetDrMd(anRP,oldmode);
	SafeSetWriteMask(anRP,oldmask);

}

/* now render it in the real buffer */
oldmode = anWorkRP.DrawMode;
oldmask = anWorkRP.Mask;
SetDrMd(&anWorkRP,COMPLEMENT);
SafeSetWriteMask(&anWorkRP,0x2);

RectFill(&anWorkRP,
        	anBarWidth*row, 0 ,
        	anBarWidth*(row+1)-1,anHeight-1 );

WaitBlit();

SetDrMd(&anWorkRP,oldmode);
SafeSetWriteMask(&anWorkRP,oldmask);

anSelBar = row+anTopBar;
}


/********************************************************/
BOOL AnHitTest(ULONG Micros, ULONG Seconds, ULONG x, ULONG y)
{
 ULONG col,test;
 static LONG lastcol = -1;
 BOOL retval = FALSE;
 static ULONG micros = 0, secs = 0;

  if (anBarMax > anNumBars)
	test = anNumBars;
 else	test = anBarMax;

 /* quick clip of analysis gadget */
 if (x < anLeft || x > anWidth+anLeft ||
     y < anTop  || y > anHeight+anTop )
          return (FALSE);
 

 /* calc row */
 x -= anLeft;
 col = x / anBarWidth;
 
 /* ok, is it a valid col? */
 if (col < test) {
	if (DoubleClick(secs,micros,Seconds,Micros) && lastcol == col) {
		retval = TRUE;
	}
   	AnSelect(col, TRUE);
 }
 
 micros = Micros;
 secs = Seconds;
 lastcol = col;

 return (retval);

}

/********************************************************/
void AnRenderBars(int bar)
{
filterNode *filter;
long  barx, bary, barh;
BOOL neg = 0;
int x;
int sb = anSelBar;

bar++;


/* clear area */
SetAPen(&anWorkRP,DETAILPEN);
/*RectFill(&anWorkRP,0,0,anWidth,anHeight);*/
SetRast(&anWorkRP, DETAILPEN);

filter = (filterNode *)DataOrd2Node((struct List *)&filtered,bar-1);
for (x=bar;x<=anNumBars && x < bar + anBarMax; x++) {

	barx = (x-bar)*anBarWidth;
	if (filter->entry->flags & VOIDED)
		barh=0;
	else {
		if (graphtype == 2) {
			barh = filter->entry->amount / decimalModulos[usrAccount.decimal];
			if (barh < 0) {
				neg = 1;
				barh *= -1;
			}
		}
		else if (graphtype == 1) {
			barh = filter->filterBal.dollar;
			neg = filter->filterBal.neg;
		}
		else	{
			barh = filter->runningBal.dollar;
			neg = filter->runningBal.neg;
		}
	}

	bary = anBarHeight;
	if (neg) {
		barh = barh*anBarScale;
		if (barh >= anBarHeight) {
			SetAPen(&anWorkRP,SHINEPEN);
			Move(&anWorkRP,barx+1,anHeight-1);
			Draw(&anWorkRP,barx+anBarWidth-2,anHeight-1);
			barh = anBarHeight-2;
		}

		/*scoot below the dashed line */
		bary += barh;
		barh = anBarHeight;
	}
	else 	{
		barh = (long)(barh*anBarScale); 
		if (barh  >= anBarHeight) {
			SetAPen(&anWorkRP,SHINEPEN);
			Move(&anWorkRP,barx+1,0);
			Draw(&anWorkRP,barx+anBarWidth-2,0);
			barh = anBarHeight-1;
		}
		barh = anBarHeight - barh;
	}

	if (filter->entry->type == DEPOSITTYPE) 
		SetAPen(&anWorkRP, TEXTPEN);
	else	SetAPen(&anWorkRP, BLOCKPEN);

	RectFill(&anWorkRP, barx + 1, barh, barx + anBarWidth - 2, bary );
	WaitBlit();

	filter = (filterNode*) filter->node.mln_Succ;
}

/* draw dashed middle line */
SetAPen(&anWorkRP,SHINEPEN);
SetDrPt(&anWorkRP,0xaaaa);
Move(&anWorkRP,0,anHeight/2);
Draw(&anWorkRP,anWidth,anHeight/2);
SetDrPt(&anWorkRP,~0);

/* is the selected bar visible? */
if (anSelBar != -1 && anSelBar >= anTopBar && anSelBar <= anTopBar+anBarMax-1) {
	sb = anSelBar;
	anSelBar = -1;
	AnSelect(sb-anTopBar,FALSE);
}
}

/********************************************************/
void AnRefresh(void)
{
/*
 BltBitMapRastPort(anWorkRP.BitMap,0,0,anRP,anLeft,anTop,
        anWidth,anHeight,0xc0);
 WaitBlit();
*/

ClipBlit(&anWorkRP,0,0,anRP,anLeft,anTop,anWidth,anHeight,(ULONG)0xc0);
}

/*****************************************************************/
BOOL AnalysisSetup(void)
{
 if (AnalysisCreate() == FALSE) {
	AnalysisFree();
	return (FALSE);
 }

 return (TRUE);
}

/*****************************************************************/
BOOL AnalysisCreate(void)
{
 int x;  

 /* define geometry (-2 accounts for shadowing border) */
 anWidth =  AN_MainSpecs[GID_ANFIELD]->gs_Gadget->Width - 4;
 anHeight=  AN_MainSpecs[GID_ANFIELD]->gs_Gadget->Height - 2;
 anTop   =  AN_MainSpecs[GID_ANFIELD]->gs_Gadget->TopEdge + 1;
 anLeft  =  AN_MainSpecs[GID_ANFIELD]->gs_Gadget->LeftEdge + 2;

 /* 
  * extract information about our main window 
  */
   
 GF_GetGUIAttr(gui, GUI_Window, &anWin, TAG_DONE);

 anRP = anWin->RPort;
 andepth = anRP->BitMap->Depth;  
            
 /* 
  * create working rast port area 
  */
 
 /* create bitmap */
 InitBitMap(&anbuffer,andepth, anWidth, anHeight);

 for (x=0;x<andepth;x++) {
        anbuffer.Planes[x] = (PLANEPTR)AllocRaster(anWidth+1, 
                                        anHeight+1);
        if (anbuffer.Planes[x] == NULL) return (FALSE);
 }

 /* create area buffer */
 for (x=0;x<ANAREA_SIZE;x++) anAreaBuffer[x] =0;
 InitArea(&anarea, anAreaBuffer, (ANAREA_SIZE*2)/5);

 /* create TmpRas */
 antmprp = (void *)AllocVec((anWidth+1)*(anHeight+1), MEMF_CHIP);
 if (antmprp == NULL) return (FALSE);
 
 InitTmpRas(&antmp,antmprp,(anWidth+1)*(anHeight+1));

 /* link in to our work rastport */
 InitRastPort(&anWorkRP);
 anWorkRP.BitMap = &anbuffer;
 anWorkRP.AreaInfo = &anarea;
 anWorkRP.TmpRas = &antmp;
 anWorkRP.Layer = NULL;

 /* some tiny layout calcs */
 anBarWidth = regFont->tf_XSize;
 anBarMax = anWidth / anBarWidth;
 anBarHeight = anHeight / 2;

 return (TRUE);
}

/**************************************************************/
void AnalysisFree(void)
{
 int x;

 /*
  * anRP stuff
  */
       
 /* free up bitmap */
 for (x=0;x<andepth;x++)
        if (anbuffer.Planes[x] != NULL) {
                 FreeRaster(anbuffer.Planes[x],anWidth+1,anHeight+1);  
        }
        
 /* free anTmpRas */
 if (antmprp != NULL) {
        FreeVec(antmprp);
 }

}

/****************************************************************/
balanceType AnFilterBal(void)
{
 filterNode *next, *filt;
 amountType zero = 0;
 balanceType bal, largest;

 DataInitBal(DEPOSITTYPE,&zero,&largest);
 DataInitBal(DEPOSITTYPE,&zero,&bal);

 if (filtered.mlh_TailPred == &filtered)
	return largest;

 filt = (filterNode *)filtered.mlh_Head;
 while ((next = (filterNode *)filt->node.mln_Succ)) {
	if (filt->entry->flags & VOIDED)
		DataInitBal(DEPOSITTYPE,&zero,&filt->filterBal);
	else {
		DataAddBal(filt->entry->type,&filt->entry->amount,&bal);
		memcpy(&filt->filterBal,&bal, sizeof(balanceType));

		if (DataCmpBal(FALSE,&bal, &largest) == 1)
			memcpy(&largest,&bal,sizeof(balanceType));			
	}

	filt = next;
 }

 return largest; 
}
