//#define	D(x)	x;
#define	D(x)	;

#include <intuition/screens.h>
#include <graphics/rastport.h>
#include <graphics/gfxmacros.h>
#include <intuition/intuition.h>
#include <intuition/classes.h>
#include <intuition/imageclass.h>
#include <intuition/icclass.h>
#include <intuition/gadgetclass.h>

#include <libraries/p4specials.h>

#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <proto/dos.h>
#include <proto/xsl.h>
#include	<proto/picasso96.h>

#include	<stdio.h>
#include	<math.h>

#include "TV.h"
#include "cs_sup.h"

/***************************************************************************
 * some usually private tags
 ***************************************************************************
 */

#define	FA_Interlace				(TAG_USER+16)
#define	FA_DoubleBuffer			(TAG_USER+30)


/***************************************************************************
 *
 *  Pepo's peculiarities.
 *
 ***************************************************************************
 */

#define NEW(type) ((type *) AllocMem(sizeof(type), MEMF_CLEAR | MEMF_PUBLIC))
#define DISPOSE(stuff) (FreeMem(stuff, sizeof(*stuff)))

#ifndef IM
#define IM(o) ((struct Image *) o)
#endif

#ifndef MAX
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#endif
#ifndef MIN
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#endif


/***************************************************************************
 *
 *  Global variables.
 *
 ***************************************************************************
 */


enum {
	ARG_Width,
	ARG_Height,
	ARG_PubScreen,
	ARG_Interlace,
	ARG_FullScreen,
	ARG_DoubleBuffer,
	ARG_AccuPak,
	ARG_StartChannel,
	ARG_NumArgs
};

char template[] = "Width=W/N,Height=H/N,Pubscreen=PS/K,Interlace=IL/S,FullScreen=FS/S,DoubleBuffer=DB/S,AccuPak=AP/S,StartChannel=SC/K";
char *array[ARG_NumArgs] = {NULL, NULL, "Workbench", FALSE, FALSE, FALSE, FALSE, NULL};

struct Library		*P96Base;
struct Window		*wd;

ULONG brightness = 0, volume = 31;
WORD	VideoWidth = 704, VideoHeight = 548;

int ChannelIndex = 0, Mode = MODE_TV;
char WindowTitle[60];

struct DrawInfo *dri;
Object *sgadget, *sizeimage, *uimage, *dimage, *nimage, *pimage, *simage;

struct IClass  *NextClass, *PrevClass, *SnapClass;
Object *BrightnessGadget, *VolumeGadget, *UpGadget, *DownGadget, *PrevGadget, *NextGadget, *SnapGadget;

/* Creates a sysiclass object. */
Object *NewImageObject(ULONG which)
{
	return (NewObject(NULL, SYSICLASS,
	 SYSIA_DrawInfo, dri,
	 SYSIA_Which, which,
	 SYSIA_Size, SYSISIZE_HIRES,
	TAG_DONE));
}

/* Creates a buttongclass object. */
Object *NewButtonObject(Object *image, Tag tag1, ...)
{
	return (NewObject(NULL, BUTTONGCLASS,
	 ICA_TARGET, ICTARGET_IDCMP,
	 GA_Image, image,
	/* No need for GA_Width/Height.  buttongclass is smart :) */
	TAG_MORE, &tag1));
}

/* Creates a propgclass object. */
Object *NewPropObject(ULONG freedom, Tag tag1, ...)
{
	return (NewObject(NULL, PROPGCLASS,
	/* Send update to IDCMP.  If we make it a model, we would send the
	 * notification to our model object. */
	 ICA_TARGET, ICTARGET_IDCMP,
	 PGA_Freedom, freedom,
	 PGA_NewLook, TRUE,
	/* Borderless does only look right with newlook screens */
	 PGA_Borderless, ((dri->dri_Flags & DRIF_NEWLOOK) && dri->dri_Depth != 1),
	TAG_MORE, &tag1));
}

