// datautils.cp
// data handling utilities
//データの表示と、拡大縮小、スクロールを行う
#define DATAUTILS_SRC

#include <complex.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <Strings.h>

//#include <Quickdraw.h>
//#include <CursorDevices.h>

#include "debugs.h"
#include "datautils.h"


// local funcionts
static void  PLShowPointValues(PlotFormat  *pl);
static void  PLActonRateDialog(PlotFormat *pl, EventRecord ev);
static short  PLGetDataIndex(PlotFormat *pl, double xval);
static void  PLShowMarkVal(PlotFormat *pl);

// call this function only at the starting of the program.
void  PLInit(PlotFormat *pl, short winID)
{
	GrafPtr cptr;
	
	GetPort(&cptr);
	
	pl->w = GetNewCWindow(winID, NULL, (WindowPtr)-1);
	SetPort(pl->w);
	SetWRefCon(pl->w, (long)pl);
	pl->ObjectID = PLOT_OBJECT_ID;
	
	pl->MarkCurHandle = GetCCursor(PLOT_MARKCSR_ID);
	pl->MQCurHandle = GetCCursor(PLOT_MARQUEECSR_ID);
	pl->DFCurHandle = GetCCursor(PLOT_DEFAULTCSR_ID);
	pl->DRCurHandle = GetCCursor(PLOT_DRAGMARKCSR_ID);

	
	TextSize(10);
	TextFont(kFontIDGeneva);
	TextFace(condense);
	TextMode(srcCopy);

	SetPort(cptr);
}

WindowPtr  PLQuerywin(PlotFormat *pl)
{
	return pl->w;
}

void  PLGoAway(PlotFormat *pl, EventRecord ev)
{
	
	if(pl->w == FrontWindow()){
		if(TrackGoAway(pl->w, ev.where)){
			HideWindow(pl->w);
		}
	}
}


// set scroll bars
void  PLScrlInit(PlotFormat *pl, short vscrID, short hscrID)
{
	pl->vscrl = GetNewControl(vscrID, pl->w);
	pl->hscrl = GetNewControl(hscrID, pl->w);	

	pl->rateb = GetNewControl(PLOT_RATE_ID, pl->w);
	pl->markb = GetNewControl(PLOT_MARK_ID, pl->w);
	
	SetControlValue(pl->vscrl, 0);
	SetControlValue(pl->hscrl, 0);
	PLSetScrlRange(pl);
}

// this function shold be call after PLSetData
void  PLSetScrlRange(PlotFormat *pl)
{
	SetControlMinimum(pl->hscrl, 0);
	SetControlMinimum(pl->vscrl, 0);
	SetControlMaximum(pl->hscrl, (short)((pl->xmax - pl->xmin) / pl->xpd) );
	SetControlMaximum(pl->vscrl, (short)((pl->ymax - pl->ymin) / pl->ypd) );
}

void PLSetScrlVal(PlotFormat *pl)
{
	short newval;
	// horizontal bar
	newval = (short)((pl->xorg - pl->xmin) / pl->xpd);
	SetControlValue(pl->hscrl, newval);
	// vertical bar
	newval = (short)((pl->ymax - pl->yorg) / pl->ypd);
	SetControlValue(pl->vscrl, newval);
}

//データ表示の初期設定
short  PLSetData(PlotFormat *pl, double datax[], double datay[], short num)
{
	short i;

	if(num == 0) return ZERO_DATA;
	
	pl->markflag = false;
	pl->markcount = 0;
	for(i = 0 ; i < N_PLOTMARK ; i++){
		pl->marknum[i] = 0;
		pl->markxval[i] = 0;
		pl->markxcrd[i] = 0;
	}

	pl->x = datax;
	pl->y = datay;
	pl->n = num;

	// get min and max value of data;
	pl->xmin = DATA_TOO_LARGE;
	pl->xmax = DATA_TOO_SMALL;
	pl->ymin = DATA_TOO_LARGE;
	pl->ymax = DATA_TOO_SMALL;

	for (i = 0 ; i < pl->n ; i++){
		if(pl->xmin > *(pl->x + i)) pl->xmin = *(pl->x + i);
		if(pl->xmax < *(pl->x + i)) pl->xmax = *(pl->x + i);
		if(pl->ymin > *(pl->y + i)) pl->ymin = *(pl->y + i);
		if(pl->ymax < *(pl->y + i)) pl->ymax = *(pl->y + i);
	}
	
	pl->xorg = pl->xmin;
	pl->yorg = pl->ymax;
	pl->xpd  = (pl->xmax - pl->xmin) / (double)(pl->w->portRect.right - LEFTZONE - 16);
	pl->ypd  = (pl->ymax - pl->ymin) / (double)(pl->w->portRect.bottom - TOPZONE - 16);
	
	pl->hbarpos = (pl->w->portRect.bottom - TOPZONE - 16) / 2;
	pl->isFirst = true;

	// default color
	pl->rgb.red = 0;
	pl->rgb.green = 0;
	pl->rgb.blue = 0xffff;
	
	return NOERR;
}

