/* Generated by Interface Builder */

#import "Abspieler.h"


char *lade_module(char *);
char *lade_module_normal(FILE *, int);
char *lade_module_pp(FILE *, int, char *);

extern int Aktion_Todo;
extern char Aktion_Pfad[1024];
#define LADEN 2
#define LOAD_AND_PLAY 1
#define ABSPIELEN 2
#define BEIM_BEENDEN 1
#define END_OK 0
extern int be_stat;
extern mutex_t be_stat_lock;

@implementation Abspieler

extern int spektrum;
extern float nullWert[];
extern int klang_reset;
int noch_starten = 0;
int init_klar = 0;
int autor_gesetzt = 0;
int MaxPatternGlobal = 100;

/* ------------------------------------------------------------ */
/* Unterstuetzende C-Funktionen */

char *lade_module(char *dateiname)
{
	struct stat stbuf;// Statbuffer
	char temp[10];    // Kleiner temporaerer Buffer
	FILE *fp;         // Filepointer fuer Datei
	char *ptr;        // Pointer auf den eingelesenen Buffer
	int groesse;      // Groesse der Datei

	ptr = NULL;
		
	if(stat(dateiname, &stbuf) == -1)
	{
		return NULL;
	}
	groesse = stbuf.st_size;
	
	if((fp = fopen(dateiname, "r")) != NULL)
	{
		// zur Identifizierung die ersten acht Bytes lesen
		if(fread(temp, 8, 1, fp) == 1)
		{
			if(strncmp(temp, "PP20", 4) == 0)
			{
				// Aha, ein Module mit Powerpacker gepackt.
				ptr = lade_module_pp(fp, groesse, &temp[4]);
			}
			else if(strncmp(temp, "PX20", 4) == 0)
			{
				// Fehlermeldung ausgeben
			}
			else
			{
				// Also kein mit Powerpacker gepacktes Module
				ptr = lade_module_normal(fp, groesse);
			}
		}
		fclose(fp);
	}
	return ptr;
}

char *lade_module_normal(FILE *fp, int groesse)
{
	char *ptr;
	
	ptr = calloc(groesse, 1);
	
	// An den Dateianfang fahren...
	fseek(fp, 0L, SEEK_SET);
	// ...und einlesen
	if(fread(ptr, groesse, 1, fp) != 1)
	{
		fprintf(stderr, "Fehler beim Lesen...\n");
		return NULL;
	}
	return ptr;
}

char *lade_module_pp(FILE *fp, int groesse, char *tmpbuf)
{
	char temp[10];
	char *ptr;
	int effizienz, info, groesse_neu;
	
	effizienz = info = 0;
	
	// Effizienz kopieren
	memcpy(&effizienz, tmpbuf, 4);

	// Vier Bytes vor das Ende der Datei fahren
	fseek(fp, -4L, SEEK_END);

	if(fread(temp, 4, 1, fp) != 1)
	{
		fprintf(stderr, "Fehler beim Lesen\n");
		return NULL;
	}

	// Laenge der Datei ermitteln
	memcpy(&info, &temp[0], 4);
	info = (info >> 8) + 8;

	ptr = calloc(info, 1);
	
	// Acht Bytes hinter den Anfang der Datei fahren
	fseek(fp, 8, SEEK_SET);

	groesse_neu = groesse - 8;
	if(fread(ptr, groesse_neu, 1, fp) != 1)
	{
		fprintf(stderr, "Fehler beim Lesen\n");
		return NULL;
	}

	// Funktion in PowerPackerD.o
	Decrunch(ptr + groesse_neu, ptr, effizienz);
	
	return ptr;
}

/* ------------------------------------------------------------ */
/* Ab hier Objective-C Methoden */

- init
{	
	be_stat_lock = mutex_alloc();
	return self;
}


- ladeModule:sender
{
	mutex_lock(be_stat_lock);
	if(be_stat == END_OK)
	{
		mutex_unlock(be_stat_lock);
		[fftView neueWerte:&nullWert[0]];
		[self ladeModule:self datei:NULL];
	} else
	{
		mutex_unlock(be_stat_lock);
		[Stopknopf performClick:self];
		Aktion_Todo = LADEN;
	}
	return self;
}

