// ****************
//  General Viewer
// ****************
long CALLBACK ViewerProc(hWnd, message, wParam, lParam)
HWND hWnd;                      /* window handle                 */
UINT message;                   /* type of message               */
WPARAM wParam;                  /* additional information        */
LPARAM lParam;                  /* additional information        */
{
    PAINTSTRUCT ps ;
		   HPEN Pen, oPen ;
 static  HBRUSH oBr ;
	        HDC hdc ;
	static RECT rc, Fr, D ;
		   char buff[50] = "This is a test string" ;

	static lftmarg =  0 ;
	static rytmarg =  0 ;
	static topmarg =  0 ;
	static botmarg =  0 ;
	static unit, a, b ;
	static p, q, ht, wd, i, m ;
	static xp1, yp1, xp2 , yp2 ;
	static xu1, yu1, xu2, yu2 ;
	static xc, yc, xr, yr, xm, ym, xS, yS ;
	static xf, yf, XT, YT ;
	static len, u, v ;
	static UINT k ;

	static double  cs, sn, amp, fr, U, radius ;


	switch (message)
	{
      case WM_NCHITTEST: // works for a mouse event anywhere in this window

	// If the mouse has moved window, tell the abandoned window so that
	// it can turn off any tip that it might have showing, then make
	// this window officially current. Else preserve status quo.

	if (hWnd != CurrentWindow)
	{
		SendMessage(CurrentWindow,WM_COMMAND,WM_MOUSEGONE,0L) ;
		CurrentWindow = hWnd ;
	}

	// The hit test must be passed
	// to the default window proc.
			return (DefWindowProc(hWnd, message, wParam, lParam)) ;

	  case WM_SIZE:
	  case WM_MOVE:
		  ivrc(hWnd, NULL, TRUE) ;
		  break ;

	  case WM_CREATE:
		  icAries = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ARIES)) ;
		  break ;

	  //case WM_DESTROY:
		  //break ;

	  case WM_PAINT:
		   hdc = BeginPaint(hWnd, &ps) ;
		  oBr  = SelectObject(hdc, GetStockObject(BLACK_BRUSH)) ;
		  unit = 200 ;
		    fr = FieldRadius ;

		  GetClientRect(hWnd, &rc) ;
		  wd = (rc.right - rc.left) - (lftmarg + rytmarg) ;
		  ht = (rc.bottom - rc.top) - (botmarg + topmarg) ;

		  SetRect(						  // Frame
			      &Fr,
			      rc.left + lftmarg - 1,
				  rc.top  + topmarg - 1,
				  rc.left + lftmarg + wd + 1,
				  rc.top  + topmarg + ht + 1
	             ) ;

	if (wantBackdrop)
		  Rectangle(
			        hdc,
			        Fr.left,
					Fr.top,
					Fr.right,
					Fr.bottom
				   ) ;

		  SetRect(
			      &D,					  // Plotting area
			      rc.left + lftmarg,
				  rc.top  + topmarg,
				  rc.left + lftmarg + wd,
				  rc.top  + topmarg + ht
	             ) ;

				// find centre

				 xc = (D.right + D.left) / 2 ;	
				 yc = (D.top + D.bottom) / 2 ;

				 XT = xc / 2 ;
				 YT = 3 * (D.top + D.bottom) / 4 ;

				// make sure Frame Radius fits in smaller dimension

				if ((D.right - D.left) < (D.bottom - D.top)) // horz < vert
				{
				while (unit < (D.right  - xc)) unit++ ; // adjust to horizontal
				while (unit > (D.right  - xc)) unit-- ;
				}
				else	// horz >= vert
				{
				while (unit < (D.bottom - yc)) unit++ ; // adjust to vertical
				while (unit > (D.bottom - yc)) unit-- ;
				}

				U = (double)unit ;

				// indicate centre & 1st of Aries
					oPen = SelectObject(hdc, dkgrayPen) ;
				 MoveToEx(hdc,  D.left + 40,  yc, NULL ) ;
				   LineTo(hdc, D.right - 40,  yc ) ;
				 //MoveToEx(hdc, xc,    D.top + 40, NULL ) ;
				   //LineTo(hdc, xc, D.bottom - 40 ) ;
						SelectObject(hdc, oPen) ;
				 DrawIcon( hdc, D.right - 35, yc - 5 , icAries ) ;