// display values of mause point
// and marker values
void  PLSetDrawParms(PlotFormat *pl)
{
	GrafPtr cptr;
	PenState pstate;
	
	GetPort(&cptr);
	SetPort(pl->w);
	GetPenState(&pstate);

	RGBForeColor(&PLOT_RGBs[PLOT_BLACK]);
	SetRect(&(pl->plotrect), LEFTZONE+1, TOPZONE+1, 
			pl->w->portRect.right - 16, pl->w->portRect.bottom-16);	
	SetRect(&(pl->currect), 0, TOPZONE+1,
			LEFTZONE+1, pl->w->portRect.bottom-16);
	SetRect(&(pl->valrect), 0, 0,
			pl->w->portRect.right, 40);

	SetRect(&(pl->pointvalrect), 80, 0, 170, 40);
	SetRect(&(pl->barvalrect), 170, 0,290, 20);
	SetRect(&(pl->markvalrect), 290, 0, 500, 40);
	
	SetPort(cptr);
	SetPenState(&pstate);
}

void PLSetInirialMarkPos(PlotFormat *pl, int pos[])
{
	int i;
	
	for(i = 0 ; i < N_PLOTMARK ; i++){
		pl->marknum[i] = pos[i];
		pl->markxval[i] = *(pl->x + pos[i]);
		pl->markxcrd[i] = pl->plotrect.left + (short)((pl->markxval[i] - pl->xorg) / pl->xpd);
	}
}
		

//  for Update
void  PLFullDraw(PlotFormat *pl)
{
	GrafPtr cptr;
	PenState pstate;
	
	GetPort(&cptr);
	SetPort(pl->w);
	GetPenState(&pstate);
	
	EraseRect(&(pl->w->portRect));

	PenNormal();
	RGBForeColor(&PLOT_RGBs[PLOT_BLACK]);
	PenMode(patCopy);
	FrameRect(&(pl->valrect));
	FrameRect(&(pl->currect));
	
	// draw graph
	PLDrawGraph(pl);
	
	// show markvalue
	PLShowMarkVal(pl);
	PLDrawMarkLines(pl);

	// Set gauge position and calcurate gauge value
	pl->isFirst = true;

	// scrollbar and GrowBox
	DrawGrowIcon(pl->w);
	DrawControls(pl->w);
	UpdateControls(pl->w, pl->w->visRgn);
	
	SetPort(cptr);
	SetPenState(&pstate);

}

void  PLDrawGraph(PlotFormat *pl)
{
	short xp, yp;
	short i;
	RgnHandle savergn;
	PenState pstate;

	GrafPtr cptr;

	GetPenState(&pstate);
	GetPort(&cptr);
	SetPort(pl->w);
	
	PenNormal();
	RGBForeColor(&PLOT_RGBs[PLOT_BLACK]);
	PenMode(patCopy);
	EraseRect(&(pl->currect));
	FrameRect(&(pl->currect));
	pl->isFirst = true;

	savergn = NewRgn();
	GetClip(savergn);
	PenMode(patCopy);
	RGBForeColor(&(pl->rgb));

	EraseRect(&(pl->plotrect));
	ClipRect(&(pl->plotrect));

	i = 0;
	xp = pl->plotrect.left + (short)((*(pl->x +i) - pl->xorg) / pl->xpd);
	yp = pl->plotrect.top +  (short)((pl->yorg - *(pl->y + i)) / pl->ypd);
	MoveTo(xp, yp);
	for(i = 1 ; i < pl->n ; i++){
		xp = pl->plotrect.left + (short)((*(pl->x +i) - pl->xorg) / pl->xpd);
		yp = pl->plotrect.top +  (short)((pl->yorg - *(pl->y + i)) / pl->ypd);
		LineTo(xp, yp);
	}
	PenNormal();
	SetPenState(&pstate);
	SetClip(savergn);
	DisposeRgn(savergn);
	SetPort(cptr);
	SetPenState(&pstate);

}


void  PLDrawhbar(PlotFormat *pl)
{
	GrafPtr cptr;
	PenState pstate;
	PixPatHandle ppath;

	GetPenState(&pstate);
	GetPort(&cptr);
	SetPort(pl->w);

	ppath = NewPixPat();
	MakeRGBPat(ppath, &PLOT_RGBs[PLOT_RED]);
	PenNormal();
	PenPixPat(ppath);
	PenMode(patXor);
	// Draw gauge
	// Erase 
	if(pl->isFirst == false){
		MoveTo(9, pl->hbarcurpos);
		LineTo(1, pl->hbarcurpos-3);
		LineTo(1, pl->hbarcurpos+3);
		LineTo(9, pl->hbarcurpos);
	}
	// Draw
	MoveTo(9, pl->hbarpos);
	LineTo(1, pl->hbarpos-3);
	LineTo(1, pl->hbarpos+3);
	LineTo(9, pl->hbarpos);

	// Draw horizontal bar
	if(pl->isFirst == false){	// erase current bar
		PLHidehbar(pl);
	}
	MoveTo(10, pl->hbarpos);	// and draw new bar
	LineTo(pl->plotrect.right, pl->hbarpos);
	
	pl->hbarval = pl->yorg - (double)(pl->hbarpos - pl->plotrect.top) * pl->ypd;
	pl->hbarcurpos = pl->hbarpos;
	pl->isFirst = false;	

	SetPort(cptr);
	SetPenState(&pstate);
	DisposePixPat(ppath);

}

