/*
 * © 1992 by Michal Watzl, compiled with DICE
 *
 * Compile Me with: Dcc MCMaster.c -2.0 -proto -o MCMaster
 *
 */




#include "MCMaster.h"

STRPTR
fitstring(STRPTR cutme, WORD length)
{
	sprintf(uname[29],"%-100s",cutme);				/* I need a global var */
        uname[29][length]='\0';
       	return((STRPTR)uname[29]);
}
STRPTR
cutstring(STRPTR cutme, WORD length)
{
	strncpy( uname[28] , cutme , length);
       	return((STRPTR)uname[28]);
}

VOID
PrintList(ULONG Mode)
{
	LONG i;
	
	if(EasyRequest(printwin,&easyprintl,NULL,what[Mode-MENU_LIST_BASE])!=1) return;
        InitPrinter();
        if(PDOPEN==FALSE){
		usermessage("Error while opening printer!");
		return;
	}
	SendCommand( aSGR4 ,0,0,0,0);
	sprintf( uname[0] , "List of all %s\n\n" , what[Mode-MENU_LIST_BASE] );
	SendBuffer( uname[0] , CMD_WRITE );
	SendCommand( aSGR24 ,0,0,0,0);

        for(i=0; i<=LastNode ; i++){
		SendBuffer( LEntry[i].LabelName , CMD_WRITE);
		SendBuffer( "\n" , CMD_WRITE );
	}	
	FORM_FEED;
        ClosePrinter();
}

VOID
PrintOut(WORD start,end, UWORD Mode)
{
	WORD 	j,i;
	UBYTE	temp[ LINE_LENGTH ];	/* Buffer that will be sent to the printer */

        if(EasyRequest(printwin,&easyprint,NULL,(APTR)frommc,cass[frommc].Name[0],cass[frommc].Name[1],cass[frommc].Name[15],cass[frommc].Name[16],(APTR)tomc,cass[tomc].Name[0],cass[tomc].Name[1],cass[tomc].Name[15],cass[tomc].Name[16])==0) return;
        InitPrinter();
        if(PDOPEN==FALSE){
		usermessage("Error while opening printer!");
		return;
	}
	if( Mode == DRAFT )	SendCommand( aDEN1 ,0,0,0,0);
	else			SendCommand( aDEN2 ,0,0,0,0);

	for(j=start; j<=end ; j++){
	        CPI10;
		sprintf( uname[0], "%-37.37s", ownername[0]);
		SendBuffer( uname[0] , CMD_WRITE );
		LINE_FEED;

		sprintf( uname[0], "%-25.25s", ownername[1]);
		SendBuffer( uname[0] , CMD_WRITE );
		CPI15;
		SendBuffer("  Side A: N.R. "      , CMD_WRITE );
		SendBuffer( NR[ cass[j].NR[0] ] , CMD_WRITE );
		LINE_FEED;

		CPI10;
		sprintf( uname[0], "%-25.25s", ownername[2]);
		SendBuffer( uname[0] , CMD_WRITE );
		CPI15;
		SendBuffer("  Side B: N.R. ", CMD_WRITE );
		SendBuffer( NR[ cass[j].NR[1] ], CMD_WRITE  );
		LINE_FEED;
		SendBuffer(LINE, CMD_WRITE );

        	/*
        	 *	The back of the cover
        	 */
		SendCommand(aSGR1  ,0,0,0,0); /* BOLD ON */
		SendCommand( aPLD  ,0,0,0,0); /* Part. Line Down */
                SendBuffer( strcpy( uname[0] , fitstring( cass[j].Name[0]  , 30 ) ), CMD_WRITE  );
		SendCommand(aSGR22 ,0,0,0,0); /* BOLD OFF */
		SendBuffer("'", CMD_WRITE );
		SendBuffer( strcpy( uname[0] , cutstring( cass[j].Name[1]  , 31 ) ) , CMD_WRITE  );
		SendBuffer("'", CMD_WRITE );

                LINE_FEED;
		SendCommand(aSGR1  ,0,0,0,0); /* BOLD ON */
                SendBuffer( strcpy( uname[0] , fitstring( cass[j].Name[15]  , 30 ) ) , CMD_WRITE );
		SendCommand(aSGR22 ,0,0,0,0); /* BOLD OFF */
		SendBuffer("'", CMD_WRITE );
		SendBuffer( strcpy( uname[0] , cutstring( cass[j].Name[16]  , 31 ) ) , CMD_WRITE );
		SendBuffer("'\r", CMD_WRITE );
		SendCommand( aPLD ,0,0,0,0);		
		SendBuffer( LINE , CMD_WRITE );

		sprintf( uname[0] , "\n %-32.32s %-30.30s\n", cass[j].Name[1] , cass[j].Name[16] );
		SendBuffer( uname[0] , CMD_WRITE );
		for(i=2;i<15;i++){
			LINE_FEED;
			if( strlen(cass[j].Name[i   ])!=0) sprintf( uname[0] , "%2d. %-28.28s ", i-1 , cass[j].Name[i] );
			else	sprintf( uname[0] , "%-33.33s" , NULL);
			if( strlen(cass[j].Name[i+15])!=0) sprintf( uname[1] , "%2d. %-27.27s", i-1 , cass[j].Name[i+15]);
			else	uname[1][0]='\0';
			strcat( uname[0] , uname[1] );
			SendBuffer( uname[0] , CMD_WRITE );
		}
		SendCommand( aPLD ,0,0,0,0);
		SendBuffer( "\r" , CMD_WRITE );
		SendBuffer( LINE , CMD_WRITE );
		LINE_FEED;
		if( (float)((j-start) / 2) == (j-start)/ 2 ) FORM_FEED;	/* ff every 2 covers */
	} /* for j */
/*	ResetPrinter();*/
        ClosePrinter();
}

WORD
Print()
{
	BOOL leave=FALSE;
	WORD i;
	UWORD PMode=DRAFT;
	STRPTR	Quality[] ={"_Draft","_Letter",NULL};
	frommc = current;
	tomc   = current;

	struct NewGadget fromAIn ={ 20, 20,200,14,NULL      ,&TOPAZ80, 0,NULL,vi,NULL};	/* start stringgad */
	struct NewGadget fromATi ={ 20, 40,200,14,NULL      ,&TOPAZ80, 0,NULL,vi,NULL};	/* end stringgad */
	struct NewGadget fromBIn ={420, 20,200,14,NULL      ,&TOPAZ80, 0,NULL,vi,NULL};	/* start stringgad */
	struct NewGadget fromBTi ={420, 40,200,14,NULL      ,&TOPAZ80, 0,NULL,vi,NULL};	/* end stringgad */
	struct NewGadget toAIn	 ={ 20, 70,200,14,NULL      ,&TOPAZ80, 0,NULL,vi,NULL};	/* start stringgad */
	struct NewGadget toATi	 ={ 20, 90,200,14,NULL      ,&TOPAZ80, 0,NULL,vi,NULL};	/* end stringgad */
	struct NewGadget toBIn	 ={420, 70,200,14,NULL      ,&TOPAZ80, 0,NULL,vi,NULL};	/* start stringgad */
	struct NewGadget toBTi	 ={420, 90,200,14,NULL      ,&TOPAZ80, 0,NULL,vi,NULL};	/* end stringgad */
	struct NewGadget up1	 ={275, 42, 20,11,"<"       ,&TOPAZ80, 1,NULL,vi,NULL};		/* up arrow for 1st*/
	struct NewGadget down1	 ={345, 42, 20,11,">"       ,&TOPAZ80, 2,NULL,vi,NULL};		/* down arrow for 1st */
	struct NewGadget up2	 ={275, 92, 20,11,"<"       ,&TOPAZ80, 3,NULL,vi,NULL}; 		/* up arrow for 2nd*/
	struct NewGadget down2	 ={345, 92, 20,11,">"       ,&TOPAZ80, 4,NULL,vi,NULL}; 		/* down arrow for 2nd */
	struct NewGadget pos1	 ={300, 40, 40,14,"_FROM MC",&TOPAZ80, 5,PLACETEXT_ABOVE|NG_HIGHLABEL,vi,NULL}; 		/* up arrow for 2nd*/
	struct NewGadget pos2	 ={300, 90, 40,14,"_TO MC"  ,&TOPAZ80, 6,PLACETEXT_ABOVE|NG_HIGHLABEL,vi,NULL}; 		/* down arrow for 2nd */
	struct NewGadget ok 	 ={ 40,117, 80,14,"_OK"     ,&TOPAZ80, 7,PLACETEXT_IN   ,vi,NULL};		/* OK gad */
	struct NewGadget cancel	 ={520,117, 80,14,"_CANCEL" ,&TOPAZ80, 8,PLACETEXT_IN   ,vi,NULL}; 		/* CANCEL gad */
	struct NewGadget printq  ={278,113, 10,10,NULL      ,&TOPAZ80, 9,PLACETEXT_RIGHT,vi,NULL};		/* Draft/Letter */

	if(!(printcon=CreateContext((struct Gadget **)&printcon)))                     				leave=TRUE;
	if(!(gad=CreateGadget(TEXT_KIND,printcon,&fromATi,GTTX_Border,TRUE,TAG_DONE,0)))                                 leave=TRUE;
	if(!(gad=CreateGadget(TEXT_KIND,gad,&fromAIn,GTTX_Border,TRUE,TAG_DONE,0)))                                        leave=TRUE;
	if(!(gad=CreateGadget(TEXT_KIND,gad,&fromBTi,GTTX_Border,TRUE,TAG_DONE,0)))                                        leave=TRUE;
	if(!(gad=CreateGadget(TEXT_KIND,gad,&fromBIn,GTTX_Border,TRUE,TAG_DONE,0)))                                        leave=TRUE;
	if(!(pos1gad=CreateGadget(INTEGER_KIND,gad,&pos1,GT_Underscore,'_',GTIN_Number,current,TAG_DONE,0)))                   leave=TRUE;
	if(!(gad=CreateGadget(TEXT_KIND,pos1gad,&toATi  ,GTTX_Border,TRUE,TAG_DONE,0)))                                  leave=TRUE;
	if(!(gad=CreateGadget(TEXT_KIND,gad,&toAIn  ,GTTX_Border,TRUE,TAG_DONE,0)))                                        leave=TRUE;
	if(!(gad=CreateGadget(TEXT_KIND,gad,&toBTi  ,GTTX_Border,TRUE,TAG_DONE,0)))                                        leave=TRUE;
	if(!(gad=CreateGadget(TEXT_KIND,gad,&toBIn  ,GTTX_Border,TRUE,TAG_DONE,0)))                                        leave=TRUE;
	if(!(pos2gad=CreateGadget(INTEGER_KIND,gad,&pos2,GT_Underscore,'_',GTIN_Number,current,TAG_DONE,0)))                   leave=TRUE;
	if(!(gad=CreateGadget(BUTTON_KIND,pos2gad,&up1,TAG_DONE,0)))                                                     leave=TRUE;
	if(!(gad=CreateGadget(BUTTON_KIND,gad,&down1,TAG_DONE,0)))                                                         leave=TRUE;
	if(!(gad=CreateGadget(BUTTON_KIND,gad,&up2,TAG_DONE,0)))                                                           leave=TRUE;
	if(!(gad=CreateGadget(BUTTON_KIND,gad,&down2,TAG_DONE,0)))                                                         leave=TRUE;
	if(!(gad=CreateGadget(BUTTON_KIND,gad,&ok,GT_Underscore,'_',TAG_DONE,0)))                                          leave=TRUE;
	if(!(gad=CreateGadget(BUTTON_KIND,gad,&cancel,GT_Underscore,'_',TAG_DONE,0)))                                      leave=TRUE;
	if(!(gad=CreateGadget(MX_KIND,gad,&printq,GTMX_Labels,Quality,GTMX_Spacing,4,GT_Underscore,'_',TAG_DONE,0)))       leave=TRUE;
	if(leave==TRUE){
		usermessage("Trouble while creating gadgets");
		FreeGadgets(printcon);
		return(0);
        }
       	printwintag[6].ti_Data = printcon;
	if(!(printwin=OpenWindowTagList(NULL,printwintag))){
		usermessage("Clould not open print window!");
		return(0);}
	DrawBevelBox(printwin->RPort,10,15,620,44,GTBB_Recessed,TRUE,GT_VisualInfo,vi);
	DrawBevelBox(printwin->RPort,10,65,620,44,GTBB_Recessed,TRUE,GT_VisualInfo,vi);
	UpdatePGads(1,0);
	UpdatePGads(2,1);
	leave=FALSE;
	while(leave==FALSE){
		Wait(1<<printwin->UserPort->mp_SigBit);
		while(message = GT_GetIMsg(printwin->UserPort)){
			if( message->Class==IDCMP_GADGETUP){
				switch( ((struct Gadget *)message->IAddress)->GadgetID ){
				case 1:	UpdatePGads(frommc-1,0);
					break;
				case 2:	UpdatePGads(frommc+1,0);
					break;
				case 3:	UpdatePGads(tomc-1  ,1);
					break;
				case 4:	UpdatePGads(tomc+1  ,1);
					break;
				case 5: if(frommc>tomc) tomc=frommc;
					UpdatePGads(((struct StringInfo *)pos1gad->SpecialInfo)->LongInt,0);
					break;
				case 6:	if(tomc<frommc) frommc=tomc;
					UpdatePGads(((struct StringInfo *)pos2gad->SpecialInfo)->LongInt,1);
					break;
				case 7:	PrintOut(frommc,tomc,PMode);
					break;
				case 8:	leave=TRUE;	/* cancel */
					break;
				case 9:	PMode=!PMode;
					break;
                                } /* Switch */
                        } /* Gadgetup */
			if( message->Class==IDCMP_RAWKEY)
				switch(message->Code){
					case	CURSORRIGHT:
							if(message->Qualifier & SHIFTKEYS) UpdatePGads(tomc+1,1);
							else	UpdatePGads(frommc+1,0);
							break;
					case	CURSORLEFT:
							if(message->Qualifier & SHIFTKEYS) UpdatePGads(tomc-1,1);
							else	UpdatePGads(frommc-1,0);
							break;
					case    RAW_F:	ActivateGadget( pos1gad , printwin , NULL);
							break;
                			case	RAW_T:	ActivateGadget( pos2gad , printwin , NULL);
							break;
					case	RAW_D:  PMode=DRAFT;
							GT_SetGadgetAttrs(gad,printwin,NULL,GTMX_Active,PMode,TAG_DONE,0);
							break;
					case	RAW_L:	PMode=LQ;
							GT_SetGadgetAttrs(gad,printwin,NULL,GTMX_Active,PMode,TAG_DONE,0);
							break;
					case	RAW_O:	PrintOut(frommc,tomc,PMode);
	        	                  		break;
                                	case	RAW_C:	leave=TRUE;
                                                        break;
				} /* switch Code */
			if( message->Class==IDCMP_CLOSEWINDOW )	leave=TRUE;
			GT_ReplyIMsg((struct IntuiMessage *)message);
		} /* 1st while */
	} /* 2nd while */
	CloseWindow(printwin);
	FreeGadgets(printcon);
}

