/* Small Plugin 2 ©2001 Jaca/Dreamolers
** Clever Amigants Polish Society
** republika.pl/jacadcaps/ jacadcaps@poczta.onet.pl
** Plugin looks best on title bar! it's transparent!!!
*/

/*                                 Based on                                  */
/*****************************************************************************/
/*                         AmigaAMP Plugin skeleton v1.2                     */
/*                     Written December 1998  by Thomas Wenzel               */
/*               Adapted to work with VBCC by Thomas Jensen Jan 1999         */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/nodes.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/cybergraphics.h>
#include <proto/icon.h>
#include <workbench/startup.h>

#include <dos/dostags.h>
#include <dos/dosextens.h>
#include <graphics/gfxbase.h>
#include <exec/tasks.h>
#include <intuition/screens.h>
#include <graphics/rastport.h>

#include <cybergraphics/cybergraphics.h>
#include <wbstartup.h>

#include "trackinfo.h"

#define VERSTR "$VER: SmallPlugin2 1.1 (26.02.01) ©2001 Jaca/Dreamolers-CAPS"

static struct WBStartup *wbmsg;
struct GfxBase *GfxBase;
struct Library *CyberGfxBase;

ULONG *background,*renderarray;
struct Window *wind;
BOOL fromwb=FALSE;

BOOL PluginInit(void);
void PluginExit(void);
void PluginLoop(void);
void FillLine(UBYTE yposition);
void ShowRequester(char *Text, char *Button);

/***************************************************************************/
/* This is the global variables section. Don't change anything here unless */
/* you know what you're doing!                                             */
/***************************************************************************/

BYTE             PluginSignal;
ULONG            PluginMask;
BOOL             Accepted;
struct Process   *PluginTask;
struct MsgPort   *PluginMP;
struct MsgPort   *PluginRP;
BYTE             InfoSignal; // v1.2
ULONG            InfoMask;   // v1.2
struct TrackInfo *tinfo;     // v1.2

UWORD	*PluginRawL;
UWORD	*PluginRawR;
UWORD	*SpecRawL;
UWORD	*SpecRawR;

struct PluginMessage {
	struct Message msg;
	ULONG          PluginMask;
	struct Process *PluginTask;
	UWORD          **SpecRawL;
	UWORD          **SpecRawR;
	BOOL           Accepted;

	/* All data beyond this point is new for v1.2.                         */
	/* AmigaAMP v2.5 and up will detect this new data and act accordingly. */
	/* Older versions of AmigaAMP will simply ignore it.                   */

	ULONG            InfoMask;
	struct TrackInfo **tinfo;
	ULONG            reserved;
};

/***************************************************************************/
/* This is the main part. Again, don't change anything here if you haven't */
/* got a very good reason to do so!                                        */
/***************************************************************************/