void PLHidehbar(PlotFormat *pl)
{
	GrafPtr cptr;
	PenState pstate;
	PixPatHandle ppath;

	GetPenState(&pstate);
	GetPort(&cptr);
	SetPort(pl->w);

	ppath = NewPixPat();
	MakeRGBPat(ppath, &PLOT_RGBs[PLOT_RED]);
	PenNormal();
	PenPixPat(ppath);
	PenMode(patXor);

	MoveTo(10, pl->hbarcurpos);
	LineTo(pl->plotrect.right, pl->hbarcurpos);
	pl->isFirst = true;

	SetPort(cptr);
	SetPenState(&pstate);
	DisposePixPat(ppath);

}

void  PLDoMovehbar(PlotFormat *pl, EventRecord ev)
{
	Point mouse;
	char valstr[30], *vstr;
	GrafPtr cptr;
	PenState pstate;
	
	if(pl->w == FrontWindow() ){
		GetPort(&cptr);
		SetPort(pl->w);
		GetPenState(&pstate);
		GetMouse(&mouse);	
		if(PtInRect(mouse, &(pl->currect)) && (ev.what == mouseDown || StillDown() ) ){
			pl->hbarpos = mouse.v;
			PLDrawhbar(pl);
			EraseRect(&(pl->barvalrect));
			FrameRect(&(pl->barvalrect));
			MoveTo(pl->barvalrect.left +2, pl->barvalrect.bottom - 3);
			sprintf(valstr,"hbar: % 6.4e", pl->hbarval);
			vstr = valstr;
			DrawString(C2PStr(vstr));
		}
		SetPort(cptr);
		SetPenState(&pstate);
	}
}


void  PLDoMouseMove(PlotFormat *pl, EventRecord ev)
{
	Point mouse;
	static Point mptcur;
	GrafPtr cptr;

	if(pl->w == FrontWindow() ){	
		GetPort(&cptr);
		SetPort(pl->w);
		GetMouse(&mouse);
			
		if(mptcur.v == mouse.v  && mptcur.h == mouse.h) return;
	
		if(PtInRect(mouse, &(pl->plotrect)) ){
			if(pl->markflag == false) SetCursor(*GetCursor(crossCursor));
			else                      SetCCursor(pl->MarkCurHandle);
			pl->mpt = mouse;
			PLShowPointValues(pl);
			mptcur = mouse;
		}
		else{
			InitCursor();
		}
	
		PLDoMovehbar(pl, ev);
		SetPort(cptr);
	}
}


static void  PLShowPointValues(PlotFormat  *pl)
{
	char pointstr[30], *pstr;
	double xval, yval;
	GrafPtr cptr;
	PenState pstate;
	short n;
	
	GetPort(&cptr);
	SetPort(pl->w);
	GetPenState(&pstate);
	
	xval = pl->xorg + pl->xpd * (double)(pl->mpt.h - pl->plotrect.left);
	yval = pl->yorg - pl->ypd * (double)(pl->mpt.v - pl->plotrect.top);
	pstr = pointstr;
	
	PenNormal();
	EraseRect(&(pl->pointvalrect));
	ForeColor(blackColor);
	FrameRect(&(pl->pointvalrect));

	n = PLGetDataIndex(pl, xval);
	MoveTo(pl->pointvalrect.left +2, pl->pointvalrect.top + 12);
	sprintf(pointstr,"Point: % 4.0d", n);
	DrawString(C2PStr(pstr));

	MoveTo(pl->pointvalrect.left +2, pl->pointvalrect.top + 24);
	sprintf(pointstr,"X: % 8.6e", xval);
	DrawString(C2PStr(pstr));

	MoveTo(pl->pointvalrect.left +2, pl->pointvalrect.bottom -3);
	sprintf(pointstr,"Y: % 8.6e", yval);
	DrawString(C2PStr(pstr));
	
	SetPort(cptr);
	SetPenState(&pstate);
}