//****************************************
//         Show Selected Bodies
//****************************************
     if (wantBodies)
			for ( p = EAR ; p <= SUN ; p++)
			{
				HPEN oP ;
				int x, y, size ;
				static ox, oy, osize, done ;

				if (p == PLU || !BodyList[p] || !ViewBody[p]) continue ;
				if (VSy.z_on_Sun[p] < 0.0)
				{ Pen = goldPen ;   size = 3 ; } // South of Ecliptic, small, gold
				else
				{ Pen = yellowPen ; size = 4 ; } // North of Ecliptic, big, yellow
				oP = SelectObject(hdc, Pen) ;

				x = xc + (int)(U * ajx(VSy.x_on_Sun[p], VSy) / fr) ;
				y = yc - (int)(U * ajy(VSy.y_on_Sun[p], VSy) / fr) ;
				if (done)
				Ellipse(hdc, ox - osize, oy - osize, ox + osize, oy + osize) ;

				Ellipse(hdc, x - size, y - size, x + size, y + size) ;
				done = 1 ;
				ox = x ; oy = y ; osize = size ;
				SelectObject(hdc, oP) ;
			}

// **************************
//  Position of Mean Body
// **************************
			{
				double x, y ;
			xr = xc + (int)(U * ajx(x = VSy.x_on_Sun[MBD], VSy) / fr ) ; 
			yr = yc - (int)(U * ajy(y = VSy.y_on_Sun[MBD], VSy) / fr ) ;
		radius = sqrt(x*x + y*y) ;	// heliocentric radius
			}

// **************************
//  Position of Mass Centre
// **************************

			xm = xc + (int)(U * ajx(VSy.x_on_Sun[MAS], VSy) / fr ) ; 
			ym = yc - (int)(U * ajy(VSy.y_on_Sun[MAS], VSy) / fr ) ;

// **************************
//  Position of Sun
// **************************

			xS = xc + (int)(U * ajx(0.0, VSy) / fr ) ; 
			yS = yc - (int)(U * ajy(0.0, VSy) / fr ) ;

//****************************************
//         Link Selected Bodies
//****************************************

		if (wantInterbodyLines)	// link each included to all others included
				{
					   HPEN oP ;
						int x1, y1, x2, y2 ;
					 static ox1, oy1, ox2, oy2, done ;
					oP = SelectObject(hdc, dkgrayPen) ;
					for (p = EAR ; p < SUN ; p++)
					{
				        if (p == PLU || !BodyList[p] || !ViewBody[p]) continue ;
						for (q = p+1 ; q <= SUN ; q++)
						{
							if (q == PLU || !BodyList[q] || !ViewBody[q]) continue ;

							x1 = xc + (int)(U * ajx(VSy.x_on_Sun[p], VSy) / fr) ;
							y1 = yc - (int)(U * ajy(VSy.y_on_Sun[p], VSy) / fr) ;
							x2 = xc + (int)(U * ajx(VSy.x_on_Sun[q], VSy) / fr) ;
							y2 = yc - (int)(U * ajy(VSy.y_on_Sun[q], VSy) / fr) ;

						if (done)
						{
							MoveToEx(hdc, ox1, oy1, NULL) ;
							  LineTo(hdc, ox2, oy2) ;
						}
							MoveToEx(hdc, x1, y1, NULL) ;
							  LineTo(hdc, x2, y2) ;
							  done = 1 ;
							  ox1 = x1 ; oy1 = y1 ;
							  ox2 = x2 ; oy2 = y2 ;
						}
					}
					SelectObject(hdc, oP) ;
				}

		if (wantMeanbodyLines)	// link Mean Body to all included
				{
					   HPEN oP ;
						int x1, y1 ;
					oP = SelectObject(hdc, ltredPen) ;
					for (p = EAR ; p <= SUN ; p++)
					{
				        if (p == PLU || !BodyList[p] || !ViewBody[p]) continue ;

							x1 = xc + (int)(U * ajx(VSy.x_on_Sun[p], VSy) / fr) ;
							y1 = yc - (int)(U * ajy(VSy.y_on_Sun[p], VSy) / fr) ;
							MoveToEx(hdc, xr, yr, NULL) ;
							  LineTo(hdc, x1, y1) ;
					}
							SelectObject(hdc, oP) ;
				}

		if (wantCoMLines)		// link Centre of Mass to all included
				{
					   HPEN oP ;
						int x1, y1 ;
					oP = SelectObject(hdc, ltbluePen) ;
					for (p = EAR ; p <= SUN ; p++)
					{
				        if (p == PLU || !BodyList[p] || !ViewBody[p]) continue ;

							x1 = xc + (int)(U * ajx(VSy.x_on_Sun[p], VSy) / fr) ;
							y1 = yc - (int)(U * ajy(VSy.y_on_Sun[p], VSy) / fr) ;
							MoveToEx(hdc, xm, ym, NULL) ;
							  LineTo(hdc, x1, y1) ;
					}
							SelectObject(hdc, oP) ;
				}