int main(void) {
	struct PluginMessage *PluginMsg;
	struct PluginMessage *ReplyMsg;

	/* (TJ) added for VBCC compatibility */
	#ifndef __SASC
	IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 36);
	if(IntuitionBase == NULL) {
		printf("Unable to open intuition.library V36+ (OS 2.1 required)\n");
		exit(5);
	}
	#endif

	/* Allocate all user resources */
	if(PluginInit()) {
		/* Check if a plugin capable instance of AmigaAMP is running */
		if(PluginMP=FindPort("AmigaAMP plugin port"))	{
			/* Allocate a sigbit for receiving signals FROM AmigaAMP */
			PluginTask   = (struct Process *)FindTask(NULL);
			PluginSignal = AllocSignal(-1);
			InfoSignal   = AllocSignal(-1);              // v1.2
			if(PluginSignal != -1 && InfoSignal != -1) { // v1.2
				InfoMask   = 1L << InfoSignal;             // v1.2
				PluginMask = 1L << PluginSignal;

				/* Allocate a message and reply port for sending messages TO AmigaAMP */
				PluginMsg=AllocVec(sizeof(struct PluginMessage), MEMF_PUBLIC|MEMF_CLEAR);
				PluginRP=CreatePort(0,0);

				/* Tell AmigaAMP all the details it needs to know */
				PluginMsg->msg.mn_Node.ln_Type = NT_MESSAGE;
				PluginMsg->msg.mn_Length       = sizeof(struct PluginMessage);
				PluginMsg->msg.mn_ReplyPort    = PluginRP;
				PluginMsg->PluginMask          = PluginMask;
				PluginMsg->PluginTask          = PluginTask;
				PluginMsg->SpecRawL            = &SpecRawL;
				PluginMsg->SpecRawR            = &SpecRawR;
				PluginMsg->InfoMask            = InfoMask;  // v1.2
				PluginMsg->tinfo               = &tinfo;    // v1.2
				PluginMsg->reserved            = 0;         // v1.2
				PutMsg(PluginMP, (struct Message *)PluginMsg);
				/* Wait for a reply */
				WaitPort(PluginRP);
				/* Let's see if AmigaAMP accepted our registration attempt */
				if(ReplyMsg = (struct PluginMessage *)GetMsg(PluginRP)) Accepted=ReplyMsg->Accepted;
				else Accepted=FALSE;

				if(Accepted) {
					/* If it did, start the plugin loop */
					PluginLoop();

					/* Tell AmigaAMP that this plugin is going down */
					PluginMsg->PluginMask          = 0;		/* (TJ) changed from NULL for VBCC compatibility */
					PluginMsg->PluginTask          = NULL;
					PluginMsg->SpecRawL            = NULL;
					PluginMsg->SpecRawR            = NULL;
					PluginMsg->InfoMask            = 0;     // v1.2
					PluginMsg->tinfo               = NULL;  // v1.2
					PluginMsg->reserved            = 0;     // v1.2
					PutMsg(PluginMP, (struct Message *)PluginMsg);
					/* Wait for confirmation before going on! */
					WaitPort(PluginRP);
					GetMsg(PluginRP);
					/* Now that AmigaAMP knows that we're gone, we can quit */
				}
				else {
					/* If AmigaAMP didn't accept us, tell the user about it */
					ShowRequester("Plugin rejected by AmigaAMP!\nPerhaps there's another one running.", "Abort");
				}

				/* Free all resources */
				FreeVec(PluginMsg);
				DeletePort(PluginRP);
				if(PluginSignal != -1) FreeSignal(PluginSignal);
				if(InfoSignal   != -1) FreeSignal(InfoSignal);   // v1.2
			}
			else {
				ShowRequester("Signal allocation failure!", "Abort");
			}
		}
		else {
			ShowRequester("Could not find message port!\nAmigaAMP probably not running.", "Abort");
		}
	}
	else {
		ShowRequester("Plugin initialisation failed!", "Ok");
	}
	/* Free all user resources */
	PluginExit();

	/* added for VBCC compatibility */
	#ifndef __SASC
	if(IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
	#endif
	return(0);
}

/*****************************************************************************/
/* Ok, now for the individual plugin sourcecode.                             */
/* Just like before, we start with the global variables section              */
/*****************************************************************************/



/****************************************************************************/
/* This function will be called once when the plugin is started. You should */
/* allocate all needed resources here. Return TRUE if all went well.        */
/****************************************************************************/