// action for scroll bar
void  PLContentClick(PlotFormat *pl, EventRecord ev)
{
	ControlHandle control;
	Point mouse, movepoint;
	long part;
	short i, n;
	short mindex;
	double xv;
	GrafPtr cptr;
	Rect mRect, boundRect;

	GetPort(&cptr);
	SetPort(pl->w);
	mouse = ev.where;
	GlobalToLocal(&mouse);
	
	// mark
	if(PtInRect(mouse, &(pl->plotrect)) && pl->markflag == true){
		xv = pl->xorg + pl->xpd * (double)(mouse.h - pl->plotrect.left);
		n = PLGetDataIndex(pl, xv);
		pl->marknum[pl->markcount] = n;
		pl->markxval[pl->markcount] = *(pl->x + n);
		pl->markcount += 1;
		PLShowMarkVal(pl);
		PLDrawMark1Line(pl, pl->markcount-1);
		if(pl->markcount >= N_PLOTMARK) pl->markflag = false;
	}
	
	// drag mark
	if(PtInRect(mouse, &(pl->plotrect)) && (mindex = PLGetClickedMark(pl, mouse)) != -1
	    &&pl->markflag == false){
	    boundRect = pl->plotrect;
	    PLGetMarkBound(pl, mindex, &boundRect);
	    /* clicked position may be +-1 of the marker */
	    mouse.h = pl->plotrect.left + (short)((pl->markxval[mindex] - pl->xorg) / pl->xpd);
		movepoint = mouse;
		LocalToGlobal(&movepoint);
	    PLMoveCursor(movepoint);
	    SetRect(&mRect, mouse.h, boundRect.top, mouse.h+1, boundRect.bottom);
	    SetCCursor(pl->DRCurHandle);
		PLDrawMark1Line(pl, mindex);	// delete line
		PLTrackMarquee(pl, &mRect, boundRect, MOVE_ONLY_HORIZ);
		xv = pl->xorg + pl->xpd * (double)(mRect.right - pl->plotrect.left);
		n = PLGetDataIndex(pl, xv);
		pl->marknum[mindex] = n;
		pl->markxval[mindex] = *(pl->x + n);
		PLDrawMark1Line(pl, mindex);	// show new line
		PLShowMarkVal(pl);
		SetCCursor(pl->DFCurHandle);
	}

	// marquee  Drag & command key
	if(PtInRect(mouse, &(pl->plotrect)) && PLGetClickedMark(pl, mouse) == -1
	    &&pl->markflag == false){
		SetRect(&mRect, mouse.h, mouse.v, mouse.h, mouse.v);
		SetCCursor(pl->MQCurHandle);
		PLTrackMarquee(pl, &mRect, pl->plotrect, CORNER_GROW);
		SetCCursor(pl->DFCurHandle);
		if((ev.modifiers & cmdKey) != 0){
			PLResizeGraph(pl, &mRect);
		}
	}
	// Autoscale graph  click and option key
	if(PtInRect(mouse, &(pl->plotrect))  && PLGetClickedMark(pl, mouse) == -1
	   && pl->markflag == false && (ev.modifiers & optionKey) != 0){
		PLAutoScaleGraph(pl);
	}
	
	// controls
	part = FindControl(mouse, pl->w, &control);
	if(control == pl->hscrl){
		PLActionHscrl(pl, ev);
		PLDrawGraph(pl);
		PLDrawMarkLines(pl);
	}
	else if(control == pl->vscrl){
		PLActionVscrl(pl, ev);
		PLDrawGraph(pl);
		PLDrawMarkLines(pl);
	}
	else if(control == pl->rateb){
		if(TrackControl(control, mouse, NULL) != NULL){
			PLActonRateDialog(pl, ev);
		}
		PLFullDraw(pl);
	}
	else if(control == pl->markb){
		if(TrackControl(control, mouse, NULL) != NULL){
			PLHideMarkLines(pl);
			pl->markcount = 0;
			for(i = 0 ; i < N_PLOTMARK ; i++){
				pl->markcount = 0;
				pl->markflag = true;
				pl->marknum[i] = 0;
				pl->markxval[i] = 0;
			}
			PLShowMarkVal(pl);
		}
	}
	
	PLDoMovehbar(pl, ev);			
	SetPort(cptr);
}

static void  PLActonRateDialog(PlotFormat *pl, EventRecord ev)
{
	short itemtype, item;
	Rect box;
	DialogPtr dlg;
	Handle itemH;
	Str255 rate;
	double xrate, yrate;
	GrafPtr cptr;
	
	GetPort(&cptr);
	dlg = GetNewDialog(PLOT_RATE_ID, nil, (WindowPtr)-1);
	SetPort(dlg);
	while(1){
		ModalDialog(0, &item);
		if(item == 1){	// this dialog's OK
			// get X coeffcient(DITL is 5)
			GetDialogItem(dlg, 5, &itemtype, &itemH, &box);
			GetDialogItemText(itemH, rate);
			xrate = atof(P2CStr(rate));
			// get Y coeffcient(DITL is 6)
			GetDialogItem(dlg, 6, &itemtype, &itemH, &box);
			GetDialogItemText(itemH, rate);
			yrate = atof(P2CStr(rate));
			if(xrate > DATA_NEAR_ZERO && xrate < DATA_TOO_LARGE){
				pl->xpd /= xrate;
			}
			if(yrate > DATA_NEAR_ZERO && yrate < DATA_TOO_LARGE){
				pl->ypd /= yrate;
			}
			PLSetScrlRange(pl);
			break;
		}
		if(item == 2)	break;		// Cancel
	}
	DisposeDialog(dlg);
	SetPort(cptr);
}



