#include <math.h>
#include <intuition/intuitionbase.h>
#include <stdio.h>
#include <exec/libraries.h>
#include <dos/dos.h>
#ifndef AZTEC
#include <stdlib.h>
#endif

char *dummy="$VER: Julia version 4 (22.06.1996)";

struct Library *IconBase=0L;
struct IntuitionBase *IntuitionBase=0L;
struct GfxBase *GfxBase=0L;
struct Library *CxBase=0L;

#define rp CustWindow->RPort
#define ip InfoWindow->RPort

struct NewWindow BlankWindow=
{
	50,50,200,100,1,2,
	MOUSEMOVE | MOUSEBUTTONS | CLOSEWINDOW | NEWSIZE,
	REPORTMOUSE | RMBTRAP | WINDOWSIZING | WINDOWCLOSE | GIMMEZEROZERO | SMART_REFRESH | WINDOWDEPTH | ACTIVATE | WINDOWDRAG,
	0,0,0,0,0,0,0,0,0,
	PUBLICSCREEN
};

struct NewWindow NewInfoWindow=
{
	50,50,100,20,1,2,
	0,
	SMART_REFRESH | BORDERLESS,
	0,0,0,0,0,0,0,0,0,
	PUBLICSCREEN
};

struct Window *CustWindow, *InfoWindow;