// **************************
// Show Position of Mean Body
// **************************

			if (wantMB)
			{
				 int size ;
				 Pen = (VSy.z_on_Sun[MBD] < 0.0) ? plbluePen : whitePen ;
				size = (VSy.z_on_Sun[MBD] < 0.0) ? 3 : 4 ;
				SelectObject(hdc, Pen) ;
		        Ellipse(hdc,  xr -  size,  yr -  size,  xr +  size,  yr +  size) ; // new circle on mean body
				DrawCross(hWnd, 0, xr,  yr, size, Pen) ;
			}

// ******************************
//  Show Position of Mass Centre
// ******************************

			if (wantMassCentre)
			{
				int size ;
				 Pen = (VSy.z_on_Sun[MAS] < 0.0) ? bluePen : ltbluePen ;
				size = (VSy.z_on_Sun[MAS] < 0.0) ? 3 : 4 ;
				SelectObject(hdc, Pen) ;
			    Ellipse(hdc, xm - size, ym - size, xm + size, ym + size) ; // circle on mass centre
				DrawCross(hWnd, 0, xm,  ym, size, Pen) ;
			}


// ************************************
//	Turning Points of Inter-Body Lines
// ************************************
			if (wantInterbodyTPs)
			{
				int P1, P2 ;

				for (P1 = EAR ; P1 <= SUN ; P1++)
				{
					if (P1 == PLU || !ShowInterBodyTP[P1]) continue ;

					for (P2 = EAR ; P2 <= SUN ; P2++)
					{
						if (P2 == PLU || P1 == P2 || !ShowInterBodyTP[P2]) continue ;

						u = xc + (int)(U * ajx(VSy.xT[P1][P2], VSy) / fr) ; 
						v = yc - (int)(U * ajy(VSy.yT[P1][P2], VSy) / fr) ;

						DrawCross(hWnd, 0, u, v, 1, whitePen) ;
					}
				}
			}

// ******************************************************
//						'Systemic Primary'
// ******************************************************
	if (wantSystemicPrimary)
			{
						u = xc + (int)(U * ajx(VSy.SPMx, VSy) / fr) ; 
						v = yc - (int)(U * ajy(VSy.SPMy, VSy) / fr) ;

						DrawCircle(hWnd, 0, u, v, 5, yellowPen) ;

						 DrawCross(hWnd, 0, u, v, 7, yellowPen) ;
			}

// ******************************************************
// Component in ecliptic of velocity vector of mean body
// ******************************************************

	//if (wantMBvelVect || wantMBvelEndPt) 
	{
		Pen = (VSy.mVectLat > pi) ? ltbluePen : whitePen ;

				SelectObject(hdc, Pen) ;

			   cs = cos(VSy.mVectDir) ;	// velocity vector
			   sn = sin(VSy.mVectDir) ;
			  amp = U * VSy.mVectSum / fr ;
			    u = xr + (int)(amp * cs) ;
			    v = yr - (int)(amp * sn) ;

		if (wantMBvelVect)
		{
		   MoveToEx(hdc, xr, yr, NULL) ;
		     LineTo(hdc, u, v) ;
		}

			 if (wantMBvelEndPt)		// end point of velocity vector
				Ellipse(hdc, u - 2, v - 2, u + 2, v + 2) ;
	}

// **********************************************************
// Component in ecliptic of acceleration vector of mean body
// **********************************************************

	if (wantMBaccVect || wantMBaccEndPt)
	{
		HPEN oP ;

			Pen = (VSy.maVectLat > pi) ? ltgreenPen : dkgreenPen ;
			oP = SelectObject(hdc, Pen) ;

			   cs = cos(VSy.maVectDir) ;
			   sn = sin(VSy.maVectDir) ;
			  amp = U * VSy.maVectSum / (10.0 * fr) ;
				u = xr + (int)(amp * cs) ;
				v = yr - (int)(amp * sn) ;

		if (wantMBaccVect)
		{
		   MoveToEx(hdc, xr, yr, NULL) ; // acceleration vector
		     LineTo(hdc, u, v) ;
		}

		if (wantMBaccEndPt)				 // end point of vector
		   Ellipse(hdc, u - 3, v - 3, u + 3, v + 3) ;
		SelectObject(hdc, oP) ;
	}