// Get Data index from given x-value
static short  PLGetDataIndex(PlotFormat *pl, double xval)
{
	short i, n;
	
	n = pl->n -1;
	
	for(i = 0 ; i < pl->n ; i++){
		if( ( (xval - *(pl->x + i)) >= 0 ) && ( (xval - *(pl->x + i + 1)) < 0 ))
			break;
	}
	return i;
}

static void  PLShowMarkVal(PlotFormat *pl)
{
	char valstr[50], *vptr;
	PenState pstate;
	
	GetPenState(&pstate);
	vptr = valstr;
	
	PenMode(patCopy);
	EraseRect(&(pl->markvalrect));
	ForeColor(blackColor);
	FrameRect(&(pl->markvalrect));
	
	MoveTo(pl->markvalrect.left +2, pl->markvalrect.bottom - 20 - 3);
	sprintf(valstr,"1:% 4.3e[% 4.4d] 2:%4.3e[% 4.4d]", 
				pl->markxval[0], pl->marknum[0],
				pl->markxval[1], pl->marknum[1] );
	DrawString(C2PStr(vptr));
	MoveTo(pl->markvalrect.left +2, pl->markvalrect.bottom -3);
	sprintf(valstr,"3:% 4.3e[% 4.4d] 4:%4.3e[% 4.4d]", 
				pl->markxval[2], pl->marknum[2],
				pl->markxval[3], pl->marknum[3] );
	DrawString(C2PStr(vptr));
	
	SetPenState(&pstate);
}

// draw vertical lines at marked position
// draw nth mark XOR mode(toggle)
// return x-coordinate value of current port
short  PLDrawMark1Line(PlotFormat *pl, int n)
{
	short xp;
	RgnHandle savergn;
	PenState pstate;
	PixPatHandle ppath;

	GrafPtr cptr;

	GetPenState(&pstate);
	GetPort(&cptr);
	SetPort(pl->w);
	
	savergn = NewRgn();
	GetClip(savergn);

	ppath = GetPixPat(PLOT_PPGREEN_ID);
	PenNormal();
	PenPixPat(ppath);
	PenMode(patXor);
		
	ClipRect(&(pl->plotrect));

	if(n>=0 && n < N_PLOTMARK && pl->marknum[n] != 0){
		xp = pl->plotrect.left + (short)((pl->markxval[n] - pl->xorg) / pl->xpd);
		MoveTo(xp, pl->plotrect.top);
		LineTo(xp, pl->plotrect.bottom);
		pl->markxcrd[n] = xp;
	}
	
	SetClip(savergn);
	DisposeRgn(savergn);
	DisposePixPat(ppath);
	SetPort(cptr);
	SetPenState(&pstate); 

	return xp;
}

void PLDrawMarkLines(PlotFormat *pl)
{
	int i;
	for(i = 0 ; i < N_PLOTMARK ; i++){
		PLDrawMark1Line(pl, i);		// write xor mode
	}
}

void PLHideMarkLines(PlotFormat *pl)
{
	short xp;
	short i;
	RgnHandle savergn;
	PenState pstate;
	PixPatHandle ppath;

	GrafPtr cptr;

	GetPenState(&pstate);
	GetPort(&cptr);
	SetPort(pl->w);
	
	savergn = NewRgn();
	GetClip(savergn);

	ppath = GetPixPat(PLOT_PPGREEN_ID);
	PenNormal();
	PenPixPat(ppath);
	PenMode(patXor);
	
	ClipRect(&(pl->plotrect));

	for(i = 0 ; i < N_PLOTMARK ; i++){
		if(pl->marknum[i] != 0){
			xp = pl->plotrect.left + (short)((pl->markxval[i] - pl->xorg) / pl->xpd);
			MoveTo(xp, pl->plotrect.top);
			LineTo(xp, pl->plotrect.bottom);
		}
	}
	
	SetClip(savergn);
	DisposeRgn(savergn);
	DisposePixPat(ppath);
	SetPort(cptr);
	SetPenState(&pstate); 

}

// return index of marker clicked 
// else return -1
short PLGetClickedMark(PlotFormat *pl, Point clickedpos)
{
	int i;
	
	for(i = 0 ; i < N_PLOTMARK ; i++){
		if( clickedpos.h >= pl->markxcrd[i] -1 && clickedpos.h <= pl->markxcrd[i] +1
			 && clickedpos.h != 0){
			return i;
		}
	}
	
	return -1;
}