main(int argc, char **argv)
{
	UBYTE **ttypes;
	double is,di,rs,dr,iinc,rinc,o_is,o_di,o_rs,o_dr;
	USHORT i,j,n,colors;
	USHORT x,y,xsize,ysize;
	double re2,re,im,restart,imstart;
	char name[256];
	int paint=1;
	double memi,memr;
	short tmp,startx,starty,xneu,yneu;
	double dx,dy;
	struct Screen *PubScreen;
	struct IntuiMessage *message;
	struct IntuiMessage *GetMsg();
	ULONG color;
	double degree=2.0;
	double r,phi,tmp2,icon,rcon;
	int iter=16,iloop;
	int tmpw,tmph,pen;
	int class,code,loop=0;
	struct ColorMap *cm;
	int mandel=1;

	if ((IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",39))==NULL) exit(1);
	if ((GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0))==NULL) exit(1);

/*	get Number of colors and screensize	*/

	GetDefaultPubScreen(name);
	while (!(PubScreen=(struct Screen *)LockPubScreen(name)));

	colors=1<<(PubScreen->BitMap.Depth);

	xsize=PubScreen->Width;
	ysize=PubScreen->Height;

	BlankWindow.MinWidth=80;
	BlankWindow.MinHeight=30;
	BlankWindow.MaxWidth=xsize;
	BlankWindow.MaxHeight=ysize;
	BlankWindow.Screen=PubScreen;

	UnlockPubScreen(0L,PubScreen);

/*	Get the tooltypes if we have OS2.04	*/

	if (IconBase=(struct Library *)OpenLibrary("icon.library",37L))
	{
		if ((ttypes=ArgArrayInit(argc,argv)))
		{
			BlankWindow.LeftEdge=ArgInt(ttypes,"XPOS",50);
			BlankWindow.TopEdge=ArgInt(ttypes,"YPOS",50);
			BlankWindow.Width=ArgInt(ttypes,"XSIZE",200);
			BlankWindow.Height=ArgInt(ttypes,"YSIZE",100);
			degree=(double)ArgInt(ttypes,"DEGREE",2);
			iter=ArgInt(ttypes,"ITER",256);
			CloseLibrary(IconBase);
		}
	}

	if ((CustWindow=(struct Window *)OpenWindow(&BlankWindow))==NULL)
	{
		printf("cant open window !\n",name);
		CloseLibrary(IntuitionBase);
		CloseLibrary(GfxBase);
		exit(10);
	}

	if (iter>colors) iloop=iter;
	else iloop=colors;

/*	Preferences	*/

	is=-3.0;		/*	Im-range	*/
	di=6.0;

	rs=-3.0;		/*	Re-range	*/
	dr=6.0;

	while (1)
	{
pnt:		tmpw=CustWindow->GZZWidth;
		tmph=CustWindow->GZZHeight;

		rinc=dr/(double)tmpw;
		iinc=di/(double)tmph;

		if (!paint) goto next;

		SetWindowTitles(CustWindow,"painting...",-1);

		memi=is;
		memr=rs;

		for (y=0; y<CustWindow->GZZHeight; y++)	/*	row	*/
		{
			for (x=0; x<CustWindow->GZZWidth; x++)
			{
				if (tmpw!=CustWindow->GZZWidth || tmph!=CustWindow->GZZHeight)
				{
					rs=memr;
					is=memi;
					goto pnt;
				}

				re=restart=(rs+=rinc);
				im=imstart=is;

				pen=1;
				if (mandel)
				{
					icon=is;
					rcon=rs;
				}
				for (n=0; n<iloop-1; n++)	/*	main iteration	*/
				{
					if (degree==2)
					{
						re2=re*re-im*im+rcon;
						im=2*re*im+icon;
						re=re2;
					}
					else
					{
						r=sqrt(re*re+im*im);
						phi=acos(re/r);
						if (im<0.0) phi=6.28318530718-phi;
						tmp2=pow(r,degree);
						re=rcon+tmp2*cos(phi*degree);
						im=icon+tmp2*sin(phi*degree);
					}

					if ((re-restart)*(re-restart)+(im-imstart)*(im-imstart)>100.0)
					{
						if ((pen=1+n%(colors-1))==1) pen=0;
						break;
					}
				}
				SetAPen(rp,pen);
				WritePixel(rp,x,y);
			}
			rs=memr;
			is+=iinc;
		}
		is=memi;

		if (mandel) SetWindowTitles(CustWindow,"Mandel",-1);
		else SetWindowTitles(CustWindow,"Julia",-1);

next:		Wait(1L<<CustWindow->UserPort->mp_SigBit);

		while (message=GetMsg(CustWindow->UserPort))
		{
			class=message->Class;
			code=message->Code;
			ReplyMsg(message);

			switch (class)
			{
				case CLOSEWINDOW:
					CloseWindow(CustWindow);
					CloseLibrary(IntuitionBase);
					CloseLibrary(GfxBase);
					exit(1);
					break;

				case NEWSIZE:
					paint=1;
					break;

				case MOUSEBUTTONS:
					switch (code)
					{
						case SELECTDOWN:
							SetWindowTitles(CustWindow,"select...",-1);
							paint=0;
							loop=1;
							startx=x=xneu=CustWindow->GZZMouseX;
							starty=y=yneu=CustWindow->GZZMouseY;
							SetDrMd(rp,2);
							break;

						case SELECTUP:
							paint=1;
							loop=0;
							SetDrMd(rp,1);

							if (xneu<startx)
							{
								tmp=xneu;
								xneu=startx;
								startx=tmp;
							}
							if (yneu<starty)
							{
								tmp=yneu;
								yneu=starty;
								starty=tmp;
							}

							dx=(double)xneu-(double)startx;
							dy=(double)yneu-(double)starty;

							if (dx && dy)
							{
								rs+=(double)startx*rinc;
								is+=(double)starty*iinc;
								dr=dx*rinc;
								di=dy*iinc;
							}
							else
							{
								if (mandel)
								{
									mandel=0;
									o_is=is;
									o_di=di;
									o_rs=rs;
									o_dr=dr;
									rcon=rs+(double)startx*rinc;
									icon=is+(double)starty*iinc;
									is=-3.0;
									di=6.0;
									rs=-3.0;
									dr=6.0;
								}
								else
								{
									mandel=1;
									is=o_is;
									di=o_di;
									rs=o_rs;
									dr=o_dr;
								}
							}
							break;

						case MENUDOWN:
							paint=0;
							break;

						case MENUUP:
							paint=1;
							rs+=(-0.5*dr+(double)(CustWindow->GZZMouseX)*rinc);
							is+=(-0.5*di+(double)(CustWindow->GZZMouseY)*iinc);
							break;

						default:
							paint=0;
							break;
					}
					break;

				case MOUSEMOVE:
					paint=0;
					if (!loop) break;
					xneu=CustWindow->GZZMouseX;
					yneu=CustWindow->GZZMouseY;
					if (xneu!=x || yneu!=y)
					{
						if (xneu<0) xneu=0;
						if (yneu<0) yneu=0;
						if (xneu>=CustWindow->GZZWidth) xneu=CustWindow->GZZWidth-1;
						if (yneu>=CustWindow->GZZHeight) yneu=CustWindow->GZZHeight-1;
						Move(rp,startx,starty);
						Draw(rp,startx,y);
						Draw(rp,x,y);
						Draw(rp,x,starty);
						Draw(rp,startx,starty);

						Move(rp,startx,starty);
						Draw(rp,startx,yneu);
						Draw(rp,xneu,yneu);
						Draw(rp,xneu,starty);
						Draw(rp,startx,starty);
						x=xneu;
						y=yneu;
					}
					break;

				default:
					paint=0;
					break;
			}
		}
	}
}