BOOL PluginInit(void) {
	/* Initialise everything here. Return TRUE if all went well, FALSE otherwise */
BOOL rc=TRUE;
static struct Library *IconBase;
static struct DiskObject *icon;
static struct Process *prog;
static struct Screen *wbscr;
static struct Screen scr;
static struct RastPort *rp;
static struct CommandLineInterface *cli;
char *val,*name;
ULONG scrx=425,scry=2,realdepth;

	prog = (struct Process *)FindTask(0);
	cli = BADDR(prog->pr_CLI);
	name = BADDR(cli->cli_CommandName);
	name++;

	if ((IconBase = OpenLibrary("icon.library",0)))
	{
		if (fromwb)
		{
			CurrentDir(wbmsg->sm_ArgList[0].wa_Lock);
			icon = GetDiskObject(wbmsg->sm_ArgList[0].wa_Name);
		} else {
		icon = GetDiskObject(name)}
		if (icon)
		{
			if ((val = FindToolType((STRPTR *) icon->do_ToolTypes,"XPOS")))
			{
				scrx = strtol(val,0,0);
			}
			if ((val = FindToolType((STRPTR *) icon->do_ToolTypes,"YPOS")))
			{
				scry = strtol(val,0,0);
			}
			
			FreeDiskObject(icon);
		}
	}

	if (IconBase) CloseLibrary(IconBase);

	if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0))) rc=FALSE;
	if (!(CyberGfxBase = (struct Library *)OpenLibrary("cybergraphics.library",41))) rc=FALSE;

	if (!(background = AllocVec(100*10*3,MEMF_PUBLIC))) rc=FALSE;
	if (!(renderarray = AllocVec(100*10*3,MEMF_PUBLIC))) rc=FALSE;

	if (rc == FALSE) return(FALSE); //MUST BE PLACED HERE!

	Delay(5); //wait 1/10 sec for quit of last plugin :)

	if ((wbscr=LockPubScreen(0)))
	{
		rp = &wbscr->RastPort;
		ReadPixelArray(background,0,0,300,rp,
			scrx,scry,100,10,RECTFMT_RGB); //get background

		realdepth=0;
		
		if (IsCyberModeID(GetVPModeID(&wbscr->ViewPort)))
		{
			realdepth = GetBitMapAttr(wbscr->RastPort.BitMap, BMA_DEPTH );
		}
	
		if (realdepth>8)
		{
			if (!(wind = OpenWindowTags(0,WA_Left,scrx,
												WA_Top,scry,
												WA_Width,100,WA_Height,10,
												WA_SizeGadget,FALSE,WA_DragBar,FALSE,
												WA_DepthGadget,FALSE,WA_CloseGadget,FALSE,
												WA_Backdrop,FALSE,WA_Activate,FALSE,
												WA_RMBTrap,TRUE,WA_PubScreen,wbscr,
												WA_Flags,WFLG_BORDERLESS,WA_IDCMP,IDCMP_VANILLAKEY,
												WA_ScreenTitle,VERSTR,
												TAG_DONE))) rc=FALSE;
		} else {rc=FALSE}

		UnlockPubScreen(0,wbscr);
	} else {
		rc=FALSE;
	}

	if (rc) WritePixelArray(background,0,0,300,wind->RPort,0,0,100,10,RECTFMT_RGB);
	//1st step of transparency :)
	
	return rc;
}

/******************************************************************************/
/* This function will be called when the plugin is shut down. You should free */
/* all previously allocated resources here.                                   */
/******************************************************************************/

void PluginExit(void) {
	/* Free everything you've allocated before */
if (wind) CloseWindow(wind);
if (renderarray) FreeVec(renderarray);
if (background) FreeVec(background);
if (CyberGfxBase) CloseLibrary(CyberGfxBase);
if (GfxBase) CloseLibrary((struct Library *)GfxBase);
}

/*******************************************************************************/
/* This is the main Plugin Loop. It will receive a signal matching PluginMask  */
/* each time new spectral data is ready. The data is stored in two arrays,     */
/* UWORD SpecRawL[512] and UWORD SpecRawR[512]. The scale is logarithmic, i.e. */
/* 0 means below -96dB, 65535 means 0dB.                                       */
/* No matter how long it takes until your plugin actually processes the data,  */
/* the memory referenced by the array pointers always remains valid!           */
/*                                                                             */
/* Your plugin loop MUST quit when it receives SIGBREAKF_CTRL_C. If you've     */
/* opened a window you should react to the close gadget as well. For full      */
/* screen plugins I strongly recommend checking the ESC key.                   */
/*******************************************************************************/