VOID
UpdatePGads(WORD new, x)		/* Set new strings in Interpret/LPTitle gadgets of the printwindow */
{
	if(new>=1 && new<=LastNode){
		if(x==0){
			frommc=new;
			if(new >tomc) UpdatePGads(new ,1);
			GT_SetGadgetAttrs(pos1gad,printwin,NULL,GTIN_Number,frommc,TAG_DONE,0);
			GT_SetGadgetAttrs(printcon->NextGadget						,printwin,NULL,GTTX_Text,cass[frommc].Name[1 ],TAG_DONE);
			GT_SetGadgetAttrs(printcon->NextGadget->NextGadget				,printwin,NULL,GTTX_Text,cass[frommc].Name[0 ],TAG_DONE);
			GT_SetGadgetAttrs(printcon->NextGadget->NextGadget->NextGadget			,printwin,NULL,GTTX_Text,cass[frommc].Name[16],TAG_DONE);
			GT_SetGadgetAttrs(printcon->NextGadget->NextGadget->NextGadget->NextGadget	,printwin,NULL,GTTX_Text,cass[frommc].Name[15],TAG_DONE);
		} else if(x==1){
			tomc=new;
			if(new <frommc) UpdatePGads(new ,0);
			GT_SetGadgetAttrs(pos2gad,printwin,NULL,GTIN_Number,tomc,TAG_DONE,0);
			GT_SetGadgetAttrs(pos1gad->NextGadget						,printwin,NULL,GTTX_Text,cass[tomc].Name[1 ],TAG_DONE);
			GT_SetGadgetAttrs(pos1gad->NextGadget->NextGadget				,printwin,NULL,GTTX_Text,cass[tomc].Name[0 ],TAG_DONE);
			GT_SetGadgetAttrs(pos1gad->NextGadget->NextGadget->NextGadget			,printwin,NULL,GTTX_Text,cass[tomc].Name[16],TAG_DONE);
			GT_SetGadgetAttrs(pos1gad->NextGadget->NextGadget->NextGadget->NextGadget	,printwin,NULL,GTTX_Text,cass[tomc].Name[15],TAG_DONE);
		}
	}
}

BOOL
RequestMyFile( UWORD Mode )					/* Get file/dir from the aslrequester */
{
	AslTag[1].ti_Data = window;
	AslTag[6].ti_Data = (screen->Width  - ASLWIDTH )/2;
	AslTag[7].ti_Data = (screen->Height - ASLHEIGHT)/2;

	if(!(filerequester=(struct FileRequester *)AllocAslRequest(ASL_FileRequest,AslTag))){
		usermessage("Asl Request failed!\n");
                return(FALSE);
        }
	if(Mode==FRQ_LOAD){
		AslTag[0].ti_Data=(ULONG)"LOAD";
		AslTag[2].ti_Data=(ULONG)"Load new data set";
		AslTag[3].ti_Data=FILF_PATGAD;
	} else
	{
		AslTag[0].ti_Data=(ULONG)"SAVE";
		AslTag[2].ti_Data=(ULONG)"Save this data set";
		AslTag[3].ti_Data=FILF_PATGAD|FILF_SAVE;
	}
	if(AslRequest(filerequester,AslTag)) return(TRUE);
	return(FALSE);
}

VOID
GetIDCMP()					/* Recieve IDCMP of mainwin and answer */
{
	struct	MenuItem *mi;
	WORD	id,i=0;
	UWORD	code, quali, class;

	FOREVER{
		Wait(1<<window->UserPort->mp_SigBit);
		while( message = GT_GetIMsg(window->UserPort) ){
			class=message->Class;
			code =message->Code;
			quali=message->Qualifier;
			switch(class){
				case IDCMP_MENUPICK:
					if(mi= (struct MenuItem*)ItemAddress(menu,message->Code))
					GetMenu((UWORD)GTMENUITEM_USERDATA(mi));
					break;
				case IDCMP_MOUSEBUTTONS:	/* Screen to back when clicked in upper line */
                              		if( (screen->MouseY==0) ) ScreenToBack(screen);
                              		break;
				case IDCMP_GADGETUP:
					gad=(struct Gadget*)message->IAddress;
					id=gad->GadgetID;
					switch(id){
						case 31:	ChangeCurrent( ((struct StringInfo *)gad->SpecialInfo)->LongInt );	/* The Number-Gadget */
								break;
						case 40:	cass[current].NR[0]=code;
								break;
						case 41:	cass[current].NR[1]=code;
								break;
						case 42:	cass[current].Source[0]=code;
								break;
						case 43:	cass[current].Source[1]=code;
								break;
						case 44:	ChangeCurrent(current+1);
								break;
						case 45:	ChangeCurrent(current-1);
								break;
						case 50:	ChangeCurrent(code+1);
								break;
						default:	if(id>29) break;					/* the following is only for the strgads */
								fastexit=FALSE;						/* Data has been edited => ask for quit */
								if(id==0 || id==1 || id==15 || id==16){			/* Clicked in the title bar */
									UpdateNodeName(current);			/* correct the labellist */
									if( (current==LastNode+1) && (strlen( si[id].Buffer ) >0) ) AddNode(LEntry[current].LabelName);		/* New MC! */
									GT_SetGadgetAttrs(listviewgad,window,NULL,GTLV_Labels,&LabelList,GTLV_Top,current-1,TAG_DONE,0); /* List starts at zero => -1 */
								}
								if(quali & SHIFTKEYS){					/* filter all SHIFT+RETURNS */
									if( (id==0) & (current>0) ){			/* Previous cass */
										ChangeCurrent(current-1);
										ActivateGadget(&StrGad[29],window,NULL);
										break;
									}
									ActivateGadget(&StrGad[id-1],window,NULL);	/* Previous StrGads */
									break;
								}
								if( quali & ALTKEYS  ) break;  				/* Exit the strgads! */
								if(id==29){
									ChangeCurrent(current+1);			/* Last String + RETURN */
									ActivateGadget(&StrGad[0],window,NULL);
									break;
								}
								ActivateGadget(gad->NextGadget,window,NULL);		/* Activate Next Str Gad */
								break;
					}
				case IDCMP_RAWKEY:	i=1;
							if(quali & SHIFTKEYS ) i=5;
							if(quali & ALTKEYS   ) i=10;
							if(code ==CURSORLEFT ){
								ChangeCurrent(current-i);
								break;
							}
							if(code ==CURSORRIGHT){
								ChangeCurrent(current+i);
								break;
							}
							break;
			} /* switch class */
			GT_ReplyIMsg((struct IntuiMessage *)message);
		} /* whille message ... */
	} /* FOREVER */
}