- ladeModule:sender datei:(const char *)datei
{
	const char *const suffix[] = {"mod", "pp", "MOD", "PP", NULL};
	const char *const *modname;
	char pfad[4096];

	if(spielAb == YES)
	{
		[Stopknopf performClick:self];
		spielAb = NO;
		modulePuffer = NULL;
	}
	[Fenster setTitle:[stringTab valueForStringKey:"keinModuleGeladen"]];
	[self setzeModuleNamen:[stringTab valueForStringKey:"keinTitel"] laenge:0];
	[AktPattern setStringValue:""];
	[PosAnzeiger neuePos:0:MaxPatternGlobal];

	[fftView neueWerte:&nullWert[0]];
	// Tracker zuruecksetzen!!!

  if(datei == NULL)
	{
		openPanel = [OpenPanel new];
		[openPanel setTitle:[stringTab valueForStringKey:"moduleLaden"]];
		[openPanel allowMultipleFiles:NO];
		if ([openPanel runModalForDirectory:stdPfad file:NULL types:suffix]	&&
		     (modname = [openPanel filenames]) != NULL)
		{
			if(*modname)
			{
				strcpy(pfad, [openPanel directory]);
				strcat(pfad, "/");
				strcat(pfad, *modname);
			}
			else
			{
				[self knopfZustand:0];
				return self;
			}
		}
		else
		{
			[self knopfZustand:0];
		  return self;
		}
	}
  else
	{
	  strcpy(pfad, datei);
	}
	
	if((modulePuffer = lade_module(pfad)) != NULL)
	{
		if(!trackerPlayer)
		{
			trackerPlayer = [[TrackerPlayer alloc] init];
			[trackerPlayer setDelegate:self];
			[trackerPlayer setFFTView:fftView];
			[trackerPlayer setzeStringTab:stringTab];
		}

		[Fenster setTitleAsFilename:pfad];
		spielAb = 
			[trackerPlayer ladeModuleEin:modulePuffer 
				mix:stereoMix speed:speed endlos:endlos fft:fftspeed];
		free(modulePuffer);
	}
	if ((init_klar == 1) && (noch_starten == 1))
	{
	  [Abspielknopf performClick:self];
		noch_starten = 0;
	}
	
	return self;
}

- setzeSampleNamen:(char *)name nr:(int)nr lae:(int)lae
										offset:(int)offset ofle:(int)ofle
{
	int i;
		
	[[SamMat1Name cellAt:nr-1:0] setStringValue:name];

	if (autor_gesetzt == 1)
	{
		[AutorFeld setStringValue:name];
		autor_gesetzt = 2;
	}

	if ((autor_gesetzt == 0) && (name))
	{
		for (i = 0; i < strlen(name); i++)
		{
			if ((name[i] == 'b') || (name[i] == 'B'))
			{
				if ((name[i + 1] == 'y') || (name[i + 1] == 'Y'))
				{
					if ((name[i + 2] == ' ') && ((name[i + 3] != ' ')
							&& (name[i + 3] != 0x0)))
					{
						[AutorFeld setStringValue:&name[i + 3]];
						autor_gesetzt = 2;
					}
					else if ((name[i + 2] == 0x0) || (name[i + 2] == ' '))
						autor_gesetzt = 1;
				}
			}
		}
	}
	
	if (lae != -1)
		[[SamMat1Laenge cellAt:nr-1:0] setIntValue:lae];
	else
		[[SamMat1Laenge cellAt:nr-1:0] setStringValue:""];

	if (offset != -1)
		[[SamMat1Offset cellAt:nr-1:0] setIntValue:offset];
	else
		[[SamMat1Offset cellAt:nr-1:0] setStringValue:""];
	
	DPSFlush();

	return self;
}

- setzeAktuellesPattern:(int)pattern
{
	if (pattern != -1)
	{
		[AktPattern setIntValue:pattern+1];
		[PosAnzeiger neuePos:pattern+1:MaxPatternGlobal];
	}
	else
	{
		[AktPattern setStringValue:""];
		[PosAnzeiger neuePos:0:MaxPatternGlobal];
	}
	DPSFlush();
	return self;
}
	
- setzeModuleNamen:(const char *)name laenge:(int)laenge
{
	[Modulename setStringValue:name];
	MaxPatternGlobal = laenge;
	[AutorFeld setStringValue:[stringTab valueForStringKey:"unbekannt"]];
	autor_gesetzt = 0;
	DPSFlush();
	return self;
}

