#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 3 (6.11.1995)";

#ifndef AZTEC
struct Library *IconBase;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *CxBase;
#endif

#define rp CustWindow->RPort

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

/*	ran() is an Aztec C library function	*/

#ifndef AZTEC
#define ran() ((double)rand()/(double)RAND_MAX)
#endif

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

	if ((IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0))==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",16);
			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;

	icon=-.2;	/*	complex constant	*/
	rcon=-1.3;

/*	make #### (censored since version 3) to julia	*/

	while (1)
	{
		rinc=dr/(double)(CustWindow->GZZWidth);
		iinc=di/(double)(CustWindow->GZZHeight);

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

		if (!paint) goto next;

		memi=is;

		tmpw=CustWindow->GZZWidth;
		tmph=CustWindow->GZZHeight;

		for (y=0; y<CustWindow->GZZHeight; y++)	/*	row	*/
		{
			memr=rs;

			for (x=0; x<CustWindow->GZZWidth; x++)
			{
				if (tmpw!=CustWindow->GZZWidth || tmph!=CustWindow->GZZHeight) continue;
				
				re=restart=(rs+=rinc);
				im=imstart=is;

				SetAPen(rp,0);

				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)
					{
						SetAPen(rp,1+n%(colors-1));
						break;
					}
				}
				WritePixel(rp,x,y);
			}
			rs=memr;
			is+=iinc;
		}
		is=memi;

next:		paint=1;

		SetWindowTitles(CustWindow,"Fun with Julia",-1);
wait:
		Wait(1L<<CustWindow->UserPort->mp_SigBit);

		if (message=GetMsg(CustWindow->UserPort))
		{
			class=message->Class;
			code=message->Code;
			ReplyMsg(message);
		}
		else
		{
			class=0;
			code=0;
		}

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

			case NEWSIZE:
				continue;
				break;

			default:
				break;
		}

		switch (code)
		{
			case SELECTDOWN+1:
				SetWindowTitles(CustWindow,"Oh, yeah...do it to me !",-1);

				while (1)
				{
					Wait(1L<<CustWindow->UserPort->mp_SigBit);
					if (message=GetMsg(CustWindow->UserPort))
					{
						code=message->Code;
						ReplyMsg(message);
					}
					else code=0;

					if (code==SELECTUP+1)
					{
						rs+=(-0.5*dr+(double)(CustWindow->GZZMouseX)*rinc);
						is+=(-0.5*di+(double)(CustWindow->GZZMouseY)*iinc);
						break;
					}
				}
				break;

			case SELECTDOWN:
				SetWindowTitles(CustWindow,"Oh, yeah...do it to me !",-1);

				startx=x=xneu=CustWindow->GZZMouseX;
				starty=y=yneu=CustWindow->GZZMouseY;

				SetDrMd(rp,2);

				while (1)
				{
					if (message=GetMsg(CustWindow->UserPort))
					{
						code=message->Code;
						ReplyMsg(message);
					}

					if (code==SELECTUP)
					{
						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
						{
							is=-3.0;
							di=6.0;
							rs=-3.0;
							dr=6.0;
							rcon=2.0*ran()-1.0;
							icon=2.0*ran()-1.0;
						}
						break;
					}

					if ((xneu=CustWindow->GZZMouseX)!=x || (yneu=CustWindow->GZZMouseY)!=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;
		}
	}	
}