// **********************************************************
// Component in ecliptic of velocity vector of centre of mass
// **********************************************************
	{
		HPEN oP ;
		double a, b, g, h ;
		int u1, v1, u2, v2 ;

		Pen = (VSy.mMVectLat > pi) ? ltbluePen : whitePen ;

			   cs = cos(VSy.mMVectDir) ;	// velocity vector
			   sn = sin(VSy.mMVectDir) ;
			  amp = U * VSy.mMVectSum / fr ;
			    u = xm + (int)(a = amp * cs) ;
			    v = ym - (int)(b = amp * sn) ;

		  if (wantExtVelVect)
		  {
				oP = SelectObject(hdc, grayPen) ;
				 g = 20.0 * a ; 
				 h = 20.0 * b ;
				u1 = xm - (int)g ;
				v1 = ym + (int)h ;
				u2 = xm + (int)g ;
				v2 = ym - (int)h ;

			  MoveToEx(hdc, u1, v1, NULL) ; // extended acceleration vector
				LineTo(hdc, u2, v2) ;
				SelectObject(hdc, oP) ;
		  }

		if (wantCoMvelVect)
		{
			oP = SelectObject(hdc, Pen) ;
		   MoveToEx(hdc, xm, ym, NULL) ;
		     LineTo(hdc, u, v) ;
			SelectObject(hdc, oP) ;

		}
			 if (wantCoMvelEndPt)		// end point of velocity vector
			 {
				oP = SelectObject(hdc, Pen) ;
				Ellipse(hdc, u - 3, v - 3, u + 3, v + 3) ;
				SelectObject(hdc, oP) ;
			 }
	}