- moduleAbspielen
{
	if(spielAb == YES)
	{
		[fftView neueWerte:&nullWert[0]];
		[trackerPlayer starteAbspielen];
		[Abspielknopf setState:1];
	}
	
	return self;
}

- knopfAbspielen:sender
{
	if(![Pauseknopf state]) // Im Pausemodus?
	{
		[Stopknopf performClick:self];
		
		if(spielAb == NO)
		{
			[self ladeModule:self datei:NULL];
		}
	
		if(spielAb == YES)
		{
			[self moduleAbspielen];
		}
	}
	else
	{
		[Abspielknopf setState:1];
		[Pauseknopf performClick:self];
	}
	return self;
}

- knopfPause:sender
{
	[trackerPlayer pausiereAbspielen];
	if([Pauseknopf state])
	{
		[PosAnzeiger anfangPause];
		[Abspielknopf setEnabled:YES];
	}
	else
	{
		[PosAnzeiger endePause];
		[Abspielknopf setEnabled:NO];
	}		
	return self;
}

extern initSimpleMsg(simpleMsg *);

- knopfStop:sender
{
	simpleMsg msg;

	[PosAnzeiger stoppeZeit];
	if([trackerPlayer beimAbspielen] == YES)
	{
		[trackerPlayer beendeAbspielen];
		initSimpleMsg(&msg);
		msg.Aktion = FFT_CLEAR;
		msg_send(&msg.h, MSG_OPTION_NONE, 0);
		[AktPattern setStringValue:""]; // mz 14.5.92
		[PosAnzeiger neuePos:0:MaxPatternGlobal];
	}
	[self knopfZustand:0];
	return self;
}

- knopfZustand:(int)flag
{
	if(flag == 0)
	{
		[PosAnzeiger stoppeZeit];
		[Abspielknopf setState:0];
		[Abspielknopf setEnabled:YES];
		[Pauseknopf setState:0];
		[Stopknopf setState:0];
		[Pauseknopf setEnabled:NO];
		[Stopknopf setEnabled:NO];
	}
	else
	{
		[Abspielknopf setState:1];
		[Abspielknopf setEnabled:NO];
		[Pauseknopf setState:0];
		[Pauseknopf setEnabled:YES];
		[Stopknopf setEnabled:YES];
	}
	DPSFlush();
	return self;
}


- abspielKnopf	{ return Abspielknopf; }
- pauseKnopf		{ return Pauseknopf; }
- stopKnopf			{	return Stopknopf; }

- aendereGeschwindigkeit:sender
{
	switch([sender tag])
	{
		case 1: // Slider
			speed = [sender intValue];
			if(trackerPlayer)
				[trackerPlayer setzeGeschwindigkeit:speed];
			return self;
			break;
		case 3:  speed = 30; break;
		case 4:  speed = 40; break;
		case 5:  speed = 50; break;
		case 6:  speed = 60; break;
		case 7:  speed = 70; break;
		case 8:  speed = 80; break;
		default: speed = 50; break;
	}

	[gSlider setIntValue:speed];
	if(trackerPlayer)
		[trackerPlayer setzeGeschwindigkeit:speed];

	return self;
}

- aendereStereo:sender
{
		switch([sender tag])
	{
		case 1: // Slider
			stereoMix = [sender intValue];
			if(trackerPlayer)
				[trackerPlayer setzeStereo:stereoMix];
			return self;
			break;
		case 2:  stereoMix = 0; break;
		case 3:  stereoMix = 34; break;
		case 4:  stereoMix = 67; break;
		case 5:  stereoMix = 100; break;
		default: stereoMix = 34; break;
	}

	[sSlider setIntValue:stereoMix];
	if(trackerPlayer)
		[trackerPlayer setzeStereo:stereoMix];

	return self;
}

- aendereKlang:sender
{
	spektrum = (spektrum + 1) % 2;
	klang_reset = 1;
	return self;
}

- aendereTiefpass:sender
{
	SNDSetFilter((int)[sender state]);
	return self;
}

- setzeTiefpassSwitch:(BOOL)flag
{
	[tiefpassSwitch setIntValue:flag];
	return self;
}

- aendereEndlos:sender
{
	endlos = [sender state];
	if(trackerPlayer)
		[trackerPlayer setzeEndlos:endlos];

	return self;
}