WORD
Search( STRPTR name, UWORD Mode )		/* Searches for any thing and set current to found */
{
	WORD	start, j, i, found=-1;		/* Startnumber, MC number, stringnumber and Pos of found string */
	UBYTE	dest[256];

	if( ParsePatternNoCase(name,dest,256)==-1 ){
		easyerror.es_TextFormat="Error in search pattern!";
		EasyRequest(window,&easyerror,NULL,NULL);
		return(0);
	}

	if( Mode & TOP_SEARCH  )	start=1;
	else				start=current+1;

	for( j=start ; j<=LastNode ; j++ ){
		for( i=0 ; i<30 ; i++ ){
			if( Mode & SEARCH_INTER ){
				if( (i==0) || (i==15) )	if(MatchPatternNoCase(dest,cass[j].Name[i]) == TRUE ){
								found=j;
								goto gotit;
							}
			}
			if(Mode&SEARCH_LP){
				if( (i==1) || (i==16) ) if(MatchPatternNoCase(dest,cass[j].Name[i]) == TRUE ){
								found=j;
								goto gotit;
							}
			}
			if(Mode&SEARCH_SONG){
				if( ((i>1) && (i<15)) || ((i>16) && (i<30)) )	if(MatchPatternNoCase(dest,cass[j].Name[i]) == TRUE ){
											found=j;
											goto gotit;
										}
			}
		} /* end for i */
	} /* end for j */
gotit:
	if(found==-1) {
		easyfound.es_TextFormat=(UBYTE *)"Could not find anything matching with:\n'%s'";
		EasyRequest(window,&easyfound,NULL,name);
	} else
	{
		STRPTR Side="A";
		WORD line;

		ChangeCurrent(found);					/* Jump to new MC */
		line=i+1;
		easyfound.es_TextFormat  ="Found '%s'\non MC %ld, side %s, line %ld\n";
		if(line>14){
			Side=(STRPTR)"B";
			line-=15;
		}
		EasyRequest( window,&easyfound,NULL,cass[j].Name[i],j,Side,line );
	}
}

VOID
GetMenu(UWORD n)					/* Answers the MENU_PICK message */
{
	BOOL	leave=FALSE;
	WORD	found=FALSE;
	UWORD	SMode , column;

	switch(n){
	case MENU_PROJ_LOAD:
		if(Load(NULL)==OPEN_ERR){
			easyerror.es_TextFormat="I had some trouble while\nloading '%s'!!\n";
			EasyRequest(window,&easyerror,NULL,filerequester->rf_File);
		}
		break;
	case MENU_PROJ_SAVE:
		if(Save(NULL)==OPEN_ERR){
			easyerror.es_TextFormat="I had some trouble while\nsaving '%s'!!\n";
			EasyRequest(window,&easyerror,NULL,filerequester->rf_File);
		}
		break;
	case MENU_PROJ_ABOUT:
		EasyRequest(window,&easyabout,NULL,NULL);
		break;
	case MENU_PROJ_INFO:
                struct	Preferences *prefs = NULL;
		STRPTR	pname = "unknown";

		prefs=(struct Perferences *)AllocMem( sizeof(struct Preferences) , NULL );
		if( prefs ){
			GetPrefs( prefs, sizeof(struct Preferences ) );
			pname = prefs->PrinterFilename;
			EasyRequest( window,&easyinfo,NULL,(APTR)LastNode,(APTR)MaxCass,(APTR)AvailMem(MEMF_CHIP),(APTR)AvailMem(MEMF_FAST) , pname );
			FreeMem( prefs , sizeof(struct Preferences) );
		}
		break;
	case MENU_PROJ_PRINT:
		Print();
		break;
	case MENU_PROJ_DELETE:
		if( (current>0) && (EasyRequest( window , &easydelete , NULL , (APTR)current , cass[current].Name[0],cass[current].Name[1],cass[current].Name[15],cass[current].Name[16])==1)) RemoveCurrentNode();
		break;
	case MENU_PROJ_QUIT:
		if(fastexit==TRUE) quit(NULL);
		if(EasyRequest(window,&easyquit,NULL,NULL)) quit(NULL);
		break;
	case MENU_LIST_INTER:
	case MENU_LIST_LP:
	case MENU_LIST_SONG:
		struct	Window *msgwin;			/* temp win, which carries the "Sorting..." message */
		UBYTE	entryname[80];
		WORD	i,next=-1,top=0;

		struct	NewGadget	listsortgad	= { (screen->Width)-150		, 30 , 100 , 15 			, "_SORT"	, &TOPAZ80 , 1 , PLACETEXT_IN , vi , NULL};
		struct	NewGadget	listVgad	= { ((screen->Width)-(screen->Width-20))/2	, 60 , screen->Width-40 , (screen->Height)-65 	, "List View"	, &TOPAZ80 , 2 , PLACETEXT_ABOVE , vi , NULL};
		struct	NewGadget	listexitgad	= { 50                 		, 30 , 100 , 15 			, "_EXIT"      	, &TOPAZ80 , 0 , PLACETEXT_IN , vi , NULL};
		struct	NewGadget	listprintgad	= { ((screen->Width)-100)/2	, 30 , 100 , 15 			, "_PRINT!"  	, &TOPAZ80 , 3 , PLACETEXT_IN , vi , NULL};
		struct	Gadget		*listcon;

		strcpy(uname[29],"Listing of all ");
		strcat(uname[29], what[n-MENU_LIST_BASE] );
                listwintag[0].ti_Data=uname[29];
		CreateList(n);

		column = (( screen->Width - 16 -20 -6)/8 - 10)/2;
		if( n == MENU_LIST_SONG ) column = (( screen->Width - 16 -20 -6)/8 - 10)/3;
		switch(n){
			case MENU_LIST_INTER:
				strcpy( uname[10] , fitstring( "Interpret's Name" , column ));
				strcpy( uname[11] , fitstring( "Album Name"       , column ));
				sprintf( uname[20] , "%s %s  MC     ", uname[10] , uname[11]);
				listVgad.ng_GadgetText= uname[20];
				break;
			case MENU_LIST_LP:
				strcpy( uname[10] , fitstring( "Album Name" 		, column ));
				strcpy( uname[11] , fitstring( "Interpret's Name"       , column ));
				sprintf( uname[20] , "%s %s  MC     ", uname[10] , uname[11]);
				listVgad.ng_GadgetText= uname[20];
				break;
			case MENU_LIST_SONG:
				strcpy( uname[10] , fitstring( "Song Name"		, column ));
				strcpy( uname[11] , fitstring( "Interpret's Name"       , column ));
				strcpy( uname[12] , fitstring( "Album Name" 		, column ));
				sprintf( uname[20] , "%s %s %s MC     ", uname[10] , uname[11] , uname[12] );
				listVgad.ng_GadgetText= uname[20];
				break;
		}
		leave=FALSE;
		if(!(gad=CreateContext((struct Gadget **)&listcon))) leave=TRUE;
		if(!(gad=CreateGadget(BUTTON_KIND  ,gad,&listexitgad	,GT_Underscore,'_'	,TAG_DONE))) leave=TRUE;
		if(!(gad=CreateGadget(BUTTON_KIND  ,gad,&listprintgad	,GT_Underscore,'_'	,TAG_DONE))) leave=TRUE;
		if(!(gad=CreateGadget(BUTTON_KIND  ,gad,&listsortgad	,GT_Underscore,'_'	,TAG_DONE))) leave=TRUE;
		if(!(gad=CreateGadget(LISTVIEW_KIND,gad,&listVgad	,GTLV_Labels,&LabelList	,TAG_DONE))) leave=TRUE;
		if(leave==TRUE){
			usermessage("Could not create Gadgets for ListWin!");
                        FreeGadgets(listcon);
                        return;
		}
		listwintag[3].ti_Data=listcon;
		if(!(listwin=OpenWindowTagList(NULL,listwintag))){
			usermessage("Can't open listwindow!");
			RemakeList();
			FreeGadgets(listcon);
			break;
		}
		GT_SetGadgetAttrs(gad,listwin,NULL,TAG_DONE,0);			/* Refresh Gadget! */
		DrawBevelBox(listwin->RPort,gad->LeftEdge,gad->TopEdge,gad->Width - 16 ,gad->Height,GT_VisualInfo,vi,TAG_DONE,0);
		DrawBevelBox(listwin->RPort,gad->LeftEdge+gad->Width-16,gad->TopEdge, 16 ,gad->Height-16,GT_VisualInfo,vi,TAG_DONE,0);
		leave=FALSE;
		while(leave==FALSE){
			Wait(1<<listwin->UserPort->mp_SigBit);
			while(message=GT_GetIMsg(listwin->UserPort)){
				switch(message->Class){
				case IDCMP_GADGETUP:
					switch( (((struct Gadget *)message->IAddress))->GadgetID){
					case	0:	leave=TRUE;
							break;
					case	1:	msgwin=OpenWindowTags(NULL,
								WA_Left,	(screen->Width-250)/2,
								WA_Top,		15,
								WA_Width,	250,
								WA_Height,	11,
								WA_Title,	"Sorting all entries",
								WA_CustomScreen,screen,
								TAG_DONE,0);
							GT_SetGadgetAttrs(gad,listwin,NULL,GTLV_Labels,NULL,TAG_DONE,0);
							QuickSort(1,LastNode);
							GT_SetGadgetAttrs(gad,listwin,NULL,GTLV_Labels,&LabelList,TAG_DONE,0);
							if(msgwin) CloseWindow(msgwin);
							break;
					case	2:	leave=TRUE;
							strcpy( uname[1] , (STRPTR)&LEntry[message->Code+1].LabelName[ strlen( LEntry[message->Code+1].LabelName)- 3 ] );
							next=atoi(uname[1]);
							break;
					case	3:	PrintList(n); /* send, which type of list is displayed */
							break;
                                        } /* end of id switch */
					break;
				case IDCMP_VANILLAKEY:
					if(message->Code=='s'){
						msgwin=OpenWindowTags(NULL,
							WA_Left,	(screen->Width - 250)/2,
							WA_Top,		15,
							WA_Width,	250,
							WA_Height,	11,
							WA_Title,	"Sorting all entries",
							WA_CustomScreen,screen,
							TAG_DONE,0);
						GT_SetGadgetAttrs(gad,listwin,NULL,GTLV_Labels,NULL,TAG_DONE,0);
						QuickSort(1,LastNode);
						GT_SetGadgetAttrs(gad,listwin,NULL,GTLV_Labels,&LabelList,TAG_DONE,0);
						if(msgwin) CloseWindow(msgwin);
					}
					if(message->Code=='e') leave=TRUE;
					if(message->Code=='p') PrintList(n);
					break;
				case IDCMP_CLOSEWINDOW:
					leave=TRUE;
					break;
	                        } /* End switch Class */
				GT_ReplyIMsg((struct IntuiMessage *)message);
			} /* 1st while */
		} /* 2nd while */
		CloseWindow(listwin);
		FreeGadgets(listcon);
		RemakeList();
		if(next!=-1) ChangeCurrent(next);
		break;	/* END OF LIST PART */
	case MENU_SEARCH_INTER:
	case MENU_SEARCH_LP:
	case MENU_SEARCH_SONG:
	case MENU_SEARCH_ANYTHING:
		struct Gadget	 *searchcon;
		struct NewGadget searchtxtgad	= {(SREQ_WIDTH-300)/2 , 50             , 300  , 14 , "_Search for..."     , &TOPAZ80 , 0 , PLACETEXT_ABOVE , vi , NULL};
		struct NewGadget searchtopgad	= {20                 , SREQ_HEIGHT-50 , 120  , 20 , "Start at _first"    , &TOPAZ80 , 1 , PLACETEXT_IN    , vi , NULL};
		struct NewGadget searchnextgad	= {SREQ_WIDTH-140     , SREQ_HEIGHT-50 , 120  , 20 , "Search _next"       , &TOPAZ80 , 2 , PLACETEXT_IN    , vi , NULL};
		struct NewGadget searchexitgad	= {(SREQ_WIDTH-80)/2  , SREQ_HEIGHT-50 ,  80  , 20 , "_EXIT"              , &TOPAZ80 , 3 , PLACETEXT_IN    , vi , NULL};
                SMode=n-MENU_SEARCH_BASE;
		switch(n){
			case MENU_SEARCH_INTER:		searchtxtgad.ng_GadgetText="_Search for interpret's name";
							strcpy(uname[0],cass[current].Name[0]);
							break;
			case MENU_SEARCH_LP:		searchtxtgad.ng_GadgetText="_Search for a LP title:";
							strcpy(uname[0],cass[current].Name[1]);
							break;
			case MENU_SEARCH_SONG:		searchtxtgad.ng_GadgetText="_Search for song name:";
							strcpy(uname[0],cass[current].Name[2]);
				 			break;
			case MENU_SEARCH_ANYTHING:	searchtxtgad.ng_GadgetText="_Search for any occurance of:";
							strcpy(uname[0],cass[current].Name[0]);
				 			break;
		}
		leave=FALSE;
		if(!(gad=CreateContext((struct Gadget **)&searchcon))) leave=TRUE;
		if(!(gad=CreateGadget( BUTTON_KIND , gad , &searchtopgad  , GT_Underscore , '_' , TAG_DONE))) leave=TRUE;
		if(!(gad=CreateGadget( BUTTON_KIND , gad , &searchnextgad , GT_Underscore , '_' , TAG_DONE))) leave=TRUE;
		if(!(gad=CreateGadget( BUTTON_KIND , gad , &searchexitgad , GT_Underscore , '_' , TAG_DONE))) leave=TRUE;
		if(!(gad=CreateGadget( STRING_KIND , gad , &searchtxtgad  , GT_Underscore , '_' , GTST_String , uname[0] , TAG_DONE))) leave=TRUE;
		if(leave==TRUE){
			usermessage("Could not create gadgets for search window!");
                        FreeGadgets(searchcon);
                        return;
		}
		searchwintag[7].ti_Data = searchcon;
		if(!(searchwin=(struct Window *)OpenWindowTagList(NULL,searchwintag))){
			usermessage("Could not open search requester!");
			FreeGadgets(searchcon);
			break;}
		ActivateGadget(gad,searchwin,NULL);			/* Activate string Gadget */
		leave=FALSE;
		while(leave==FALSE){
			Wait(1<<searchwin->UserPort->mp_SigBit);
			while(message=(struct IntuiMessage *)GT_GetIMsg(searchwin->UserPort)){
                                switch(message->Class){
				case	IDCMP_GADGETUP:		/* exit of strgad with return or! searchgadget clicked*/
					switch( (((struct Gadget *)message->IAddress))->GadgetID ){
						case	1:	Search(((STRPTR)((struct StringInfo *)(gad->SpecialInfo))->Buffer),SMode|TOP_SEARCH);
								break;
						case	2:	Search(((STRPTR)((struct StringInfo *)(gad->SpecialInfo))->Buffer),SMode|NEXT_SEARCH);
								break;
                                	        case	3:	leave=TRUE;
                                        			break;} /* end switch ID*/
	                                break;
				case	IDCMP_CLOSEWINDOW:
					leave=TRUE;
                                        break;
				case	IDCMP_VANILLAKEY:
					if(message->Code=='f')	Search(((STRPTR)((struct StringInfo *)(gad->SpecialInfo))->Buffer),SMode|TOP_SEARCH);
					if(message->Code=='n')	Search(((STRPTR)((struct StringInfo *)(gad->SpecialInfo))->Buffer),SMode|NEXT_SEARCH);
					if(message->Code=='s')	ActivateGadget(gad,searchwin,NULL);			/* Activate string Gadget */
					if(message->Code=='e')	leave=TRUE;
                                	break;
                                } /* End IDCMP switch */
				GT_ReplyIMsg((struct IntuiMessage *)message);
			} /* 1st while */
		} /* 2nd while */
		CloseWindow(searchwin);
		FreeGadgets(searchcon);
		break;
	case MENU_SPECIAL_NAME:
		struct Gadget	 *namecon,*g1,*g2,*g3;
		struct NewGadget name1gad	= {50 , 20 , 300 , 14 ,NULL, &TOPAZ80 , 0 , NULL , vi , NULL};
		struct NewGadget name2gad	= {50 , 40 , 300 , 14 ,NULL, &TOPAZ80 , 1 , NULL , vi , NULL};
		struct NewGadget name3gad	= {50 , 60 , 300 , 14 ,NULL, &TOPAZ80 , 2 , NULL , vi , NULL};
		struct NewGadget nameexitgad	= {150, 80 , 100 , 14 ,"OK", &TOPAZ80 , 3 , PLACETEXT_IN , vi , NULL};

		leave=FALSE;
		if(!(gad=CreateContext((struct Gadget **)&namecon))) leave=TRUE;	/* Create the Gadget context */
		if(!(g1= CreateGadget( STRING_KIND , gad , &name1gad     , GTST_String , ownername[0] , TAG_DONE ))) leave=TRUE;
		if(!(g2= CreateGadget( STRING_KIND , g1  , &name2gad     , GTST_String , ownername[1] , TAG_DONE ))) leave=TRUE;
		if(!(g3= CreateGadget( STRING_KIND , g2  , &name3gad     , GTST_String , ownername[2] , TAG_DONE ))) leave=TRUE;
		if(!(gad=CreateGadget( BUTTON_KIND , g3  , &nameexitgad  , GT_Underscore , '_' , TAG_DONE )))	leave=TRUE;
		if(leave==TRUE){
			usermessage("Can't create gadgets for namewindow");
			FreeGadgets(namecon);
			return;
                }
		namewintag[7].ti_Data = namecon;
		if(!(namewin=OpenWindowTagList(NULL,namewintag))){
			usermessage("Could not open name requester!");
			FreeGadgets(namecon);
			break;}
		leave=FALSE;
		ActivateGadget(g1,namewin,NULL);		/* Activate string Gadget */
		while(leave==FALSE){
			Wait(1<<namewin->UserPort->mp_SigBit);
			while(message=GT_GetIMsg(namewin->UserPort)){
				if( (message->Class)==IDCMP_GADGETUP ){
					switch((((struct Gadget *)message->IAddress))->GadgetID){
						case 0:
						case 1:	ActivateGadget(((struct Gadget *)message->IAddress)->NextGadget,namewin,NULL);
							break;
						case 2:	ActivateGadget(g1,namewin,NULL);
							break;
						case 3:	leave=TRUE;
							break;} /* End of Switch */
				} /* if */
				if( message->Class==CLOSEWINDOW ) leave=TRUE;
				GT_ReplyIMsg((struct IntuiMessage *)message);
			} /* 1st while */
		} /* 2nd while */
		strcpy(ownername[0],((struct StringInfo *)(g1->SpecialInfo))->Buffer);
		strcpy(ownername[1],((struct StringInfo *)(g2->SpecialInfo))->Buffer);
		strcpy(ownername[2],((struct StringInfo *)(g3->SpecialInfo))->Buffer);
		CloseWindow(namewin);
		FreeGadgets(namecon);
		break;
	case MENU_SPECIAL_EDIT:
		ActivateGadget(&StrGad[0],window,NULL);
		break;
	case MENU_SPECIAL_PALETTE:
		Palette();
		break;
	} /* end switch */
}