void  PLActionHscrl(PlotFormat *pl, EventRecord ev)
{
	long part;
	short oldval, newval;
	short pagedot;
	double pageval;
	Point mouse;
	ControlHandle control;
	GrafPtr cptr;
	
	GetPort(&cptr);
	SetPort(pl->w);
	mouse = ev.where;
	GlobalToLocal(&mouse);
	part = FindControl(mouse, pl->w, &control);

	pagedot = pl->plotrect.right - pl->plotrect.left;
	pageval = (double)pagedot * pl->xpd;
	oldval = GetControlValue(pl->hscrl);
	switch(part){
		case kControlUpButtonPart:
			if((pl->xorg - pageval / (double)5) >= pl->xmin){
				pl->xorg -= pageval / (double)5;
				newval = (short)((pl->xorg - pl->xmin)/ pl->xpd);
			}
			else{
				pl->xorg = pl->xmin;
				newval = 0;
			}
			break;
		case kControlDownButtonPart:
			if((pl->xorg + pageval / (double)5)<= pl->xmax){
				pl->xorg += pageval / (double)5;
				newval = (short)((pl->xorg - pl->xmin) / pl->xpd);
			}
			else{
				pl->xorg = pl->xmax;
				newval = (short)((pl->xmax - pl->xmin)/ pl->xpd);
			}
			break;
		case kControlPageUpPart:
			if((pl->xorg - pageval) >= pl->xmin){
				pl->xorg -= pageval;
				newval = (short)((pl->xorg - pl->xmin)/ pl->xpd);
			}
			else{
				pl->xorg = pl->xmin;
				newval = 0;
			}
			break;
		case kControlPageDownPart:
			if((pl->xorg + pageval) <= pl->xmax){
				pl->xorg += pageval;
				newval = (short)((pl->xorg - pl->xmin)/ pl->xpd);
			}
			else{
				pl->xorg = pl->xmax;
				newval = (short)((pl->xmax - pl->xmin) / pl->xpd);
			}
			break;
		case kControlIndicatorPart:
			part = TrackControl(pl->hscrl, mouse, NULL);
			newval = GetControlValue(pl->hscrl);
			pl->xorg = pl->xmin + pl->xpd * (double)newval;
			break;
	}
	SetControlValue(pl->hscrl, newval);
	SetPort(cptr);
}


void  PLActionVscrl(PlotFormat *pl, EventRecord ev)
{
	long part;
	short oldval, newval;
	short pagedot;
	double pageval;
	Point mouse;
	ControlHandle control;
	GrafPtr cptr;
	
	GetPort(&cptr);
	SetPort(pl->w);
	mouse = ev.where;
	GlobalToLocal(&mouse);
	part = FindControl(mouse, pl->w, &control);

	pagedot = pl->plotrect.bottom - pl->plotrect.top;
	pageval = (double)pagedot * pl->ypd;
	oldval = GetControlValue(pl->vscrl);
	
	switch(part){
		case kControlUpButtonPart:
			if((pl->yorg + pageval / (double)5) <= pl->ymax){
				pl->yorg += pageval / (double)5;
				newval = (short)((pl->ymax - pl->yorg) / pl->ypd);
			}
			else{
				pl->yorg = pl->ymax;
				newval = 0;
			}
			break;
		case kControlDownButtonPart:
			if((pl->yorg - pageval / (double)5) >= pl->ymin){
				pl->yorg -= pageval / (double)5;
				newval = (short)((pl->ymax - pl->yorg) / pl->ypd);
			}
			else{
				pl->yorg = pl->ymin;
				newval = (short)((pl->ymax - pl->yorg)/ pl->ypd);
			}
			break;
		case kControlPageUpPart:
			if((pl->yorg + pageval) <= pl->ymax){
				pl->yorg += pageval;
				newval = (short)((pl->ymax - pl->yorg) / pl->ypd);
			}
			else{
				pl->yorg = pl->ymax;
				newval = 0;
			}
			break;
		case kControlPageDownPart:
			if((pl->yorg - pageval) >= pl->ymin){
				pl->yorg -= pageval;
				newval = (short)((pl->ymax - pl->yorg) / pl->ypd);
			}
			else{
				pl->yorg = pl->ymin;
				newval = (short)((pl->ymax - pl->yorg)/ pl->ypd);
			}
			break;
		case kControlIndicatorPart:
			part = TrackControl(pl->vscrl, mouse, NULL);
			newval = GetControlValue(pl->vscrl);
			pl->yorg = pl->ymax - pl->ypd * (double)newval;
			break;
	}
	SetControlValue(pl->vscrl, newval);
	SetPort(cptr);
}


