/* ExperimentMFC.c */
/* Paul Boersma, September 9, 2001 */

#include "ExperimentMFC.h"

#include "oo_DESTROY.h"
#include "ExperimentMFC_def.h"
#include "oo_COPY.h"
#include "ExperimentMFC_def.h"
#include "oo_EQUAL.h"
#include "ExperimentMFC_def.h"
#include "oo_READ_ASCII.h"
#include "ExperimentMFC_def.h"
#include "oo_WRITE_ASCII.h"
#include "ExperimentMFC_def.h"
#include "oo_READ_BINARY.h"
#include "ExperimentMFC_def.h"
#include "oo_WRITE_BINARY.h"
#include "ExperimentMFC_def.h"
#include "oo_DESCRIPTION.h"
#include "ExperimentMFC_def.h"

class_methods (ExperimentMFC, Data)
	class_method_local (ExperimentMFC, destroy)
	class_method_local (ExperimentMFC, description)
	class_method_local (ExperimentMFC, copy)
	class_method_local (ExperimentMFC, equal)
	class_method_local (ExperimentMFC, writeAscii)
	class_method_local (ExperimentMFC, readAscii)
	class_method_local (ExperimentMFC, writeBinary)
	class_method_local (ExperimentMFC, readBinary)
class_methods_end

#include "enum_c.h"
#include "Experiment_enums.h"

static int readSound (ExperimentMFC me, StimulusMFC thee) {
	char fileName [256], pathName [256];
	struct MelderFile file;
	strcpy (fileName, thy name);
	#if defined (macintosh)
	for (;;) { char *slash = strchr (fileName, '/'); if (! slash) break; *slash = ':'; }
	#elif defined (_WIN32)
	for (;;) { char *slash = strchr (fileName, '/'); if (! slash) break; *slash = '\\'; }
	#endif
	sprintf (pathName, "%s%s%s", my fileNameHead, fileName, my fileNameTail);
	Melder_pathToFile (pathName, & file); cherror
	forget (thy sound);
	thy sound = Data_readFromFile (& file); cherror
	if (thy sound -> methods != classSound) {
		Melder_error ("No sound in file \"%s\".", MelderFile_messageName (& file));
		goto end;
	}
end:
	iferror return 0;
	return 1;
}

static void permuteRandomly (ExperimentMFC me, long first, long last) {
	long itrial;
	for (itrial = first; itrial < last; itrial ++) {
		long jtrial = NUMrandomInteger (itrial, last), dummy;
		dummy = my stimuli [jtrial];
		my stimuli [jtrial] = my stimuli [itrial];
		my stimuli [itrial] = dummy;
	}
}

int ExperimentMFC_start (ExperimentMFC me) {
	long istim, itrial, ireplica;
	my trial = 0;
	NUMlvector_free (my stimuli, 1);
	NUMlvector_free (my responses, 1);
	my pausing = FALSE;
	my numberOfTrials = my numberOfDifferentStimuli * my numberOfReplicationsPerStimulus;
	my stimuli = NUMlvector (1, my numberOfTrials); cherror
	my responses = NUMlvector (1, my numberOfTrials); cherror
	if (my carrierBefore. name && my carrierBefore. name [0]) { readSound (me, & my carrierBefore); cherror }
	if (my carrierAfter. name && my carrierAfter. name [0]) { readSound (me, & my carrierAfter); cherror }
	for (istim = 1; istim <= my numberOfDifferentStimuli; istim ++) {
		readSound (me, & my stimulus [istim]); cherror
	}
	if (my randomize == enumi (Experiment_RANDOMIZE, CyclicNonRandom)) {
		for (itrial = 1; itrial <= my numberOfTrials; itrial ++)
			my stimuli [itrial] = (itrial - 1) % my numberOfDifferentStimuli + 1;
	} else if (my randomize == enumi (Experiment_RANDOMIZE, PermuteAll)) {
		for (itrial = 1; itrial <= my numberOfTrials; itrial ++)
			my stimuli [itrial] = (itrial - 1) % my numberOfDifferentStimuli + 1;
		permuteRandomly (me, 1, my numberOfTrials);
	} else if (my randomize == enumi (Experiment_RANDOMIZE, PermuteBalanced)) {
		for (ireplica = 1; ireplica <= my numberOfReplicationsPerStimulus; ireplica ++) {
			long offset = (ireplica - 1) * my numberOfDifferentStimuli;
			for (istim = 1; istim <= my numberOfDifferentStimuli; istim ++)
				my stimuli [offset + istim] = istim;
			permuteRandomly (me, offset + 1, offset + my numberOfDifferentStimuli);
		}
	} else if (my randomize == enumi (Experiment_RANDOMIZE, PermuteBalancedNoDoublets)) {
		for (ireplica = 1; ireplica <= my numberOfReplicationsPerStimulus; ireplica ++) {
			long offset = (ireplica - 1) * my numberOfDifferentStimuli;
			for (istim = 1; istim <= my numberOfDifferentStimuli; istim ++)
				my stimuli [offset + istim] = istim;
			do {
				permuteRandomly (me, offset + 1, offset + my numberOfDifferentStimuli);
			} while (ireplica != 1 && my stimuli [offset + 1] == my stimuli [offset] && my numberOfDifferentStimuli > 1);
		}
	} else if (my randomize == enumi (Experiment_RANDOMIZE, WithReplacement)) {
		for (itrial = 1; itrial <= my numberOfTrials; itrial ++)
			my stimuli [itrial] = NUMrandomInteger (1, my numberOfDifferentStimuli);
	}
end:
	iferror {
		my numberOfTrials = 0;
		my stimuli = NULL;
		return 0;
	}
	return 1;
}