VOID
CreateList(ULONG Mode)
{
	UWORD column;
	WORD j=1,i,k=1,l=1,m=0;
        struct Window *msgwin;				/* this window will tell you, that I am creatin the list */

	msgwin=OpenWindowTags(NULL, WA_Title,"Creating List...",
		WA_Left		,(screen->Width-200)/2,
		WA_Top		,(screen->Height-10)/2,
		WA_Width	,200,
		WA_Height	,10,
		WA_CustomScreen	,screen,
		TAG_END);
	GT_SetGadgetAttrs(listviewgad,window,NULL,GTLV_Labels,NULL,TAG_DONE,0); /* Remove current List from Gadget */
	InitList();

	column = (( screen->Width - 16 -20 -6)/8 - 10)/2;
	if( Mode == MENU_LIST_SONG ) column = (( screen->Width - 16 -20 -6)/8 - 10)/3;

	while( strlen(cass[j].Name[0])!=0 ){
		switch(Mode){
		case MENU_LIST_INTER:
			strcpy( uname[10] , fitstring( cass[j].Name[0]  , column ) );
			strcpy( uname[11] , fitstring( cass[j].Name[1]  , column ) );
			sprintf(LEntry[k].LabelName,"%-s %-s %3d",uname[10],uname[11], j );
			AddNode(LEntry[k++].LabelName);

			strcpy( uname[10] , fitstring( cass[j].Name[15] , column ) );
			strcpy( uname[11] , fitstring( cass[j].Name[16] , column ) );
			sprintf(LEntry[k].LabelName,"%-s %-s %3d",uname[10],uname[11], j);
			AddNode(LEntry[k].LabelName);
			k++;	/* For the Label index */
			break;
		case MENU_LIST_LP:
			strcpy( uname[10] , fitstring( cass[j].Name[1]  , column ) );
			strcpy( uname[11] , fitstring( cass[j].Name[0]  , column ) );
			sprintf(LEntry[k].LabelName,"%-s %-s %3d",uname[10],uname[11], j );
			AddNode(LEntry[k++].LabelName);

			strcpy( uname[10] , fitstring( cass[j].Name[16] , column ) );
			strcpy( uname[11] , fitstring( cass[j].Name[15] , column ) );
			sprintf(LEntry[k].LabelName,"%-s %-s %3d",uname[10],uname[11], j);
			AddNode(LEntry[k].LabelName);
			k++;	/* For the Label index */
			break;
		case MENU_LIST_SONG:
			for(m=2;m<30;m++){
				if( strlen(cass[j].Name[m])==0 || m==15 || m==16) continue;
				strcpy(uname[0], fitstring( cass[j].Name[m] , column ));		/* Songname */
				strcpy(uname[1], fitstring( cass[j].Name[0] , column ));		/* Side A Inter */
				strcpy(uname[2], fitstring( cass[j].Name[1] , column ));		/* Album */
				if(m>15){
					strcpy(uname[1], fitstring( cass[j].Name[15] , column ));	/* Side B Inter */
					strcpy(uname[2], fitstring( cass[j].Name[16] , column ));	/* Album */
				}
				sprintf(LEntry[k].LabelName,"%s %s %s %3d",uname[0],uname[1],uname[2], j);
				AddNode(LEntry[k++].LabelName);	/* Increase Label index */
			} /* end while */
			break;
		} /* end switch */
		if(j>MAXNODES) break;		/* Safety test for eternal loops*/
		j++;	/* For the MC index */

	} /* end while */
        if(msgwin) CloseWindow(msgwin);
}