void PluginLoop(void) {
	ULONG Signals,windowsig;
	struct IntuiMessage *msg;
	char title[200];
	
	windowsig = 1L << wind->UserPort->mp_SigBit;

	strcpy(title,VERSTR);

	for(;;) {

		/* Wait until there's something to do */
		Signals=Wait(SIGBREAKF_CTRL_C | PluginMask | windowsig); // v1.2

		/* Break received -> quit at once! */
		if(Signals & SIGBREAKF_CTRL_C) break;


		if(Signals & windowsig);
		{
			msg = (struct IntuiMessage *)GetMsg(wind->UserPort);
			if (msg)
			{
				if (msg->Class = IDCMP_VANILLAKEY)
				{
					if (msg->Code == 27)
					{
						ReplyMsg(&msg->ExecMessage);
						break;
					}
				}
				ReplyMsg(&msg->ExecMessage);
			}
		}

		/* New data has arrived! */
		if(Signals & PluginMask) {
			/*********************************************************/
			/* Visualise SpecRawL[0..511] and SpecRawR[0..512] here! */
			/*********************************************************/

				CopyMem(background,renderarray,100*10*3); //clear buffer!
				FillLine(0);	//fill all lines!
				FillLine(1);	//fill all lines!
				FillLine(2);	//fill all lines!
				FillLine(3);	//fill all lines!
				FillLine(4);	//fill all lines!
				FillLine(5);	//fill all lines!
				FillLine(6);	//fill all lines!
				FillLine(7);	//fill all lines!
				FillLine(8);	//fill all lines!
				FillLine(9);	//fill all lines!
				WritePixelArray(renderarray,0,0,300,wind->RPort,0,0,100,10,RECTFMT_RGB);
			}

		/* New track info has arrived! */
//		if(Signals & InfoMask) {
			/**********************************************************************/
			/* If you want to display anything from struct TrackInfo, do it here! */
			/**********************************************************************/
//				sprintf(title,"ABC-%s",&tinfo->TrackInfoText);
//				SetWindowTitles(wind,0,title);
//		}
	}
}

void FillLine(UBYTE yposition)
{
ULONG level;
UBYTE *triplet,*triplet2,xcnt;
UBYTE red=127,green=0x00,blue=0x00;
	triplet = (UBYTE *)renderarray + (300*yposition);
	triplet2 = (UBYTE *)background + (300*yposition);
	if (yposition > 0)
	{level = 46000-(yposition*4000);}else{level=46000};

	switch (yposition)
	{
		case 1:
			green=0x30/2;break;
		case 2:
			green=0x80/2;break;
		case 3:
			green=0xFF/2;break;
		case 4:
			green=0xAA/2;red=0xAA/2;blue=0x22/2;break;
		case 5:
			green=0x88/2;red=0x88/2;blue=0x44/2;break;
		case 6:
			green=0x66/2;red=0x66/2;blue=0x55/2;break;
		case 7:
			green=0x44/2;red=0x44/2;blue=0x66/2;break;
		case 8:
			green=0x22/2;red=0x22/2;blue=0x77/2;break;
		case 9:
			green=0x00;red=0x00;blue=0x88/2;break;
	}
	if (yposition > 4) red=0;

	for (xcnt = 0; xcnt < 100; xcnt++)
	{
		if (level <= ((SpecRawL[xcnt*5] + SpecRawR[xcnt*5])/2))
		{
			triplet[0]=(red+(triplet2[0]/2));	//mix color with background
			triplet[1]=(green+(triplet2[1]/2));
			triplet[2]=(blue+(triplet2[2]/2));
		}
			triplet+=3;triplet2+=3;
	}
}

void ShowRequester(char *Text, char *Button) {
	struct EasyStruct Req;

  Req.es_Title        = "AmigaAMP Plugin";
  Req.es_TextFormat   = (UBYTE*)Text;
  Req.es_GadgetFormat = (UBYTE*)Button;
	EasyRequestArgs(NULL, &Req, NULL, NULL);
}

void wbmain(struct WBStartup *msg)
{
	wbmsg = msg;
	if (wbmsg) fromwb = TRUE;
	main();
}
/* (TJ) added to avoid VBCC linker error */
#ifndef __SASC
struct IntuitionBase *IntuitionBase=NULL;
#endif
