/**************************************************************************
 *
 *************************************************************************/

#include "gemfintl.h"

#define EXTEND_INTERIOR 0x8000

typedef struct {
	XUSERBLK   xub;
	short	   tick_limit;
	short	   tick_count;
	short	   tick_width;
	short	   curr_width;
	short	   full_width;
	short	   fill_style;
	short	   xoffset;
} ThermoInfo;

#ifdef GEMFAST_PROTOS
  static long GCALLBACK draw_thermo(XPARMBLK *pb)
#else
  static long GCALLBACK draw_thermo(pb)
	register XPARMBLK	*pb;
#endif
/*****************************************************************************
 * draw a G_THERMO object.
 *	if the EXTEND_INTERIOR bit is set in the fill style, the redraw was
 *	triggered by xob_thermo_update() to increment the interior, indicating
 *	progress.  in this case, we use a special clipping rectangle that
 *	covers just the part of the interior we're drawing; this avoids the
 *	graphic ugliness of erasing and redrawing the entire interior on
 *	each tick of the thermo.
 ****************************************************************************/
{
	register ThermoInfo *pt = (ThermoInfo *)pb->pub;
	register short		 vdi_handle;
	register short		 fillwidth;
	VRECT				 cliprect;
	VRECT				 boxrect;
	GRECT				 objrect;

	if (0 == (vdi_handle = apl_vshared())) {
		return 0;
	}

	fillwidth = pt->tick_count * pt->tick_width;
	if (fillwidth > pt->full_width) {
		fillwidth = pt->full_width;
	}

	rc_copy(&pb->drawrect, &objrect);
	objrect.g_x += pt->xoffset;
	objrect.g_w  = pt->full_width;

	rc_gtov(&objrect, &boxrect);
	rc_vadjust(&boxrect, 1, 1);

	if (pt->fill_style & EXTEND_INTERIOR) {
		objrect.g_x += pt->curr_width - 1;
		rc_intersect(&pb->cliprect, &objrect);
		rc_gtov(&objrect, &cliprect);
		vs_clip(vdi_handle, 1, (short *)&cliprect);
	} else {
		rc_gtov(&pb->cliprect, &cliprect);
		vs_clip(vdi_handle, 1, (short *)&cliprect);
		vsf_interior(vdi_handle, IS_HOLLOW);
		v_bar(vdi_handle, (short *)&boxrect);
	}

	boxrect.v_x2 = boxrect.v_x1 + fillwidth;

	vsf_interior(vdi_handle, IS_PATTERN);
	vsf_style(vdi_handle, pt->fill_style & 0x0007);
	v_bar(vdi_handle, (short *)&boxrect);
	vsf_style(vdi_handle, IP_SOLID);
	vsf_interior(vdi_handle, IS_SOLID);

	vs_clip(vdi_handle, 0, (short *)&cliprect);

	pt->curr_width = fillwidth;

	return 0;

}

short xob_thermo_create(ptree, object, nincr)
	OBJECT			*ptree;
	register short	   object;
	register short	   nincr;
/*****************************************************************************
 * transform and object into a G_THERMO object.
 ****************************************************************************/
{
	register short			iwidth;
	register OBJECT 	 *pobj = &ptree[object];
	register ThermoInfo  *pt;

/*-------------------------------------------------------------------------
 * Check for zero increments to prevent div-by-zero errors.
 * Calc the pixel width of one increment.
 * Make sure a VDI workstation is available for later.
 *-----------------------------------------------------------------------*/

	if (0 >= nincr)
		return gfErr_parameter_range;

	if (0 == (iwidth = pobj->ob_width / nincr))
		return gfErr_parameter_range;

	if (0 == apl_vshared()) {
		return gfErr_vdi_handle;
	}

/*-------------------------------------------------------------------------
 * If the object has already been made into a G_THERMO extended object,
 * just get its pointer, else make it into such an object.
 *-----------------------------------------------------------------------*/

	if (NULL != (pt = XUBPTR(pobj))) {
		if (pt->xub.ob_type != G_THERMO) {
			return gfErr_wrong_type;
		}
	} else {
		if (NULL == (pt = apl_malloc((long)sizeof(*pt)))) {
			return gfErr_no_memory;
		}
		xob_transform(ptree, object, &pt->xub, draw_thermo, NULL, (long)sizeof(*pt));
		pt->xub.ob_type = G_THERMO;
	}

/*-------------------------------------------------------------------------
 *
 *-----------------------------------------------------------------------*/

	pt->curr_width = 0;
	pt->tick_limit = nincr;
	pt->tick_count = 0;
	pt->tick_width = iwidth;
	pt->full_width = nincr * iwidth;
	pt->xoffset    = (pobj->ob_width - pt->full_width) / 2;
	pt->fill_style = (short)(((long)pt->xub.ob_spec >> 4) & 0x0007);

	return 0;

}

short xob_thermo_update(ptree, object, newpos, pclip)
	OBJECT *ptree;
	short	object;
	short	newpos;
	GRECT  *pclip;
/*****************************************************************************
 * update increment count, with optional redraw.
 ****************************************************************************/
{
	register ThermoInfo *pt;
	short				  oldpos;

	if (NULL == (pt = XUBPTR(&ptree[object]))) {
		return 0;
	}

	if (pt->xub.ob_type != G_THERMO) {
		return 0;
	}

	oldpos = pt->tick_count;

	if (newpos == OBJ_TINQUIRE) {
		return oldpos;
	} else if (newpos < 0) {
		newpos = pt->tick_count + 1;
	}

	if (newpos > pt->tick_limit) {
		newpos = pt->tick_limit;
	}

	if (oldpos == newpos) {
		return oldpos;
	}

	pt->tick_count = newpos;

	if (pclip != NULL) {
		if (oldpos < newpos) {
			pt->fill_style |= EXTEND_INTERIOR;
		}
		objc_draw(ptree, object, MAX_DEPTH, RECTVALS(pclip));
		pt->fill_style &= ~EXTEND_INTERIOR;
	}

	return oldpos;
}

short xob_thermo_change(ptree, object, nincr)
	OBJECT *ptree;
	short	object;
	short	nincr;
/*****************************************************************************
 * change number of increments; real work is done by xob_thermo_create().
 ****************************************************************************/
{
	return xob_thermo_create(ptree, object, nincr);
}