VOID
QuickSort(REGISTER WORD start, end)			/* Recursive sort algorithm, very effective */
{
	REGISTER WORD m,l,r;
	REGISTER UBYTE	v[MAXLCHARS], hilf[MAXLCHARS];

	if(start<end)
	{
		m=(start+end)/2;
		strcpy(v,LEntry[m].LabelName);
		l=start;
		r=end;
		while(l<=r){
			while( Stricmp(LEntry[l].LabelName,v) <0 ) l++;
			while( Stricmp(LEntry[r].LabelName,v) >0 ) r--;
			if(l<=r){
				strcpy(hilf         , LEntry[r].LabelName);
				strcpy(LEntry[r].LabelName, LEntry[l].LabelName);
				strcpy(LEntry[l].LabelName, hilf);
				r--;
				l++;
			}
		}
		QuickSort(start,r  );
		QuickSort(l    ,end);
	}
}

VOID
RemakeList( VOID )				/* Remake the ListViewgadget's List after overriding it with the ListList */
{
	InitList();
	UpdateList();
	GT_SetGadgetAttrs(listviewgad,window,NULL,GTLV_Labels,&LabelList,TAG_DONE);
}

VOID
UpdateNodeName(WORD n)	/* Remake the Nodestring of an MC */
{
	strcpy( uname[10] , fitstring( cass[n].Name[0]  , (screen->Width - 40)/8/4-1 ) );
	strcpy( uname[11] , fitstring( cass[n].Name[1]  , (screen->Width - 40)/8/4-2 ) );
	strcpy( uname[12] , fitstring( cass[n].Name[15] , (screen->Width - 40)/8/4-1 ) );
	strcpy( uname[13] , fitstring( cass[n].Name[16] , (screen->Width - 40)/8/4-2 ) );

	sprintf( LEntry[n].LabelName , "A: %s %s  B: %s %s" , uname[10] , uname[11] , uname[12] , uname[13] );
}

VOID
RemoveCurrentNode( VOID )			/* Delete the Current Node and adjust the list pointers */
{
	WORD j,i;

	if(LastNode<2) return;

	for(j=current ; j<LastNode ; j++)
        {
		for(i=0; i<30; i++)	strcpy( cass[j].Name[i] , cass[j+1].Name[i] );
		cass[j+1].NR[0]=cass[j].NR[0];
		cass[j+1].NR[1]=cass[j].NR[1];
		cass[j+1].Source[0]=cass[j].Source[0];
		cass[j+1].Source[1]=cass[j].Source[1];
        }

	LastNode--;						/* Decrement LastNode */
	LEntry[LastNode].Label.ln_Succ = &TailNode;
	TailNode.ln_Pred 	= &LEntry[LastNode].Label;
        LabelList.lh_TailPred	= &LEntry[LastNode].Label;

	RefreshGads(current);
	UpdateList();
	GT_SetGadgetAttrs(listviewgad,window,NULL,GTLV_Labels,&LabelList,TAG_DONE,0);
}

VOID
wbmain(struct WBStartup* wbmsg)
{
	UBYTE tt[80];
        BPTR old,new;

	if(!(IconBase=(struct IconBase*)OpenLibrary("icon.library",0)))			exit(0);
	if(!(UtilityBase=(struct UtilityBase*)OpenLibrary("utility.library",37)))	exit(0);

	strcpy (myname, wbmsg->sm_ArgList->wa_Name);
	if(!(new=DupLock( wbmsg->sm_ArgList->wa_Lock)))		exit(0);
        old=CurrentDir(new);
	mydob = GetDiskObjectNew(myname);
	CurrentDir(old);
	UnLock(new);

	strcpy( tt , FindToolType((mydob->do_ToolTypes),"DISPLAYID") );
	if( strlen(tt) == 10)	DisplayID = ahex2ulong( tt );
	else DisplayID = HIRES_KEY;

	strcpy( tt , FindToolType((mydob->do_ToolTypes),"COLORS"));
	strncat(toolstr[1],tt,12);
	if(strlen(tt)==12){
		strcpy(Colors,tt);
        }

	strcpy( tt , FindToolType((mydob->do_ToolTypes),"DATABASE"));
	if(strlen(tt)!=0) strcpy(Database,tt);

	strcpy( tt , FindToolType((mydob->do_ToolTypes),"MAXCASS"));
        if( atoi(tt) > 0 ) MaxCass=atoi(tt);

	strcpy( tt , FindToolType((mydob->do_ToolTypes),"OSCAN"));
	Oscan=NULL;
	if( Stricmp(tt,"TEXT"    )==0)	Oscan=OSCAN_TEXT;
	if( Stricmp(tt,"STANDARD")==0)	Oscan=OSCAN_STANDARD;
	if( Stricmp(tt,"MAX"     )==0)	Oscan=OSCAN_MAX;
	if( Stricmp(tt,"VIDEO"   )==0)	Oscan=OSCAN_VIDEO;

        CurrentDir( ((struct Process *)FindTask(NULL))->pr_HomeDir );	/* set home dir */
	main(0,NULL);							/* give no parameters on a wbstart */
}

VOID
fromcli(WORD argc, STRPTR *argv)
{
        STRPTR	template = "-s/K,-f/K,-c/K,-m/K,-o/K";
	STRPTR 	args[5];
	WORD	i;

	if(!(UtilityBase=(struct UtilityBase*)OpenLibrary("utility.library",37)))	exit(0);
	if(!(cliargs=(struct RDArgs *)ReadArgs(template,args,NULL))){
		Printf("Usage:\n MCMaster %s\n [32m© 1992 by Michael Watzl[31m\n", (LONG)template );
		PutStr("\n-s  DisplayID:  Hex number in the form of 0x00000000 (look at WBStartup/mode-names!)\n");
		PutStr("\n-f  DataBase:   Path/Name of Datafile to be loaded at once\n\t\tdefault is none\n");
		PutStr("\n-c  Colors:     give 12 hexchars in the form rgbrgbrgbrgb (red, green, blue)\n                e.g. 89A002FFFEB2 (defaults)\n");
		PutStr("\n-m  MaxCass:    number of maximal needed MCs, default is 60\n\n");
		PutStr("\n-o  OverScan:   TEXT, STANDARD, MAX or VIDEO, default is no overscan\n\n");
		exit(0);
	}
	if( Stricmp(args[0],"PAL")==0 )	DisplayID=PAL;
	strcpy(Database, args[1]);
	if( strlen(args[2]) == 12 ) 	strcpy( Colors,args[2] );
	if( atoi(args[3]) !=0 ) 	MaxCass = atoi(args[3]);
        for(i=0;i<5;i++)		if( Stricmp( args[4],OscanName[i] ) == 0 ) Oscan=i;
	FreeArgs(cliargs);
}

BOOL
getmem(WORD number)
{
	if(cass=(struct MCData    *)AllocMem( sizeof(struct MCData) * (number+1)   , MEMF_CLEAR ) ){
		if( LEntry=(struct ListEntry *)AllocMem( sizeof(struct ListEntry)*number*2*13 , MEMF_CLEAR ) ){
			return(TRUE);
		}
		FreeMem(cass, sizeof(struct MCData) * number );
	}
	PutStr("Can't allocate enough memory, try to free mem, or set the maxcass value lower!\n");
	if(mydob)		FreeDiskObject(mydob);
	exit(0);
}