/************************************************************************/

extern struct List ChannelList;

int main(void)
{
	struct Node *n;
	struct Menu *menu;
	struct RDArgs	*rda;
	LONG	Width = -1, Height = -1;
	
	NewList(&ChannelList);
	cs_init();

	if(P96Base=OpenLibrary("Picasso96API.library",2)){
		struct Screen		*sc;

		if(rda = ReadArgs(template,(LONG *)array,NULL)){
			if(array[ARG_Width])		Width =*((LONG *)array[ARG_Width]);
			if(array[ARG_Height])	Height=*((LONG *)array[ARG_Height]);
		}

		VideoWidth  /= (array[ARG_Interlace] ? 1 : 2);
		VideoHeight /= (array[ARG_Interlace] ? 1 : 2);

		if(sc = LockPubScreen(array[ARG_PubScreen])){
			APTR VisualInfo;
			
			VisualInfo = GetVisualInfo(sc, NULL);
			
			if(Width ==-1) Width  = sc->Width/2;
			if(Height==-1) Height = sc->Height/2;

			menu = CreateMenus(newMenu, TAG_END);
			LayoutMenus( menu, VisualInfo, GTMN_NewLookMenus, TRUE, TAG_END );

			if(dri = GetScreenDrawInfo(sc)){
				WORD w = 2;
				WORD h = 2;

				if(sizeimage = NewImageObject(SIZEIMAGE)){
					w = IM(sizeimage)->Width;
					h = IM(sizeimage)->Height;
					DisposeObject(sizeimage);
				}

				NextClass = initNext();
				PrevClass = initPrev();
				SnapClass = initSnap();

				uimage = NewObject(NULL, SYSICLASS,
										SYSIA_DrawInfo, dri,
										SYSIA_Which, UPIMAGE,
										SYSIA_Size, SYSISIZE_MEDRES,
										TAG_DONE);

				dimage = NewObject(NULL, SYSICLASS,
										SYSIA_DrawInfo, dri,
										SYSIA_Which, DOWNIMAGE,
										SYSIA_Size, SYSISIZE_MEDRES,
										TAG_DONE);

				nimage = NewObject( NextClass, NULL, GT_VisualInfo, VisualInfo, 
										MY_Height, h,
										MY_Width, w,
										TAG_DONE);

				pimage = NewObject( PrevClass, NULL, GT_VisualInfo, VisualInfo, 
										MY_Height, h,
										MY_Width, w,
										TAG_DONE);

				simage = NewObject( SnapClass, NULL, GT_VisualInfo, VisualInfo, 
											MY_Height, h,
											MY_Width, w,
											TAG_DONE );
											
				BrightnessGadget = NewPropObject(FREEVERT,
												GA_ID, BRIGHTNESS_GID,
												GA_RelRight, - w + 4,
												GA_Top, sc->WBorTop + sc->Font->ta_YSize + 3,
												GA_Width, w - 7,
												GA_RelHeight, - sc->WBorTop - sc->Font->ta_YSize - h - IM(uimage)->Height - IM(dimage)->Height - 5,
												GA_RightBorder, TRUE,
												PGA_Total, 32,
												PGA_Visible, 1,
												TAG_DONE);

				VolumeGadget = NewPropObject(FREEHORIZ,
												GA_ID, VOLUME_GID,
												GA_RelBottom, - h + 3,
												GA_Previous, BrightnessGadget,
												GA_Left, sc->WBorLeft - 1,
												GA_Height, h - 4,
												GA_RelWidth, - sc->WBorLeft - w - IM(simage)->Width - IM(pimage)->Width - IM(nimage)->Width - 1,
												GA_BottomBorder, TRUE,
												PGA_Total, 32,
												PGA_Visible, 1,
												TAG_DONE);

				UpGadget = NewButtonObject(uimage,
												GA_ID, UP_GID,
												GA_RelRight, - w + 1,
												GA_Previous, VolumeGadget,
												GA_RelBottom, - IM(uimage)->Height - IM(dimage)->Height - h + 1,
												GA_Width, IM(uimage)->Width - 2,
												GA_Height, IM(uimage)->Height - 2,
												GA_RightBorder, TRUE,
												TAG_DONE);

				DownGadget = NewButtonObject(dimage,
												GA_ID, DOWN_GID,
												GA_RelRight, - w + 1,
												GA_Previous, UpGadget,
												GA_RelBottom, - IM(dimage)->Height - h + 1,
												GA_Width, IM(dimage)->Width - 2,
												GA_Height, IM(dimage)->Height - 2,
												GA_RightBorder, TRUE,
												TAG_DONE);

				NextGadget = NewButtonObject(nimage,
												GA_ID, NEXT_GID,
												GA_Immediate, TRUE,
												GA_RelVerify, TRUE,
												GA_RelRight, - w - IM(nimage)->Width + 1,
												GA_Previous, DownGadget,
												GA_RelBottom, - h + 1,
												GA_Width, IM(nimage)->Width - 2 - 1,
												GA_Height, IM(nimage)->Height - 2,
												GA_BottomBorder, TRUE,
												TAG_DONE);

				PrevGadget = NewButtonObject(pimage,
												GA_ID, PREV_GID,
												GA_Immediate, TRUE,
												GA_RelVerify, TRUE,
												GA_RelRight, - w - IM(pimage)->Width - IM(nimage)->Width + 1,
												GA_Previous, NextGadget,
												GA_RelBottom, - h + 1,
												GA_Width, IM(pimage)->Width - 2 - 1,
												GA_Height, IM(pimage)->Height - 2,
												GA_BottomBorder, TRUE,
												TAG_DONE);

				SnapGadget = NewButtonObject(simage,
												GA_ID, SNAP_GID,
												GA_Immediate, TRUE,
												GA_RelVerify, TRUE,
												GA_RelRight, - w - IM(pimage)->Width - IM(nimage)->Width - IM(simage)->Width + 1,
												GA_Previous, NextGadget,
												GA_RelBottom, - h + 1,
												GA_Width, IM(simage)->Width - 2 - 1,
												GA_Height, IM(simage)->Height - 2,
												GA_BottomBorder, TRUE,
												TAG_DONE);

				if(BrightnessGadget && VolumeGadget && DownGadget && UpGadget && NextGadget && PrevGadget && SnapGadget){

					if(wd = p96PIP_OpenTags(
												P96PIP_Type, P96PIPT_VideoWindow,
												P96PIP_SourceFormat, array[ARG_AccuPak] ? RGBFB_Y4U1V1 : RGBFB_Y4U2V2,
												P96PIP_SourceWidth, VideoWidth,
												P96PIP_SourceHeight, VideoHeight,
												FA_Interlace, (array[ARG_Interlace] ? TRUE : FALSE),
												FA_DoubleBuffer, (array[ARG_DoubleBuffer] ? TRUE : FALSE),
												P4PALO_Video_SetStandard, P4PALO_PAL,
												array[ARG_FullScreen] ? TAG_IGNORE : WA_Title, WindowTitle,
												WA_Activate, TRUE,
												WA_SimpleRefresh, TRUE,
												WA_Left, array[ARG_FullScreen] ? 0 : (sc->Width-Width)/2,
												WA_Top, array[ARG_FullScreen] ? 0 : (sc->Height-Height)/2,
												WA_Width, array[ARG_FullScreen] ? sc->Width : Width,
												WA_Height, array[ARG_FullScreen] ? sc->Height : Height,
												WA_Borderless, array[ARG_FullScreen] ? TRUE : FALSE,
												array[ARG_FullScreen] ? TAG_IGNORE : WA_DragBar, TRUE,
												array[ARG_FullScreen] ? TAG_IGNORE : WA_DepthGadget, TRUE,
												array[ARG_FullScreen] ? TAG_IGNORE : WA_SizeGadget, TRUE,
												array[ARG_FullScreen] ? TAG_IGNORE : WA_CloseGadget, TRUE,
												array[ARG_FullScreen] ? TAG_IGNORE : WA_Gadgets, BrightnessGadget,
												WA_NewLookMenus, TRUE,
												WA_IDCMP, IDCMP_GADGETDOWN|IDCMP_CLOSEWINDOW|IDCMP_IDCMPUPDATE|IDCMP_MENUPICK|IDCMP_MOUSEBUTTONS,
												WA_PubScreen, sc, TAG_DONE)){

						struct Message	*msg;
						BOOL	goahead = TRUE;

						SetMenuStrip(wd, menu);

						WindowToFront(wd);

						ReadSettings();
						initAVModule();
						ActivateTuner();
						
						if(array[ARG_StartChannel]){
							struct Node *start = FindName(&ChannelList, array[ARG_StartChannel]);
							if(start) ChannelIndex = NodeNumber(&ChannelList, start);
						}

						if(NumChannels){
							SetChannel(ChannelIndex);
							sprintf(WindowTitle,"Paloma TV Demo Channel: \"%s\"",FindNumber(&ChannelList, ChannelIndex)->ln_Name);
						}else{
							sprintf(WindowTitle,"Paloma TV Demo");
						}
						SetWindowTitles(wd,WindowTitle,WindowTitle);
						
						p96PIP_GetTags(wd, P4PALO_Video_Brightness, &brightness, TAG_DONE);
						SetGadgetAttrs((struct Gadget *)BrightnessGadget, wd, NULL, PGA_Top, brightness>>27, TAG_DONE);
						p96PIP_GetTags(wd, P4PALO_TV_Volume, &volume, TAG_DONE);
						SetGadgetAttrs((struct Gadget *)VolumeGadget, wd, NULL, PGA_Top, volume>>27, TAG_DONE);

						do{
							WaitPort(wd->UserPort);
							while(msg = GetMsg(wd->UserPort)){
								struct IntuiMessage	*imsg = (struct IntuiMessage *)msg;
								switch(imsg->Class){
								case	IDCMP_CLOSEWINDOW:
									goahead = FALSE;
									break;
								case	IDCMP_MENUPICK:
									while( imsg->Code != MENUNULL ) {
										struct MenuItem *n;
										n = ItemAddress( menu, imsg->Code );
										goahead &= ((int (*)(void))(GTMENUITEM_USERDATA(n)))();
										imsg->Code = n->NextSelect;
									}
									break;
								case IDCMP_IDCMPUPDATE:
									/* IAddress is a pointer to a taglist with new attributes.
									 * We are only interested in the ID of the involved gadget.
									 */
									switch (GetTagData(GA_ID, 0, (struct TagItem *) imsg->IAddress)){
									case	BRIGHTNESS_GID:
										/* Get right place */

										GetAttr(PGA_Top, BrightnessGadget, (ULONG *)&brightness);
										p96PIP_SetTags(wd, P4PALO_Video_Brightness, (31-brightness)<<27, TAG_DONE);
										break;
									case	VOLUME_GID:
										/* Get right place */

										GetAttr(PGA_Top, VolumeGadget, (ULONG *)&volume);
										p96PIP_SetTags(wd, P4PALO_TV_Volume, volume<<27, TAG_DONE);
										break;
									case	UP_GID:
										GetAttr(PGA_Top, BrightnessGadget, (ULONG *)&brightness);
										if(brightness > 0){
											SetGadgetAttrs((struct Gadget *)BrightnessGadget, wd, NULL, PGA_Top, --brightness, TAG_DONE);
											p96PIP_SetTags(wd, P4PALO_Video_Brightness, (31-brightness)<<27, TAG_DONE);
										}
										break;
									case	DOWN_GID:
										GetAttr(PGA_Top, BrightnessGadget, (ULONG *)&brightness);
										if(brightness < 31){
											SetGadgetAttrs((struct Gadget *)BrightnessGadget, wd, NULL, PGA_Top, ++brightness, TAG_DONE);
											p96PIP_SetTags(wd, P4PALO_Video_Brightness, (31-brightness)<<27, TAG_DONE);
										}
										break;
									}
									break;
								case	IDCMP_GADGETDOWN:
									switch(((struct Gadget *)imsg->IAddress)->GadgetID){
									case	NEXT_GID:
										NextChannel();
										break;
									case	PREV_GID:
										PrevChannel();
										break;
									case	SNAP_GID:
										{
											BPTR	file;
											if(file = Open("Bild", MODE_NEWFILE)){
												struct RenderInfo	ri;
												struct BitMap	*bm;
												ULONG	w, h;
												LONG	lock;

												p96PIP_GetTags(wd, P96PIP_SourceBitMap, &bm, TAG_DONE);

								            w = p96GetBitMapAttr(bm, P96BMA_WIDTH);
												h = p96GetBitMapAttr(bm, P96BMA_HEIGHT);
												lock = p96LockBitMap(bm, (UBYTE *)&ri, sizeof(struct RenderInfo));
												Write(file, ri.Memory, ri.BytesPerRow*h);
												p96UnlockBitMap(bm, lock);
												Close(file);
												switch(Mode){
												case	MODE_TV:
													ActivateTuner();
													break;
												case	MODE_FBAS:
													ActivateFBAS();
													break;
												case	MODE_SVHS:
													ActivateSVHS();
													break;
												case	MODE_PABLO:
													ActivatePABLO();
													break;
												}
												SetChannel(ChannelIndex);
												D(Printf("Bild geschrieben: (%ld x %ld - %ld)\n",w,h,ri.BytesPerRow));
											}
										}
										break;
									}
									break;
								}
								ReplyMsg(msg);
							}
						}while(goahead);

						ClearMenuStrip(wd);

						Forbid();
						while(msg = GetMsg(wd->UserPort)) ReplyMsg(msg);
						Permit();

						shutdownAVModule();

						p96PIP_Close(wd);
					}
				}
				DisposeObject(SnapGadget);
				DisposeObject(PrevGadget);
				DisposeObject(NextGadget);
				DisposeObject(UpGadget);
				DisposeObject(DownGadget);
				DisposeObject(VolumeGadget);
				DisposeObject(BrightnessGadget);

				DisposeObject(simage);
				DisposeObject(uimage);
				DisposeObject(dimage);
				DisposeObject(nimage);
				DisposeObject(pimage);

				FreeClass(SnapClass);
				FreeClass(NextClass);
				FreeClass(PrevClass);

				FreeScreenDrawInfo(sc, dri);
			}
			FreeVisualInfo(VisualInfo);
			UnlockPubScreen(NULL, sc);
			FreeMenus(menu);
		}
		if(rda) FreeArgs(rda);
		
		CloseLibrary(P96Base);
	}
	
	while(n = RemHead(&ChannelList)){
		FreeVec(n->ln_Name);
		FreeVec(n);
	}
}

int NextChannel(void)
{
	if(NumChannels){
		ChannelIndex = TuneNext(ChannelIndex);
		sprintf(WindowTitle,"Paloma TV Demo Channel: \"%s\"",FindNumber(&ChannelList, ChannelIndex)->ln_Name);
		SetWindowTitles(wd,WindowTitle,WindowTitle);
	}
	return(1);
}

int PrevChannel(void)
{
	if(NumChannels){
		ChannelIndex = TunePrev(ChannelIndex);
		sprintf(WindowTitle,"Paloma TV Demo Channel: \"%s\"",FindNumber(&ChannelList, ChannelIndex)->ln_Name);
		SetWindowTitles(wd,WindowTitle,WindowTitle);
	}
	return(1);
}