// Action for ZoomBox
void  PLDoGrow(PlotFormat *pl, EventRecord ev)
{
	long growth;
	Rect GrowArea, sbrect;
	GrafPtr cptr;
	
	GetPort(&cptr);
	SetPort(pl->w);
	SetRect(&GrowArea, 60, 60, 570, 500);
	growth = GrowWindow(pl->w, ev.where, &GrowArea);
	if(growth != 0){
		SizeWindow(pl->w, LoWord(growth), HiWord(growth), true);
		InvalRect(&(pl->w->portRect));
		
		HideControl(pl->hscrl);
		HideControl(pl->vscrl);

		ClipRect(&(pl->w->portRect));
		
		PLSetDrawParms(pl);
		CalcVscrPos(pl->w, &sbrect);
		sbrect.top += TOPZONE;
		MoveControl(pl->vscrl, sbrect.left, sbrect.top);
		SizeControl(pl->vscrl, sbrect.right - sbrect.left, sbrect.bottom - sbrect.top);

		CalcHscrPos(pl->w, &sbrect);
		sbrect.left += LEFTZONE;
		MoveControl(pl->hscrl, sbrect.left, sbrect.top);
		SizeControl(pl->hscrl, sbrect.right - sbrect.left, sbrect.bottom-sbrect.top);
		
		ShowControl(pl->vscrl);
		ShowControl(pl->hscrl);
	}
	SetPort(cptr);
}


void  PLDoZoom(PlotFormat *pl, EventRecord ev)
{
	Point mouse;
	WindowPtr twin;
	short part;
	Rect sbrect;
	GrafPtr cptr;
	
	GetPort(&cptr);
	mouse = ev.where;
	part = FindWindow(ev.where, &twin);
	SetPort(pl->w);

	if(TrackBox(pl->w, mouse, part)){
		ZoomWindow(pl->w, part, false);
		InvalRect(&(pl->w->portRect));
		
		HideControl(pl->hscrl);
		HideControl(pl->vscrl);

		ClipRect(&(pl->w->portRect));

		PLSetDrawParms(pl);
		CalcVscrPos(pl->w, &sbrect);
		sbrect.top += TOPZONE;
		MoveControl(pl->vscrl, sbrect.left, sbrect.top);
		SizeControl(pl->vscrl, sbrect.right - sbrect.left, sbrect.bottom - sbrect.top);

		CalcHscrPos(pl->w, &sbrect);
		sbrect.left += LEFTZONE;
		MoveControl(pl->hscrl, sbrect.left, sbrect.top);
		SizeControl(pl->hscrl, sbrect.right - sbrect.left, sbrect.bottom-sbrect.top);
		
		ShowControl(pl->vscrl);
		ShowControl(pl->hscrl);
	}
	SetPort(cptr);
}



	
void  CalcVscrPos(WindowPtr win, Rect *r)
{
	Point p1, p2;
	
	SetPt(&p1, (win->portRect).right -15, (win->portRect).top-1);
	SetPt(&p2, (win->portRect).right+1, (win->portRect).bottom-14);
	Pt2Rect(p1, p2, r);
}

void  CalcHscrPos(WindowPtr win, Rect *r)
{
	Point p1, p2;
	
	SetPt(&p1, (win->portRect).left -1, (win->portRect).bottom-16);
	SetPt(&p2, (win->portRect).right-14, (win->portRect).bottom+1);
	Pt2Rect(p1, p2, r);
}

// r:initial Rect
void PLTrackMarquee(PlotFormat *pl, Rect *r, Rect boundary, short condition)
{
	Point mouse, cmouse;
	Rect nRect, cRect;
	PenState pstate;
	Pattern myPat;
	short dh, dv;
	
	GetPenState(&pstate);
	PenNormal();
	PenMode(patXor);

	GetIndPattern(&myPat, sysPatListID, 4);
	PenPat(&myPat);
	SetRect(&nRect, r->left, r->top, r->right, r->bottom);
	FrameRect(&nRect);	// write
	cRect = nRect;		// store current Rect
	GetMouse(&cmouse);	// store current position of pointer(local)
	while(StillDown()){
		GetMouse(&mouse);
		switch(condition){
			case MOVE_ONLY_HORIZ:
				dh = mouse.h - cmouse.h;
				if(boundary.left < r->left + dh && r->right + dh < boundary.right){
					SetRect(&nRect, r->left + dh, r->top, r->right + dh, r->bottom);
				}
				break;
			case MOVE_ONLY_VERT:
				dv = mouse.v - cmouse.v;
				if(boundary.top < r->top + dv && r->bottom + dv < boundary.bottom){
					SetRect(&nRect, r->left, r->top + dv, r->right, r->bottom + dv);
				}
				break;
			case MOVE_VH:
				dh = mouse.h - cmouse.h;
				dv = mouse.v - cmouse.v;
				if(boundary.left < r->left + dh && r->right + dh < boundary.right
				   && boundary.top < r->top + dv && r->bottom + dv < boundary.bottom){
					SetRect(&nRect, r->left + dh, r->top + dv, r->right + dh, r->bottom + dv);
				}
				break;
			case CORNER_GROW:
				SetRect(&nRect, r->left, r->top, mouse.h, mouse.v);
				SortRect(&nRect);
				break;
		}
		if(!CompareRect(&nRect, &cRect)){
			FrameRect(&cRect);	// erase
			FrameRect(&nRect);	// write
			cRect = nRect;		// store current Rect
			/* and show pointer position */
			pl->mpt = mouse;
			PLShowPointValues(pl);
		}
	}
	FrameRect(&nRect);
	SetPenState(&pstate);
	*r = nRect;

}