//__________________________
//
// Iteration
//__________________________

	for ( k = 0 ; k < ViewRate ; k++)
{

// **********************************************************
// Component in ecliptic of acceleration vector of Mass Centre
// **********************************************************
	{
		HPEN oP ;
		double a, b, g, h ;
		int u1, v1, u2, v2 ;

			Pen = (VSy.mMaVectLat > pi) ? ltgreenPen : dkgreenPen ;

			   cs = cos(VSy.mMaVectDir) ;
			   sn = sin(VSy.mMaVectDir) ;
			  amp = U * VSy.mMaVectSum / fr ;
				u = xm + (int)(a = amp * cs) ;
				v = ym - (int)(b = amp * sn) ;

		  if (wantExtAccVect)
		  {
				oP = SelectObject(hdc, whitePen) ;
				 g = 20.0 * a ; 
				 h = 20.0 * b ;

				u1 = xm - (int)g ;
				v1 = ym + (int)h ;
				u2 = xm + (int)g ;
				v2 = ym - (int)h ;

			  MoveToEx(hdc, u1, v1, NULL) ; // extended acceleration vector
				LineTo(hdc, u2, v2) ;
				SelectObject(hdc, oP) ;
		  }

		if (wantCoMaccVect)
		{
			oP = SelectObject(hdc, Pen) ;
		   MoveToEx(hdc, xm, ym, NULL) ;	// acceleration vector in CoM
		     LineTo(hdc, u, v) ;
			SelectObject(hdc, oP) ;
		}

		if (wantCoMaccEndPt)				// end point of vector
		{
			oP = SelectObject(hdc, Pen) ;
		   Ellipse(hdc, u - 2, v - 2, u + 2, v + 2) ;
			SelectObject(hdc, oP) ;
		}

		  if (wantExtAccVectSun)
		  {
				oP = SelectObject(hdc, whitePen) ;
				 g = 20.0 * a ; 
				 h = 20.0 * b ;
				u1 = xS - (int)g ;
				v1 = yS + (int)h ;
				u2 = xS + (int)g ;
				v2 = yS - (int)h ;

			  MoveToEx(hdc, u1, v1, NULL) ; // extended acceleration vector
				LineTo(hdc, u2, v2) ;
				SelectObject(hdc, oP) ;
		  }

	if (wantCoMaccVectinSun)				// acceleration vector in Sun
		{
			oP = SelectObject(hdc, Pen) ;
			 u = xS - (int)(a = amp * cs) ;	// remember sign swap
			 v = yS + (int)(b = amp * sn) ;
		   MoveToEx(hdc, xS, yS, NULL) ;
		     LineTo(hdc, u, v) ;
			SelectObject(hdc, oP) ;

		}
	}

	if (wantGeocDirofMB ||wantGeocDirofMass )
	{
			xu1 = xc + (int)(U * ajx(VSy.x_on_Sun[EAR], VSy) / fr ) ;
			yu1 = yc - (int)(U * ajy(VSy.y_on_Sun[EAR], VSy) / fr ) ;

// *********************************
// Direction from Earth of mean body
// *********************************

	if (wantGeocDirofMB)
	{
		HPEN oP ;

				oP = SelectObject(hdc, dkgreenPen) ;
		   MoveToEx(hdc, xu1, yu1, NULL) ;
		     LineTo(hdc, xr, yr) ;
				oP = SelectObject(hdc, oP) ;
	}

// ************************************
// Direction from Earth of mass centre
// ************************************

	if (wantGeocDirofMass)
	{
		HPEN oP ;
				oP = SelectObject(hdc, greenPen) ;
		   MoveToEx(hdc, xu1, yu1, NULL) ;
		     LineTo(hdc, xm, ym) ;
				oP = SelectObject(hdc, oP) ;
	}
	}


if (wantHeliocDirofMB || wantHeliocDirofMass)
	{
			xu1 = xc + (int)(U *  -VSy.x_on_Sun[ViewCentre] / fr ) ;
			yu1 = yc - (int)(U *  -VSy.y_on_Sun[ViewCentre] / fr ) ;

// *********************************
// Direction from Sun of mean body
// *********************************

	if (wantHeliocDirofMB)
	{
		HPEN oP ;
		double a, b, c, m, h1, g1, h2, g2, am, sign ;
		   int u1, v1, u2, v2 ;

		if (wantExtSunToMB)	// Extend the radius
		   {
				a = (double)(xr - xu1) ; b = (double)(yr - yu1) ;
			 sign = (b < 0.0) ? -1.0 : 1.0 ; 
				m = (a == 0.0)? sign * 1.0e20 : b / a ; 	// slope (avoiding division by zero). 
				c = yr - m * xr ;							// intercept
				am = U * radius / fr ;						// extent
				h1 = (double)xu1 - 2.0 * am ; g1 = m * h1 + c ;
				h2 = (double)xu1 + 2.0 * am ; g2 = m * h2 + c ;
				u1 = (int)h1 ;	v1 = (int)g1 ;
				u2 = (int)h2 ;	v2 = (int)g2 ;

		oP = SelectObject(hdc, ltbluePen) ;
		   MoveToEx(hdc, u1, v1, NULL) ;
		     LineTo(hdc, u2, v2) ;
			 SelectObject(hdc, oP) ;
		   }
		else
		   {
		oP = SelectObject(hdc, ltbluePen) ;
		   MoveToEx(hdc, xu1, yu1, NULL) ;
		     LineTo(hdc, xr,  yr) ;
			 SelectObject(hdc, oP) ;
		   }

	}

// *********************************
// Direction from Sun of mass centre
// *********************************

	if (wantHeliocDirofMass)
	{
		HPEN oP ;

		oP = SelectObject(hdc, bluePen) ;
		   MoveToEx(hdc, xu1, yu1, NULL) ;
		     LineTo(hdc, xm, ym) ;
				SelectObject(hdc, oP) ;
	}
	}
/*****
// ****************************
// Mass bisectoid on Mean Body 
// ****************************
	if (wantSysDironMBbyMass)
	{
		  HPEN oP ;
		double h ;

				oP = SelectObject(hdc, purplePen) ;
		    cs = cos(VSy.bMSysDir[MBD]) ; 
			sn = sin(VSy.bMSysDir[MBD]) ;
			 h = 10.0 * fr ;

		   xp1 = xr - (a = (int)(U * h * cs / fr)) ; 
		   yp1 = yr + (b = (int)(U * h * sn / fr)) ;

		   xp2 = xr + a ;
		   yp2 = yr - b ;

		   MoveToEx(hdc, xp1, yp1, NULL) ; // systemic direction on mean body by mass
		     LineTo(hdc, xp2, yp2) ;
				oP = SelectObject(hdc, oP) ;
	}
	****/

				}  // end of iteration

          SelectObject(hdc, oPen) ;
		  SelectObject(hdc, oBr ) ;
		  if (!viewcount) viewcount++ ;

		   EndPaint(hWnd, &ps) ;
		   break ;

	  case WM_COMMAND:
		  {
		  switch(LOWORD(wParam))
		  {
		   case WM_MOUSEGONE:
			   // The rodent has left the window!
			   // If there is a tip showing, get rid of it.
		       if (CurrentTip != NULL)
			   RemoveTip() ;
		       return 0L ;

			case SETVIEWFRAME:
				break ;

			case WM_DRAWSTUFF:
				break ;

		    default: break ;
		  } // end switch(LOWORD(wParam))
		  }
		  break ; // end WM_COMMAND

      default:  /* for switch(message) - Passes it on if unprocessed */
          return (DefWindowProc(hWnd, message, wParam, lParam));
    }
    return ((long)NULL);
}
