///////////////////////// Center Group 2 ////////////////
// Programmers: Julian Rohrhuber, Till Bovermann

//// Read Data
/** 
Data on PLoop bins
[-1,0,1] are physical values, 2 is filtered data (can be ignored)

KV, 02/2010, prepared for SBEII (Data by Christof Gattringer)
**/
(
q = ();
q.myPath = Document.current.dir; 
q.ttcs = [0.63, 0.69, 0.75, 0.82, 0.89, 0.97, 1.01, 1.05, 1.13, 1.22, 1.32].collect(_.asSymbol);
q.confs = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10"].collect(_.asSymbol);

q.allData = (); 
q.ttcs.do { |ttc, i| 
	var dict = (); q.allData.put(ttc, dict); 
	
	q.confs.do { |conf, j| 
		var path = q.myPath ++ "/files_gattringer/intsect_TTC_" 
			++ ttc ++ "_conf_" ++ conf ++".dat";
		dict.put(conf, FileReader.read(path, true, true, _.asInteger, $\n).unbubble.clump(40).clump(40));
	}
};
)

/* test
q.allData['0.89']['01'].shape; // */

// helper methods
(
// generalised Collection:at for 3D-toroids (wrapping around edges ) 
q.toroidAt = { |q, indices, array| 
	var res = array; 
	indices.do { |i| res = res.wrapAt(i) };
	res
};

// relative neighbor indices, only positive
q.posNeighbors = [
	[1, 0, 0],
	[0, 1, 0],
	[0, 0, 1]
];

// relative neighbor indices, also negative
q.neighbors = q.posNeighbors ++ q.posNeighbors.neg;

// get all positive neighbor indices for a given index set
q.allPosNeighbors = { |q, indices|
		q.posNeighbors.collect { |x| indices + x };
};

// get all neighbor indices for a given index set
q.allNeighbors = { |q, indices|
		q.neighbors.collect { |x| indices + x };
};

// compare current value with its surrounding values; return 1 if its the same, else 0 
q.compare = {|q, actValue, others|
	//[actValue, others].postln;

	(actValue == 2).if({
			[0, 0, 0, 0, 0, 0]
	}, {
		others.collect{|it|
			(it == actValue).binaryValue;
		}
	})
};

/* tests
// example: get all links around a specific point  

(
q.others = q.allNeighbors([4, 4, 40]).collect{|idx, i|
	q.toroidAt(idx, q.allData['0.89']['01'])
};
q.others
)

// value at that specific position
(
q.actValue = q.toroidAt([4, 4, 40], q.allData['0.89']['01']);
q.actValue;
)

// compare them
q.compare(q.actValue, q.others)
*/

)

//q.linkData = q.allLinkData['0.63'].unbubble;

q.config = q.allData['1.32']['01'];
q.config = q.allData['0.63']['01'];
q.config = q.allData['0.63']['03'];

// random starting Index
q.idx = {40.rand}!3;

/// first try
(
q.computeNextIdx = {|q, currentIdx|
	var myVal, nextIdx, neighborIdx, ii, neigh, neighVals;
	myVal = q.toroidAt(currentIdx, q.config);
	neigh = q.allNeighbors(currentIdx);
	neighVals = neigh.collect { |each| q.toroidAt(each, q.config) };
		
	ii = neighVals.collect { |val, i|  if(val != myVal) { -1 } { i } }.reject(_ == -1).choose;
	nextIdx = if(ii.isNil) {
		currentIdx
	} {
		neigh[ii]
	};
	nextIdx
}
)

/* test
q.idx = q.computeNextIdx(q.idx); q.idx // */

// minimal synth
s.boot;
(
SynthDef(\blip, {|out = 0, freq = 440, sustain = 1, amp = 1|
	Out.ar(out, amp * LPF.ar(Pulse.ar(freq), 2000 ) * Line.kr(0.1, 0, sustain, doneAction: 2).lag(0.01));
}).memStore;

SynthDef(\ping, {|out = 0, freq = 440, sustain = 1, amp = 1|
	Out.ar(out, amp * Saw.ar(freq) * Line.kr(0.1, 0, sustain, doneAction: 2));
}).memStore;

/* test
(instrument: \blip).play; // */

q.idx = {40.rand}!3; q.startIdx = q.idx;
Tdef(\player, {
	var e;
	loop{
		q.idx = q.computeNextIdx(q.idx);
		e = (instrument: \blip, freq: q.idx * 20 + 50, \dur: 0.02, \legato: 1.1, amp: 0.125).play;

		(q.idx == q.startIdx).if{
			(instrument: \ping, freq: [300, 400], \dur: 0.5, \amp: 0.2).play	
		};
		e.dur.wait;
	}
});
)

q.idx = {40.rand}!3; q.startIdx = q.idx;
q.idx

Tdef(\player).play
Tdef(\player).stop