void PLMoveCursor(Point newpoint)
{
// low memory globals
#define MTemp		0x828
#define RawMouse	0x82C
#define CrsrNew		0x08CE

	*(Point *)RawMouse = newpoint;
	*(Point *)MTemp = newpoint;
	*(Ptr)CrsrNew = 0xFFFF;


#ifdef NewHashon
	CursorDevicePtr myMouse;
	
	myMouse = nil;
	do{
		CursorDeviceNextDevice(&myMouse);
	} while((myMouse != nil) && (myMouse->cntButtons != 1));
	
	CursorDeviceMoveTo(myMouse, (long)newpoint.h, (long)newpoint.v);
#endif
}


void PLGetMarkBound(PlotFormat *pl, short mindex, Rect *boundRect)
{
	short mindx_pd;
	double delta_x;
	
	delta_x = *(pl->x + 1) - *(pl->x);
	mindx_pd = ceil(delta_x / pl->xpd);
	if(mindx_pd < 2) mindx_pd = 2;	/* 2-dot or 1-point in the x value axis */
	
	
	if(mindex == 0){
		boundRect->left = pl->plotrect.left;
		boundRect->right = pl->plotrect.left 
		                  + (short)((pl->markxval[mindex+1] - pl->xorg) / pl->xpd);
		if(boundRect->right > pl->plotrect.right) boundRect->right = pl->plotrect.right;
		
	}
	else if(mindex == N_PLOTMARK-1){
		boundRect->left = pl->plotrect.left 
		                 + (short)((pl->markxval[mindex-1] - pl->xorg) / pl->xpd);
		if(boundRect->left < pl->plotrect.left) boundRect->left = pl->plotrect.left; 
		boundRect->right = pl->plotrect.right;
	}
	else{
		boundRect->left = pl->plotrect.left 
		                 + (short)((pl->markxval[mindex-1] - pl->xorg) / pl->xpd);
		if(boundRect->left < pl->plotrect.left) boundRect->left = pl->plotrect.left; 
		boundRect->right = pl->plotrect.left 
		                  + (short)((pl->markxval[mindex+1] - pl->xorg) / pl->xpd);
		if(boundRect->right > pl->plotrect.right) boundRect->right = pl->plotrect.right;
	}
	
	boundRect->left += mindx_pd;
	boundRect->right -= mindx_pd;
}

void PLResizeGraph(PlotFormat *pl, Rect *r)
{
	double xrate, yrate;
	short xsize, ysize;
	GrafPtr cptr;
	
	GetPort(&cptr);
	
	xsize = r->right - r->left;
	ysize = r->bottom - r->top;
	
	if(xsize != 0){
		xrate = (double)(pl->plotrect.right - pl->plotrect.left)/(double)xsize;
		if(xrate > DATA_NEAR_ZERO && xrate < DATA_TOO_LARGE){
			pl->xorg = pl->xorg + (r->left - pl->plotrect.left)*pl->xpd;	// first calc origine
			pl->xpd /= xrate;	// then rescale
		}
	}
	if(ysize != 0){
		yrate = (double)(pl->plotrect.bottom - pl->plotrect.top)/(double)ysize; 
		if(yrate > DATA_NEAR_ZERO && yrate < DATA_TOO_LARGE){
			pl->yorg = pl->yorg - (r->top - pl->plotrect.top)*pl->ypd; // first calc origine
			pl->ypd /= yrate;	// then rescale
		}
	}
	PLFullDraw(pl);
	// new scrol values
	PLSetScrlRange(pl);
	PLSetScrlVal(pl);

	SetPort(cptr);
}

void PLAutoScaleGraph(PlotFormat *pl)
{
	pl->xorg = pl->xmin;
	pl->yorg = pl->ymax;
	pl->xpd  = (pl->xmax - pl->xmin) / (double)(pl->w->portRect.right - LEFTZONE - 16);
	pl->ypd  = (pl->ymax - pl->ymin) / (double)(pl->w->portRect.bottom - TOPZONE - 16);

	PLSetScrlRange(pl);
	PLFullDraw(pl);
}

void SortRect(Rect * dragRect)
{
	short			tempAx;
	
	if(dragRect->bottom<dragRect->top)	{
		tempAx = dragRect->bottom;
		dragRect->bottom = dragRect->top;
		dragRect->top = tempAx;
	}
	if(dragRect->right<dragRect->left)	{
		tempAx = dragRect->left;
		dragRect->left = dragRect->right;
		dragRect->right = tempAx;
	}
}

Boolean CompareRect(Rect *r1, Rect *r2)
{
	if(r1->left == r2->left && r1->top == r2->top
		&& r1->right == r2->right && r1->bottom == r2->bottom){
		return true;
	}
	return false;
}