void ueberpruefeTiefpass(DPSTimedEntry number, double now, char *data)
{
	int filterOn;
	
	SNDGetFilter(&filterOn);
	[(id)data setzeTiefpassSwitch:filterOn];
}

/* Bringt Prefs-Fenster nach vorne */
- zeigePrefs:sender
{
	[meinePrefs zeigePrefsFenster:self];
	
	return self;
}

- zeigeProgramm:sender
{
	[meinProgramm zeigeProgrammFenster:self];

	return self;
}

- stellePrefsEin:(BOOL)init
{
	if(meinePrefs && (init == YES))
		return self;

	if(!meinePrefs)
		meinePrefs = [[Prefs alloc] init:self];
	
	[endlosSwitch setIntValue:[meinePrefs endlosAbspielen]];
	endlos = (BOOL)[meinePrefs endlosAbspielen];
	if(trackerPlayer)
		[trackerPlayer setzeEndlos:endlos];
	
	[klangSwitch setIntValue:[meinePrefs klangSpektrum]];
	spektrum = [meinePrefs klangSpektrum];
	klang_reset = 1;

	[self setzeTiefpassSwitch:(BOOL)[meinePrefs tiefpassFilter]];
	SNDSetFilter([meinePrefs tiefpassFilter]);
	
	[sSlider setIntValue: 100 - [meinePrefs stereoEffekt]];
	stereoMix = 100 - [meinePrefs stereoEffekt];
	if(trackerPlayer)
		[trackerPlayer setzeStereo:stereoMix];

	[gSlider setIntValue:[meinePrefs geschwindigkeit]];
	speed = [meinePrefs geschwindigkeit];
	if(trackerPlayer)
		[trackerPlayer setzeGeschwindigkeit:speed];

	fftspeed = [meinePrefs fftSpeed];
	if (trackerPlayer)
		[trackerPlayer setzeFFTSpeed:fftspeed];
	
	stdPfad = [meinePrefs stdPfad];

	return self;
}

/*
 * Delegation Methods fuer Application
 */

- windowWillResize:sender toSize:(NXSize *)frameSize
{
	if(frameSize->width < Breite)
		frameSize->width = Breite;
	if(frameSize->height < Hoehe)
		frameSize->height = Hoehe;
	return self;
}

- appDidInit:sender
{
	NXRect winFrame;

	[Fenster getFrame:&winFrame];
	Breite = winFrame.size.width;
	Hoehe  = winFrame.size.height;

	[self stellePrefsEin:YES];
	if(!meinProgramm)
		meinProgramm = [[Programm alloc] init:self];
	(void) DPSAddTimedEntry(0.5, (DPSTimedEntryProc)ueberpruefeTiefpass,
		self, 10);

	if (noch_starten == 1)
	{
	  [Abspielknopf performClick:self];
		noch_starten = 0;
	}

	if(!trackerPlayer)	
		[self knopfZustand:0];

	init_klar = 1;
	// [Fenster makeKeyAndOrderFront:self];
	return self;
}

- (BOOL) appAcceptsAnotherFile:sender
{
	return YES;
}

- (int)appOpenFile:(const char *)datei type:(const char *)type
{
	if((strcasecmp(type, "mod") == 0) || (strcasecmp(type, "pp")  == 0))
	{
		[self stellePrefsEin:YES];
		
	  mutex_lock(be_stat_lock);
	  if(be_stat != END_OK)
	  {
		  mutex_unlock(be_stat_lock);
  		[Stopknopf performClick:self];
		  Aktion_Todo = LOAD_AND_PLAY;
			strcpy(Aktion_Pfad, datei);
			[Fenster makeKeyAndOrderFront:self]; //mz 27.6.92
		  return YES;
	  }
  	mutex_unlock(be_stat_lock);

		noch_starten = 1;
	  [self ladeModule:self datei:datei];
		if(spielAb == YES)
			noch_starten = 1;
		else
			noch_starten = 0;
		[Fenster makeKeyAndOrderFront:self]; //mz 27.6.92
		return YES;
	}
	else
	{
		return NO;
	}	
}

- willPosAnzeiger
{
	return PosAnzeiger;
}

- (char *)GibStdPfad;
{
	return (char *)stdPfad;
}

@end