class_methods (ResultsMFC, Data)
	class_method_local (ResultsMFC, destroy)
	class_method_local (ResultsMFC, description)
	class_method_local (ResultsMFC, copy)
	class_method_local (ResultsMFC, equal)
	class_method_local (ResultsMFC, writeAscii)
	class_method_local (ResultsMFC, readAscii)
	class_method_local (ResultsMFC, writeBinary)
	class_method_local (ResultsMFC, readBinary)
class_methods_end

ResultsMFC ResultsMFC_create (long numberOfTrials) {
	ResultsMFC me = new (ResultsMFC);
	if (! me) return NULL;
	my numberOfTrials = numberOfTrials;
	if ((my result = NUMstructvector (TrialMFC, 1, my numberOfTrials)) == NULL)
		{ forget (me); return NULL; }
	return me;
}

ResultsMFC ExperimentMFC_extractResults (ExperimentMFC me) {
	ResultsMFC thee = NULL;
	long trial;
	if (my trial == 0 || my trial <= my numberOfTrials)
		return Melder_errorp ("(ExperimentMFC_extractResults:) Experiment not finished.");
	thee = ResultsMFC_create (my numberOfTrials); cherror
	for (trial = 1; trial <= my numberOfTrials; trial ++) {
		thy result [trial]. stimulus = Melder_strdup (my stimulus [my stimuli [trial]]. name); cherror
		thy result [trial]. response = Melder_strdup (my response [my responses [trial]]. category); cherror
	}
end:
	iferror { forget (thee); return NULL; }
	return thee;
}

ResultsMFC ResultsMFC_removeUnsharedStimuli (ResultsMFC me, ResultsMFC thee) {
	long i, j;
	ResultsMFC him = ResultsMFC_create (thy numberOfTrials); cherror
	his numberOfTrials = 0;
	for (i = 1; i <= thy numberOfTrials; i ++) {
		int present = FALSE;
		for (j = 1; j <= my numberOfTrials; j ++) {
			if (strequ (thy result [i]. stimulus, my result [j]. stimulus)) {
				present = TRUE;
				break;
			}
		}
		if (present) {
			his numberOfTrials ++;
			his result [his numberOfTrials]. stimulus = Melder_strdup (thy result [i]. stimulus); cherror
			his result [his numberOfTrials]. response = Melder_strdup (thy result [i]. response); cherror
		}
	}
	if (his numberOfTrials == 0) { Melder_error ("No shared stimuli."); goto end; }
end:
	iferror { forget (him); return Melder_errorp ("(ResultsMFC_removeUnsharedStimuli:) Not performed."); }
	return him;
}

Categories ResultsMFC_to_Categories_stimuli (ResultsMFC me) {
	Categories thee = Categories_create ();
	long trial;
	if (! thee) return 0;
	for (trial = 1; trial <= my numberOfTrials; trial ++) {
		SimpleString category = SimpleString_create (my result [trial]. stimulus); cherror
		Collection_addItem (thee, category); cherror
	}
end:
	iferror { forget (thee); return NULL; }
	return thee;
}

Categories ResultsMFC_to_Categories_responses (ResultsMFC me) {
	Categories thee = Categories_create ();
	long trial;
	if (! thee) return 0;
	for (trial = 1; trial <= my numberOfTrials; trial ++) {
		SimpleString category = SimpleString_create (my result [trial]. response); cherror
		Collection_addItem (thee, category); cherror
	}
end:
	iferror { forget (thee); return NULL; }
	return thee;
}

static int compare (SimpleString me, SimpleString thee) {
	return strcmp (my string, thy string);
}
void Categories_sort (Categories me) {
	NUMsort_p (my size, my item, (int (*) (const void *, const void *)) compare);
}

double Categories_getEnthropy (Categories me) {
	long i, numberOfTokens = 0;
	char *previousString = NULL;
	double enthropy = 0.0;
	me = Data_copy (me); iferror return NUMundefined;
	Categories_sort (me);
	for (i = 1; i <= my size; i ++) {
		SimpleString s = my item [i];
		char *string = s -> string;
		if (previousString != NULL && ! strequ (string, previousString)) {
			double p = (double) numberOfTokens / my size;
			enthropy -= p * log2 (p);
			numberOfTokens = 1;
		} else {
			numberOfTokens ++;
		}
		previousString = string;
	}
	if (numberOfTokens) {
		double p = (double) numberOfTokens / my size;
		enthropy -= p * log2 (p);
	}
	forget (me);
	return enthropy;
}

/* End of file Formant.c */
