package zero1hd.polyjet.audio.map;

import org.apache.commons.math3.random.MersenneTwister;

import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.FloatArray;

import zero1hd.polyjet.Polyjet;
import zero1hd.polyjet.audio.AudioAnalyzer;
import zero1hd.polyjet.entity.Entities;
import zero1hd.polyjet.util.MiniEvents;
import zero1hd.polyjet.util.MiniSender;

public class RhythmMapAlgorithm implements Runnable {
	private MiniSender sender;
	
	private FloatArray bassPeaks;
	private FloatArray UMPeaks;
	private FloatArray overlappedPeaks;
	private MersenneTwister rand;
	private GamePlayMap map;
	
	private float avgBass;
	private float avgUM;
	private float avgSPB;
	private float umMax, bassMax;
	
	private float speedMod, healthMod;
	
	private float windowPerSecond;
	
	private volatile int progress;
	public RhythmMapAlgorithm(AudioAnalyzer analyzer, float speedMod, float healthMod) {
		sender = new MiniSender();
		
		bassPeaks = analyzer.getBassPeaks();
		UMPeaks = analyzer.getUMPeaks();
		overlappedPeaks = analyzer.getOverlappedPeaks();
		map = new GamePlayMap(analyzer.getAudioData());
		rand = new MersenneTwister(analyzer.getPUID());
		avgSPB = analyzer.getAvgSPB();
		windowPerSecond = 1/analyzer.getsecondsPerWindow();
		
		this.speedMod = speedMod;
		this.healthMod = healthMod;
		
		umMax = analyzer.getUMMaxValue();
		avgUM = analyzer.getUmAvg();

		bassMax = analyzer.getBassMaxValue();
		avgBass = analyzer.getBassAvg();
	}
	
	@Override
	public void run() {
		map.beginBuild();
		for (int index = 0; index < bassPeaks.size; index++) {
			if (bassPeaks.get(index) != 0 || UMPeaks.get(index) != 0) {
				int warningTime = (int) ((3/speedMod)*windowPerSecond);
				if ((index+warningTime < bassPeaks.size) && bassPeaks.get(index + warningTime) != 0) {
					//TODO basic void circle spawning
					float endRadius = (bassPeaks.get(index + warningTime)/bassMax)*(Polyjet.GAME_AREA_HEIGHT/2f);
					
					map.addToMap(Entities.VOID_CIRCLE, 
							endRadius, 
							rand.nextFloat()*Polyjet.GAME_AREA_WIDTH, 
							rand.nextFloat()*Polyjet.GAME_AREA_HEIGHT,
							endRadius/(avgSPB*0.6f),
							3f/speedMod
							);
				}
				if (bassPeaks.get(index) != 0) {
					map.addToMap(Entities.BAR, 
							MathUtils.round(1.5f+rand.nextFloat()*(Polyjet.GAME_AREA_WIDTH-3)), 
							(8f/avgSPB)*speedMod);
				} else {
					if (UMPeaks.get(index) != 0) {
						float xSpawnLocation = (rand.nextFloat()*(Polyjet.GAME_AREA_WIDTH-2))+1;
						map.addToMap(Entities.PELLET,
								xSpawnLocation,
								Polyjet.GAME_AREA_HEIGHT-0.25f, 
								140*rand.nextFloat()+110f, 
								(Polyjet.GAME_AREA_HEIGHT/4f)/avgSPB);
					}
				}
			} else {
				map.addNullToMap();
			}
			map.nextWindow();

			progress = MathUtils.round(100f*index/bassPeaks.size);
			
			sender.send(MiniEvents.MAPGEN_ITERATED);
		}
		map.endBuild();
		sender.send(MiniEvents.MAP_GENERATED);
	}
	
	public synchronized GamePlayMap getMap() {
		return map;
	}
	
	public synchronized int getProgress() {
		return progress;
	}
	
	public MiniSender getSender() {
		return sender;
	}
}
