// ObjectWindows - (C) Copyright 1992 by Borland International

/* MITO.CPP  Mitochondrial statistics simulation, derived from STEPS4.CPP */

#include <owl.h>
#include <stdlib.h>
#include <windows.h>
#include <stdio.h>
#include <inputdia.h>
#include <time.h>


class TMyApp : public TApplication
{
public:
  TMyApp(LPSTR AName, HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
    : TApplication(AName, hInstance, hPrevInstance, lpCmdLine, nCmdShow) {};
  virtual void InitMainWindow();
};

_CLASSDEF(TMyWindow)
class TMyWindow : public TWindow
{
public:
  HDC DragDC,PixelDC;
  BOOL ButtonDown;
  int Nsteps;   	// number of splits:  2^Nsteps = width of image
  long value_sum;

  TMyWindow(PTWindowsObject AParent, LPSTR ATitle);
  virtual BOOL CanClose();
  virtual void WMLButtonDown(RTMessage Msg)
    = [WM_FIRST + WM_LBUTTONDOWN];
  virtual void WMLButtonUp(RTMessage Msg)
    = [WM_FIRST + WM_LBUTTONUP];
  virtual void WMMouseMove(RTMessage Msg)
    = [WM_FIRST + WM_MOUSEMOVE];
  virtual void WMRButtonDown(RTMessage Msg)
	= [WM_FIRST + WM_RBUTTONDOWN];

  void TMyWindow::SplitPixel(unsigned char value, int xloc, int yloc, int level, int nlevels);
  void MakeImage();
};

TMyWindow::TMyWindow(PTWindowsObject AParent, LPSTR ATitle)
  : TWindow(AParent, ATitle)
{
  ButtonDown = FALSE;
  Nsteps = 6;
  value_sum = 0;
}

BOOL TMyWindow::CanClose()
{
  return MessageBox(HWindow, "Do you want to quit?",
    "Close Window", MB_YESNO | MB_ICONQUESTION) == IDYES;
}

void TMyWindow::WMLButtonDown(RTMessage Msg)
{
  InvalidateRect(HWindow, NULL, TRUE);
  if ( !ButtonDown )
  {
    ButtonDown = TRUE;
    SetCapture(HWindow);
    DragDC = GetDC(HWindow);
    MoveTo(DragDC, Msg.LP.Lo, Msg.LP.Hi);
  }
}

void TMyWindow::WMMouseMove(RTMessage Msg)
{
  if ( ButtonDown )
    LineTo(DragDC, Msg.LP.Lo, Msg.LP.Hi);
}

void TMyWindow::WMLButtonUp(RTMessage)
{
  if ( ButtonDown )
  {
    ButtonDown = FALSE;
    ReleaseCapture();
    ReleaseDC(HWindow, DragDC);
  }
}

void TMyWindow::WMRButtonDown(RTMessage)
{
  char InputText[6], OutputText[100];

  sprintf(InputText, "%d", Nsteps);
  sprintf(OutputText, "Avg = %d; Divisions:", value_sum / (1<<(Nsteps*2)));
  if ( GetApplication()->ExecDialog(new TInputDialog(this, "Number of Steps",
    OutputText, InputText, sizeof InputText)) == IDOK )
  {
      Nsteps = atoi(InputText);
      if ( Nsteps > 10 )
        Nsteps = 10;
  }
  value_sum = 0;
  MakeImage();
}

#define NUMENTRIES 64

void TMyWindow::MakeImage()
{
	int i, j, cColors=NUMENTRIES, c_inc, red, green, blue;
	unsigned char value;
	HPALETTE hpal, oldpal;
	PALETTEENTRY ape[NUMENTRIES];
	LOGPALETTE *plgpl;
	char tempstr[60];

    /* set up color palette for grayscale */
	plgpl = (LOGPALETTE*) LocalAlloc(LPTR,
    	sizeof(LOGPALETTE) + cColors * sizeof(PALETTEENTRY));

	plgpl->palNumEntries = cColors;
	plgpl->palVersion = 0x300;
    c_inc = (int) 256/cColors;

	for (i = 0, red = 0, green = 0, blue = 0; i < cColors;
		i++, red += c_inc, green += c_inc, blue += c_inc)
	{
   	 ape[i].peRed =
        plgpl->palPalEntry[i].peRed = LOBYTE(red);
   	 ape[i].peGreen =
        plgpl->palPalEntry[i].peGreen = LOBYTE(green);
   	 ape[i].peBlue =
        plgpl->palPalEntry[i].peBlue = LOBYTE(blue);
   	 ape[i].peFlags =
        plgpl->palPalEntry[i].peFlags = PC_RESERVED;
	}
	hpal = CreatePalette(plgpl);
	LocalFree((HLOCAL) plgpl);
    PixelDC =GetDC(HWindow);
	oldpal = SelectPalette(PixelDC, hpal, FALSE);
	sprintf(tempstr, "result = %d", RealizePalette(PixelDC));
	/* MessageBox(HWindow, tempstr,	"Realize Palette", MB_OK); */

    /* mitochondrial field */
	SplitPixel((unsigned char) 127, 0, 0, 0, Nsteps);

    /* show iid random field for comparison */
	for (i=0 ; i<(1<<Nsteps) ; i++)
		for (j=(1<<Nsteps) ; j<(2<<Nsteps) ; j++)
		{
			value = random(255);
			SetPixel(PixelDC, j, i, PALETTERGB(value, value, value));
		}

    SelectPalette(PixelDC, oldpal, FALSE);   // reset original palette
	ReleaseDC(HWindow, PixelDC);
	DeleteObject(hpal);
}

#define RANGE 32
#define MIDRANGE RANGE/2

void TMyWindow::SplitPixel(unsigned char value, int xloc, int yloc, int level, int nlevels)
{
	unsigned char v[2][2];
	int val_lr[2], i, j, temp, offset;

	if (level == nlevels)
	{
		SetPixel(PixelDC, xloc, yloc, PALETTERGB(value, value, value));
        value_sum += (int) value;
		return;
	}
	offset = random(RANGE)- MIDRANGE;
	if (offset > 255-value) offset = 255-value;
	if (offset > value) offset = value;
	if (-offset > value) offset = -value;
    if (-offset > 255-value) offset = -255+value;
	val_lr[0] = (int) value + offset;
    val_lr[1] = (int) value - offset;

	for (i=0 ; i<2 ; i++)
	{
		offset = random(RANGE)- MIDRANGE;
		if (offset > 255-val_lr[i]) offset = 255-val_lr[i];
		if (offset > val_lr[i]) offset = val_lr[i];
		if (-offset > val_lr[i]) offset = -val_lr[i];
		if (-offset > 255-val_lr[i]) offset = -255+val_lr[i];
		v[i][0] = (int) val_lr[i] + offset;
    	v[i][1] = (int) val_lr[i] - offset;

		for (j=0 ; j<2 ; j++)
		{
			SplitPixel(v[i][j], (xloc<<1) + i, (yloc<<1) + j, level+1, nlevels);
		}
    }
}

void TMyApp::InitMainWindow()
{
	time_t t;

    srand((unsigned) time(&t));
	MainWindow = new TMyWindow(NULL, Name);
}

int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  LPSTR lpCmdLine, int nCmdShow)
{
  TMyApp MyApp("Sample ObjectWindows Program", hInstance, hPrevInstance,
               lpCmdLine, nCmdShow);
  MyApp.Run();
  return MyApp.Status;
}