VOID
main(WORD argc, STRPTR *argv)
{
	BOOL leave=FALSE;
	struct DimensionInfo dim;

	if( mydob==NULL ) fromcli(argc,argv);
	if( getmem(MaxCass)==FALSE ) quit("Could not get enough memory for requested number of cassettes!");
	if(!(UtilityBase)) /* May already be opened in wbmain! */
		if(!(UtilityBase=(struct UtiltyBase *)OpenLibrary("utility.library",37L)))
			quit("Clould not open utility.library V37!\n");
	if(!(IconBase)) /* May already be opened in wbmain! */
		if(!(IconBase=(struct IconBase *)OpenLibrary("icon.library",37L)))
			quit("Clould not open icon.library V37!\n");
	if(!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",37L)))
		quit("Clould not open intuition.library V37!\n");
	if(!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",37L)))
		quit("Clould not open graphics.library V37!\n");
	if(!(GadToolsBase=(struct GadToolsBase *)OpenLibrary("gadtools.library",0L)))
		quit("Clould not open gadtools.library!\n");
	if(!(AslBase=(struct AslBase *)OpenLibrary("asl.library",37L)))
		quit("Clould not open asl.library V37!\n");

	screentag[9].ti_Data	= Oscan;
	screentag[6].ti_Data=DisplayID;

	GetDisplayInfoData( NULL , (UBYTE *)&dim , sizeof( dim ) , DTAG_DIMS , DisplayID );
	switch( Oscan ){
	case OSCAN_TEXT:
		screentag[1].ti_Data = dim.TxtOScan.MaxX+1;
		screentag[2].ti_Data = dim.TxtOScan.MaxY+1;
		break;
	case OSCAN_STANDARD:
		screentag[1].ti_Data = dim.StdOScan.MaxX+1;
		screentag[2].ti_Data = dim.StdOScan.MaxY+1;
		break;
	default:
		screentag[1].ti_Data = dim.Nominal.MaxX+1;
		screentag[2].ti_Data = dim.Nominal.MaxY+1;
		screentag[0].ti_Data = (dim.MaxOScan.MaxX - dim.Nominal.MaxX)/2;
		break;
	}

	SetScreenColors();								/* Set colors in the colorspec */

	if(!(screen=OpenScreenTagList(NULL,screentag))) quit("Can't open screen!\n");
	if(!(vi=GetVisualInfoA(screen,NULL)))		quit("Can't get visual info!\n");
	if(!(gad=CreateContext((struct Gadget **)&congad)))		/* Create the Gadget context */
		quit("Can't create context!\n");
	InitList();
	InitGads();
	InitTags();
	if(!(sourceAgad  = CreateGadget( CYCLE_KIND   , gad,&SourceA ,GTCY_Labels , Source , TAG_DONE)))		leave=TRUE;
	if(!(sourceBgad  = CreateGadget( CYCLE_KIND   , sourceAgad   ,&SourceB, GTCY_Labels , Source , TAG_DONE)))	leave=TRUE;
	if(!(noiseAgad   = CreateGadget( CYCLE_KIND   , sourceBgad   ,&DolbyA , GTCY_Labels , NR , TAG_DONE)))		leave=TRUE;
	if(!(noiseBgad   = CreateGadget( CYCLE_KIND   , noiseAgad    ,&DolbyB , GTCY_Labels , NR , TAG_DONE)))		leave=TRUE;
	if(!(listviewgad = CreateGadget( LISTVIEW_KIND, noiseBgad    ,&ListVG , GTLV_Labels , &LabelList,TAG_DONE)))	leave=TRUE;
	if(!(nextgad     = CreateGadget( BUTTON_KIND  , listviewgad  ,&Next , GA_Immediate , TRUE , TAG_DONE)))		leave=TRUE;
	if(!(prevgad     = CreateGadget( BUTTON_KIND  , nextgad      ,&Prev , GA_Immediate , TRUE , TAG_DONE)))		leave=TRUE;
	if(!(currentgad  = CreateGadget( INTEGER_KIND , prevgad      ,&Current , GTIN_Number , 1 , GTIN_MaxChars , 5 , STRINGA_Justification , GACT_STRINGCENTER , TAG_DONE)))	leave=TRUE;
	if(leave==TRUE)	quit("Error while creating gadgets for the mainwindow!");

	if(!(window = OpenWindowTags(NULL,
		WA_Flags	,WFLG_ACTIVATE|WFLG_BORDERLESS,
		WA_IDCMP	,IDCMP_CLOSEWINDOW | IDCMP_RAWKEY | LISTVIEWIDCMP | STRINGIDCMP | IDCMP_MENUPICK ,
		WA_Gadgets	,&StrGad[0],
		WA_CustomScreen	,screen,
		TAG_DONE	,0))) quit("Could not open window!\n");
	CompleteGads(&ListVG);					/* Draw some BevelBoxes */
	DrawBevelBox(window->RPort,listviewgad->LeftEdge,listviewgad->TopEdge,listviewgad->Width - 16 ,listviewgad->Height,GT_VisualInfo,vi,TAG_DONE,0);
	DrawBevelBox(window->RPort,listviewgad->LeftEdge+listviewgad->Width-16,listviewgad->TopEdge, 16 ,listviewgad->Height-16,GT_VisualInfo,vi,TAG_DONE,0);

        olderrwin = ((struct Process *)FindTask(NULL))->pr_WindowPtr;
	((struct Process *)FindTask(NULL))->pr_WindowPtr=window;

	menu=CreateMenus(MainMenu,TAG_DONE,0);
	LayoutMenus(menu,vi,TAG_DONE,0);
	SetMenuStrip(window,menu);
	if(strlen(Database)!=0) Load(Database);
	GetIDCMP();
}

WORD
Save(STRPTR startname)
{
	WORD	i,j;
	BPTR	fh;
	UBYTE	fname[128];

	AslTag[4].ti_Data=lastfname;
	AslTag[5].ti_Data=lastdname;
	if( RequestMyFile(FRQ_SAVE) == FALSE )
		return(CANCEL_ERR);
	strcpy(lastfname,filerequester->rf_File);
	strcpy(lastdname,filerequester->rf_Dir);
	strcpy(fname,filerequester->rf_Dir);
	if( (fname[strlen(fname)-1]!=':') && (fname[0]!='\0')) strcat(fname,(STRPTR)"/");
	strcat(fname,filerequester->rf_File);
	fh=Open(fname,MODE_NEWFILE);
	if(fh==DOSFALSE)	return(OPEN_ERR);
	FPutC(fh,CODE);
	for(i=0;i<3;i++){
		FPuts(fh,ownername[i]);				/* put the  ownername */
		FPutC(fh,'\n');
	}
	for(j=1;j<=LastNode;j++){				/* first to last MC */
		for(i=0;i<30;i++){
			FPuts(fh,cass[j].Name[i]);		/* put the 30 songtitles */
			FPutC(fh,'\n');
		}
		FPutC(fh,cass[j].NR[0]    +48);
		FPutC(fh,cass[j].NR[1]    +48);
		FPutC(fh,cass[j].Source[0]+48);
		FPutC(fh,cass[j].Source[1]+48);
	}
	ChangeCurrent(current);
	Close(fh);
	fastexit=TRUE;
	return(TRUE);
}

WORD
Load(STRPTR startname)
{
	WORD	i,j;
	BOOL	end=FALSE;
	BPTR	fh;
	UBYTE	modes[5];	/* for 2x N.R. and 2x Source */
	UBYTE	fname[128];	/* all stuff */

	AslTag[4].ti_Data=lastfname;			/* defaultname setzten */
	AslTag[5].ti_Data=lastdname;			/* defaultdir setzten */
	if(startname==0){
		if(!(RequestMyFile(FRQ_LOAD)))			return(CANCEL_ERR);
		strcpy(fname    ,filerequester->rf_Dir);
		strcpy(lastfname,filerequester->rf_File);
		strcpy(lastdname,filerequester->rf_Dir);
		if((fname[strlen(fname)-1]!=':') && (fname[0]!='\0')) strcat(fname,"/");
		strcat(fname,filerequester->rf_File);
        } else
        {
        	strcpy(fname,startname);
		strcpy( lastfname , FilePart(startname) );
		strncpy(lastdname , startname , strlen(startname)-strlen(FilePart(startname)) );
        }
	fh=Open(fname,MODE_OLDFILE);
	if(fh==DOSFALSE) return(OPEN_ERR);
	InitList();						/* Reset the Node struct */
	fname[0]='\0';						/* clear fname löschen-> for strncats */
	if(FGetC(fh)!=CODE)	return(FALSE);			/* Check for code */
	for(i=0;i<3;i++){
		if(FGets(fh,ownername[i],MAXCHARS)==NULL) return(FALSE);
		ownername[i][ strlen(ownername[i])-1 ]='\0';
	}
	for(j=1;j<MaxCass;j++){				/* maximal MaxCass cassettes */
		for(i=0;i<30;i++){
			if(FGets(fh,cass[j].Name[i],MAXCHARS)==NULL) end=TRUE;	/* get the 30 songtitles */
			cass[j].Name[i][ strlen(cass[j].Name[i])-1 ]='\0';
		}
		if(end==TRUE) break;
		cass[j].NR[0]=		FGetC(fh)-48;
		cass[j].NR[1]=		FGetC(fh)-48;
		cass[j].Source[0]=	FGetC(fh)-48;
		cass[j].Source[1]=	FGetC(fh)-48;
	}
	for(i=j;i<MaxCass;i++){
		cass[i].NR[0]=0;
		cass[i].NR[1]=0;
		cass[i].Source[0]=0;
		cass[i].Source[1]=0;
	}
	Close(fh);
	UpdateList();
	GT_SetGadgetAttrs(listviewgad,window,NULL,TAG_DONE,0);
	RefreshGads(1);
	fastexit=TRUE;
	return(TRUE);
}

STRPTR
itos(STRPTR string,ULONG integer)	
{
	sprintf(string,"%d",integer);
        return(string);
}

VOID
InitGads()		/* Intitialize/size the gads of the main window */
{
	int i=0;

	for(i=0;i<30;i++){
		if(i<15){
			StrGad[i].LeftEdge  = XOFFSET+2;
			StrGad[i].TopEdge   = YOFFSET+8*i;
		} else {
			StrGad[i].LeftEdge  = (screen->Width)/2+XOFFSET+2;
			StrGad[i].TopEdge   = YOFFSET+8*(i-15);
		}

		StrGad[i].Width		= (screen->Width)/2 - (StrGad[0].LeftEdge)*2;
		StrGad[i].Height	= 10;
		StrGad[i].GadgetID	= i;

		if(i!=29)	StrGad[i].NextGadget=&StrGad[i+1];
		else		StrGad[i].NextGadget=congad;

		StrGad[i].SpecialInfo=&si[i];
		si[i].Buffer    =(UBYTE *)cass[0].Name[i];
		si[i].UndoBuffer=(UBYTE *)uname[i];
	}
	StrGad[ 0].TopEdge = YOFFSET-4;
	StrGad[ 1].TopEdge = YOFFSET-4 + TOPAZ80.ta_YSize;
	StrGad[15].TopEdge = YOFFSET-4;
	StrGad[16].TopEdge = YOFFSET-4 + TOPAZ80.ta_YSize;

	ListVG.ng_VisualInfo	= vi;
	DolbyA.ng_VisualInfo	= vi;
	DolbyB.ng_VisualInfo	= vi;
	SourceA.ng_VisualInfo	= vi;
	SourceB.ng_VisualInfo	= vi;
	Next.ng_VisualInfo	= vi;
	Prev.ng_VisualInfo	= vi;
	Current.ng_VisualInfo	= vi;

	ListVG.ng_LeftEdge	= 10;
	ListVG.ng_TopEdge	= 148;
	ListVG.ng_Width		= screen->Width-2*ListVG.ng_LeftEdge;
	ListVG.ng_Height	= screen->Height-ListVG.ng_TopEdge;

	DolbyA.ng_LeftEdge	= ListVG.ng_LeftEdge;
	DolbyA.ng_TopEdge	= ListVG.ng_TopEdge-15;
	DolbyA.ng_Width		= 150;
	DolbyA.ng_Height	= 13;

	DolbyB.ng_LeftEdge	= ListVG.ng_LeftEdge+ListVG.ng_Width-DolbyA.ng_Width;
	DolbyB.ng_TopEdge 	= DolbyA.ng_TopEdge;
	DolbyB.ng_Width   	= DolbyA.ng_Width;
	DolbyB.ng_Height  	= DolbyA.ng_Height;

	Current.ng_Width   	= 40;
	Current.ng_Height  	= DolbyA.ng_Height;
	Current.ng_LeftEdge	= (screen->Width - Current.ng_Width)/2;
	Current.ng_TopEdge 	= DolbyA.ng_TopEdge;

	Next.ng_LeftEdge	= Current.ng_LeftEdge + Current.ng_Width +10 ;
	Next.ng_TopEdge 	= DolbyA.ng_TopEdge;
	Next.ng_Width		= 23;
	Next.ng_Height		= DolbyA.ng_Height;

	Prev.ng_LeftEdge	= Current.ng_LeftEdge - Next.ng_Width -10;
	Prev.ng_TopEdge 	= DolbyA.ng_TopEdge;
	Prev.ng_Width   	= Next.ng_Width;
	Prev.ng_Height  	= Next.ng_Height;

	SourceA.ng_Width   	= 85;
	SourceA.ng_Height  	= DolbyA.ng_Height;
	SourceA.ng_LeftEdge	= ( (DolbyA.ng_Width + Prev.ng_LeftEdge ) - SourceA.ng_Width + 10) / 2;
	SourceA.ng_TopEdge 	= DolbyA.ng_TopEdge;

	SourceB.ng_LeftEdge	= (Next.ng_LeftEdge+Next.ng_Width + DolbyB.ng_LeftEdge - SourceA.ng_Width )/2;
	SourceB.ng_TopEdge 	= DolbyA.ng_TopEdge;
	SourceB.ng_Width   	= SourceA.ng_Width;
	SourceB.ng_Height  	= DolbyA.ng_Height;
}

VOID
InitTags( VOID )
{
	printwintag[2].ti_Data = (screen->Width  - 640 ) /2 ;
	printwintag[3].ti_Data = (screen->Height - 140 ) / 2;
	printwintag[7].ti_Data = screen;

	namewintag[3].ti_Data = (screen->Width  - 400)/2;
	namewintag[4].ti_Data = (screen->Height - 100)/2;
	namewintag[8].ti_Data = screen;

	searchwintag[2].ti_Data = ( screen->Width  - SREQ_WIDTH )/2;
	searchwintag[3].ti_Data = ( screen->Height - SREQ_HEIGHT)/2;
	searchwintag[8].ti_Data = screen;

	listwintag[4].ti_Data=screen;
}




WORD
AddNode(STRPTR name)							/* Add Node to List */
{
	if(LastNode<MAXNODES)
	{
		LastNode++;
		LEntry[LastNode].Label.ln_Name=name;
		if(LastNode>1){
			LEntry[LastNode].Label.ln_Pred=&LEntry[LastNode-1].Label;	/* Pred to Previous */
			LEntry[LastNode-1].Label.ln_Succ=&LEntry[LastNode].Label;	/* Suc from prev to current*/
		}
		LEntry[LastNode].Label.ln_Succ = &TailNode;
		TailNode.ln_Pred 	= &LEntry[LastNode].Label;
                LabelList.lh_TailPred	= &LEntry[LastNode].Label;
	}
	return(0);
}

VOID
UpdateList( VOID )						/* Redo the List from the cass-names */
{
	WORD j=1,i;
	UBYTE fname[100];

	GT_SetGadgetAttrs(listviewgad,window,NULL,GTLV_Labels,NULL,TAG_DONE); /* Disconnect LabelList from LVG */
	InitList();
	while(strlen(cass[j].Name[0])!=0){
	                UpdateNodeName(j);				/* create string for listviewgad */
		AddNode(LEntry[j].LabelName);
		if(j>MaxCass) break;
		j++;
	}
	GT_SetGadgetAttrs(listviewgad,window,NULL,GTLV_Labels,&LabelList,TAG_DONE); /* "Reconnect Gadget and List */
}

VOID
InitList( VOID )				/* Intitialize the NodeList */
{
	LabelList.lh_Head	=&LEntry[1].Label;
        LabelList.lh_Tail	=&TailNode;
        LabelList.lh_TailPred	=NULL;
	LastNode=0;
}

WORD
quit(STRPTR errtxt)			/* print errortext, clean up and put returncode */
{
	if(errtxt) 		usermessage(errtxt);

	((struct Process *)FindTask(NULL))->pr_WindowPtr=olderrwin;

	if(mydob) 		FreeDiskObject(mydob);
	if(menu){  		ClearMenuStrip(window);
		   		FreeMenus(menu);}
	ClosePrinter();

	if(window) 		CloseWindow(window);
	if(congad) 		FreeGadgets(congad);
	if(filerequester)	FreeAslRequest(filerequester);
	if(screen) 		CloseScreen(screen);
	if(vi)     		FreeVisualInfo(vi);

	if(AslBase)		CloseLibrary(AslBase);
	if(GadToolsBase)	CloseLibrary(GadToolsBase);
	if(GfxBase)		CloseLibrary((struct Library *)GfxBase);

	if(IntuitionBase)	CloseLibrary((struct Library *)IntuitionBase);
	if(UtilityBase)		CloseLibrary(UtilityBase);

	FreeMem( cass   , sizeof(struct MCData) * (MaxCass+1) );
	FreeMem( LEntry , sizeof(struct ListEntry) * MaxCass *2 * 13);

	exit(0);
}

WORD
ChangeCurrent(WORD new)			/* Set a new current mc and assign stringbuffers,... */
{
	if(new <  1)        new=1;
	if(new > LastNode+1) new=LastNode+1;			/* Maximal one MC further */
	if(new==current) return(0);				/* Refresh only when really needed */
	RefreshGads(new);
}

WORD
RefreshGads(WORD new)				/* Assign Stringbuffers, update topentry of LVG, ... */
{
	WORD i;
	if(cass[new].NR[0]!=cass[current].NR[0])		GT_SetGadgetAttrs( noiseAgad,window,NULL,GTCY_Active,cass[new].NR[0]     ,TAG_DONE);
	if(cass[new].NR[1]!=cass[current].NR[1])		GT_SetGadgetAttrs( noiseBgad,window,NULL,GTCY_Active,cass[new].NR[1]     ,TAG_DONE);
	if(cass[new].Source[0]!=cass[current].Source[0])	GT_SetGadgetAttrs(sourceAgad,window,NULL,GTCY_Active,cass[new].Source[0] ,TAG_DONE);
	if(cass[new].Source[1]!=cass[current].Source[1])	GT_SetGadgetAttrs(sourceBgad,window,NULL,GTCY_Active,cass[new].Source[1] ,TAG_DONE);
	GT_SetGadgetAttrs(listviewgad,window,NULL,GTLV_Top      ,new-1,TAG_DONE,0);
	GT_SetGadgetAttrs(currentgad,window ,NULL,GTIN_Number   ,new  ,TAG_DONE,0);
	current=new;
	for(i=0;i<30;i++) si[i].Buffer=(UBYTE *)cass[new].Name[i];	/* assign new buffer contents */
	RefreshGList(&StrGad[0],window,NULL,30);				/* 30 x StringGadget + 1 x NumGadget */
	return(0);
}

VOID
CompleteGads(struct NewGadget *ng)		/* Complete the Gadget's LayOut */
{
	/* For the StrGads Interpret/Title*/
	DrawBevelBox(window->RPort,StrGad[ 0].LeftEdge-2, StrGad[ 0].TopEdge-1, StrGad[0].Width+6, 2 * TOPAZ80.ta_YSize+2, GT_VisualInfo,vi ,TAG_DONE,0);
	DrawBevelBox(window->RPort,StrGad[15].LeftEdge-2, StrGad[15].TopEdge-1, StrGad[0].Width+6, 2 * TOPAZ80.ta_YSize+2, GT_VisualInfo,vi ,TAG_DONE,0);

	/* For the StrGads SongNames*/
	DrawBevelBox(window->RPort,StrGad[ 0].LeftEdge-2, StrGad[ 2].TopEdge-1, StrGad[0].Width+6, 13 * TOPAZ80.ta_YSize+2, GT_VisualInfo,vi ,TAG_DONE,0);
	DrawBevelBox(window->RPort,StrGad[15].LeftEdge-2, StrGad[17].TopEdge-1, StrGad[0].Width+6, 13 * TOPAZ80.ta_YSize+2, GT_VisualInfo,vi ,TAG_DONE,0);
}

VOID
usermessage(STRPTR text)                  	/* Put an errortext in a requester */
{
	if(IntuitionBase){
		struct Window *win;
		easyerror.es_TextFormat=text;
		if(screen) win=window;
		else	win=IntuitionBase->ActiveScreen->FirstWindow;
		EasyRequest(win,&easyerror,NULL,NULL);
	} else PutStr(text);
}

VOID
SetScreenColors( VOID )
{
	WORD j;
	for(j=0;j<4;j++){
			colorspec[j].ColorIndex	=j;
			colorspec[j].Red	=c2hex( (WORD)Colors[j*3+0] );
			colorspec[j].Green	=c2hex( (WORD)Colors[j*3+1] );
			colorspec[j].Blue	=c2hex( (WORD)Colors[j*3+2] );
	}
	colorspec[4].ColorIndex=-1;
	screentag[8].ti_Data=colorspec;
}

WORD
c2hex(WORD c)
{
	c=ToUpper(c);
	if( (WORD)c > 64 )	return(c-65+10);
	return((WORD)(c-48));
}

WORD
Palette( VOID )
{
	BOOL leave=FALSE;
	WORD i=0, index=0;	/* index stands for the color number */

	for(i=0;i<4;i++){ 	/* col is only temporary */
		col = GetRGB4( ((struct ViewPort)(screen->ViewPort)).ColorMap , i );
		col0[2][i] = (UWORD)  (col & (0x000f));
		col0[1][i] = (UWORD) ((col & (0x00f0)) >> 4);
		col0[0][i] = (UWORD) ((col & (0x0f00)) >> 8);
        }
	struct NewGadget palette =	{ 10, 20,270,20,NULL     ,&TOPAZ80,0,NULL          ,NULL,NULL};
	struct NewGadget rslide  =	{ 60, 45,190,15,"Red"    ,&TOPAZ80,1,PLACETEXT_LEFT,NULL,NULL};
	struct NewGadget gslide  =	{ 60, 65,190,15,"Green"  ,&TOPAZ80,2,PLACETEXT_LEFT,NULL,NULL};
	struct NewGadget bslide  =	{ 60, 85,190,15,"Blue"   ,&TOPAZ80,3,PLACETEXT_LEFT,NULL,NULL};
	struct NewGadget ok	 =	{ 10,105, 80,15,"_USE"   ,&TOPAZ80,4,PLACETEXT_IN  ,NULL,NULL};
	struct NewGadget save    =	{100,105, 80,15,"_SAVE"  ,&TOPAZ80,5,PLACETEXT_IN  ,NULL,NULL};
	struct NewGadget cancel  =	{190,105, 80,15,"_CANCEL",&TOPAZ80,6,PLACETEXT_IN  ,NULL,NULL};

	palette.ng_VisualInfo	=vi;
	rslide.ng_VisualInfo	=vi;
	gslide.ng_VisualInfo	=vi;
	bslide.ng_VisualInfo	=vi;
	ok.ng_VisualInfo	=vi;
	save.ng_VisualInfo	=vi;
	cancel.ng_VisualInfo	=vi;

	if(!(gad=CreateContext((struct Gadget **)&palcon)))					leave=TRUE;
	if(!(gad=CreateGadget(PALETTE_KIND,gad,&palette,GTPA_Depth,2,GTPA_IndicatorWidth,50,TAG_DONE,0)))	leave=TRUE;
	if(!(rslider=CreateGadgetA(SLIDER_KIND,gad,&rslide ,SliderItem)))			leave=TRUE;
	if(!(gslider=CreateGadgetA(SLIDER_KIND,rslider,&gslide ,SliderItem)))			leave=TRUE;
	if(!(bslider=CreateGadgetA(SLIDER_KIND,gslider,&bslide ,SliderItem)))			leave=TRUE;
	if(!(gad=CreateGadget(BUTTON_KIND ,bslider,&ok     ,GT_Underscore,'_',TAG_DONE,0)))	leave=TRUE;
	if(!(gad=CreateGadget(BUTTON_KIND ,gad,&cancel ,GT_Underscore,'_',TAG_DONE,0)))	leave=TRUE;
	if(!(gad=CreateGadget(BUTTON_KIND ,gad,&save   ,GT_Underscore,'_',TAG_DONE,0)))	leave=TRUE;
	if(leave!=0)	return(0);
	if(!(palwin=(struct Window *)OpenWindowTags(NULL,
		WA_Left		,(screen->Width  - 290) /2,
		WA_Top		,(screen->Height - 130) /2,
		WA_Width	,290,
		WA_Height	,130,
		WA_Flags	,WFLG_ACTIVATE|WFLG_CLOSEGADGET|WFLG_DRAGBAR,
                WA_Title	,"Palette Window",
		WA_IDCMP	,IDCMP_CLOSEWINDOW|SLIDERIDCMP|PALETTEIDCMP|IDCMP_MOUSEBUTTONS|IDCMP_MOUSEMOVE|IDCMP_VANILLAKEY,
		WA_Gadgets	,palcon,
		WA_CustomScreen	,screen,
		TAG_DONE	,0))) return(0);
	DrawBevelBox(palwin->RPort, 67, 19,213, 22,GT_VisualInfo,vi,TAG_DONE,0);
        DrawBevelBox(palwin->RPort,  9, 19, 52, 22,GTBB_Recessed,TRUE,GT_VisualInfo,vi,TAG_DONE,0);
	DrawBevelBox(palwin->RPort, 59, 44,192, 17,GT_VisualInfo,vi,TAG_DONE,0);
	DrawBevelBox(palwin->RPort, 59, 64,192, 17,GT_VisualInfo,vi,TAG_DONE,0);
	DrawBevelBox(palwin->RPort, 59, 84,192, 17,GT_VisualInfo,vi,TAG_DONE,0);

	DrawBevelBox(palwin->RPort, 254, 44, 24, 17,GTBB_Recessed,TRUE,GT_VisualInfo,vi,TAG_DONE,0);
	DrawBevelBox(palwin->RPort, 254, 64, 24, 17,GTBB_Recessed,TRUE,GT_VisualInfo,vi,TAG_DONE,0);
	DrawBevelBox(palwin->RPort, 254, 84, 24, 17,GTBB_Recessed,TRUE,GT_VisualInfo,vi,TAG_DONE,0);
    	getcolor(index);
	if(mydob == NULL) OffGadget( gad, palwin, NULL);	/* disable save gad when started from cli */
	leave=FALSE;
	while(leave==FALSE){
               	Wait(1<<palwin->UserPort->mp_SigBit);
                while(message=(struct IntuiMessage *)GT_GetIMsg(palwin->UserPort)){
			switch(message->Class){
			case IDCMP_CLOSEWINDOW:
                		leave=TRUE;
                		break;
                        case IDCMP_VANILLAKEY:
                        	switch(message->Code){
                        	case    'u':	leave=TRUE;	break;
                        	case	's':	leave=TRUE;	break;
                        	case	'c':	restorecolor();	leave=TRUE;	break;
				}
                        case IDCMP_GADGETUP:
				activegad=0;
				switch(((struct Gadget*)(message->IAddress))->GadgetID){
				case 0:	index=message->Code;
					getcolor(index);
					break;
      				case 1:	r[index]=message->Code;
					setcolor(index);
					break;
				case 2:	g[index]=message->Code;
					setcolor(index);
					break;
				case 3:	b[index]=message->Code;
					setcolor(index);
					break;
                                case 4:	leave=TRUE;
                                	break;
                                case 5:	leave=TRUE;
	                                uname[9][0]='\0';	/* for the colors-string */
					for(i=0;i<4;i++){
						getcolor(i);
						uname[9][0+i*3]=hex2c( r[i] );
						uname[9][1+i*3]=hex2c( g[i] );
						uname[9][2+i*3]=hex2c( b[i] );
					}
					i=0;
					while(mydob->do_ToolTypes[i]!=NULL){
						strcpy(uname[i],mydob->do_ToolTypes[i]);
						if(i>5) break;
						i++;
	                                }
					sprintf( toolstr[0] , "DISPLAYID=%08lx", DisplayID );
                                        strcpy( toolstr[1] , "DATABASE=" );
					strcat( toolstr[1] , Database );

                                        strcpy( toolstr[2] , "COLORS=" );
					strcat( toolstr[2] , uname[9]  );

					strcpy( toolstr[3] , "MAXCASS="    );
					strcat( toolstr[3] , itos(uname[0],MaxCass) );

					strcpy( toolstr[4] , "OSCAN=" );
					strcat( toolstr[4] , OscanName[Oscan] );

					for(i=0;i<5;i++) mydob->do_ToolTypes[i]=toolstr[i];
					PutDiskObject(myname,mydob);
					break;
                                case 6:	restorecolor();
					leave=TRUE;
					break;
				} /* end switch GadgetID */
			case IDCMP_GADGETDOWN:
      				i=(((struct Gadget*)(message->IAddress))->GadgetID);
				activegad=i;
      				if(i==1)	r[index]=message->Code;
				if(i==2)	g[index]=message->Code;
				if(i==3)	b[index]=message->Code;
				if(i==1 || i==2 || i==3) setcolor(index);
				
				break;
        		case IDCMP_MOUSEMOVE:
      				if(activegad==1)	r[index]=message->Code;
				if(activegad==2)	g[index]=message->Code;
				if(activegad==3)	b[index]=message->Code;
				if(activegad==1 || activegad==2 || activegad==3) setcolor(index);
				break;
	                } /* switch class */
	                GT_ReplyIMsg(message);
                } /* while message */
        } /* leave me */
        CloseWindow(palwin);
        FreeGadgets(palcon);
}

VOID
restorecolor(VOID)
{
	WORD i;

	for(i=0;i<4;i++){
		SetRGB4( &(screen->ViewPort), i , col0[0][i],col0[1][i],col0[2][i]);
        }
}

VOID
getcolor(WORD index)
{
	col=GetRGB4(screen->ViewPort.ColorMap,index);
	b[index] = (UWORD)  (col & (0x000f));
	g[index] = (UWORD) ((col & (0x00f0)) >> 4);
	r[index] = (UWORD) ((col & (0x0f00)) >> 8);

  	if(palwin){
	        GT_SetGadgetAttrs(rslider,palwin,NULL,GTSL_Level,r[index],TAG_DONE,0);
       		GT_SetGadgetAttrs(gslider,palwin,NULL,GTSL_Level,g[index],TAG_DONE,0);
	        GT_SetGadgetAttrs(bslider,palwin,NULL,GTSL_Level,b[index],TAG_DONE,0);
	}
}

VOID
setcolor(WORD index)
{
	SetRGB4( &(screen->ViewPort), index , r[index],g[index],b[index]);
}

WORD
hex2c(WORD hex)
{
	if(hex < 10 ) return(hex+48);
        return(hex+65-10);
}



/********************************************************************************
 *                                                                              *
 *				print fkts                                      *
 *										*
 ********************************************************************************/

BOOL
InitPrinter( VOID )
/*
 *	initializes the printer with the chosen config
 */
{
	WORD i;
	UBYTE status[2] = {0, 0};

	PDOPEN = OpenPrinter();
	if( PDOPEN != TRUE ){
		usermessage("Can't open printer device\n");
		return(FALSE);
	}
/**
 | Check if the printer is there... Actually, if the printer is connected
 | to the serial port, I don't know what to do: in this case I continue,
 | knowing that a System requester will come after a while. If the printer
 | is connected to the parallel port, printer selected (bit 0), paper out
 | (bit 1) and printer offline (bit 2) are checked.
**/
	FOREVER {
			printerReq->ios.io_Command = PRD_QUERY;
			printerReq->ios.io_Data    = (APTR) status;
			printerReq->ios.io_Flags   = 0;
			if (DoIO((struct IORequest *)printerReq)) {
				quit("Couldn't communicate with printer!");
			}
			if (printerReq->ios.io_Actual == 2)  break;
			if ((status[0] & 0x7) == 0x4)       break;
                        easyerror.es_GadgetFormat="I'll check|Cancel";
			easyerror.es_TextFormat="Please, check if your printer is ready!";
			if(EasyRequest(NULL,&easyerror,NULL,NULL)==0){
                                easyerror.es_GadgetFormat="Ok.";
				quit("Pm removed.");
			}
			easyerror.es_GadgetFormat="UNDERSTOOD!";
	}
	easyerror.es_GadgetFormat="UNDERSTOOD!";
	return(TRUE);
}

VOID
ResetPrinter( VOID )
/*
 *	self explaining
 */
{
	SendCommand(aRIS,0,0,0,0);
}

VOID
SendBuffer( STRPTR buffer , UWORD Mode)
/*
 *	Sends the data in buffer to the printer
 */
{
	printerReq->ios.io_Command = Mode;
	printerReq->ios.io_Data    = (APTR) buffer;
	printerReq->ios.io_Length  = strlen(buffer);
	printerReq->ios.io_Flags   = 0;

	if( DoIO( (struct IORequest *)printerReq ) ) usermessage("Error while DoIO!\n");
}

VOID
SendCommand( UWORD Command , UBYTE par0,par1,par2,par3 )
/*
 *	sends a command + parameters to the printer
 */
{
	printerReq->iopc.io_Command 	= PRD_PRTCOMMAND;
	printerReq->iopc.io_Flags   	= 0;
	printerReq->iopc.io_PrtCommand	= Command;
	printerReq->iopc.io_Parm0	= par0;
	printerReq->iopc.io_Parm1	= par1;
	printerReq->iopc.io_Parm2	= par2;
	printerReq->iopc.io_Parm3	= par3;

	if(  DoIO( (struct IORequest *)printerReq )  ) usermessage("Error while setting prefs!\n");
}

BOOL
OpenPrinter( VOID )
/*
 *	install Port, IORequest, open device
 */
{
	if(printer_mp = CreatePort(NULL,0)){
		if(printerReq = (union printerIO *)CreateExtIO(printer_mp,sizeof(union printerIO))){
			if( OpenDevice("printer.device",0,(struct IORequest *)printerReq,0) ==NULL ){
				SendBuffer( "\0" , CMD_WRITE );
				return(TRUE);
			}	
			DeleteExtIO( (struct IORequest *)printerReq );
		}
		DeletePort(printer_mp);
	}
	return( FALSE );
}

VOID
ClosePrinter( VOID )
/*
 *      close printer.device, delete the IOReq and delete the Port
 */
{
	if( PDOPEN == TRUE )	CloseDevice((struct IORequest *)printerReq);
	if( printerReq ) 	DeleteExtIO((struct IORequest *)printerReq);

	if(printer_mp)	DeletePort(printer_mp);
	printerReq=NULL;
	printer_mp=NULL;
	PDOPEN=FALSE;
}

ULONG
ahex2ulong( STRPTR ahex )
{
	ULONG 	id=0, x=1;
	WORD	i;

     	for(i=9;i>1;i--){
      		id+= x * c2hex( ahex[i] );
		x*=16;
	}
	return( id );
}
