package zero1hd.polyjet.ui.pages;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Slider;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.Align;

import zero1hd.polyjet.audio.AudioAnalyzer;
import zero1hd.polyjet.audio.AudioData;
import zero1hd.polyjet.audio.AudioInfo;
import zero1hd.polyjet.audio.map.RhythmMapAlgorithm;
import zero1hd.polyjet.ui.builders.ScrollText;
import zero1hd.polyjet.util.MiniEvents;
import zero1hd.polyjet.util.MiniListener;

public class AnalyzePage extends Page implements MiniListener {
	AudioAnalyzer audioAnalyzer;
	AudioData music;
	RhythmMapAlgorithm mapGenAlgorithm;
	
	private Table songInfo;
	private volatile Label[] info;
	
	Table difficultyTable;
	private Label diffTitle;
	private Slider sensitivityRating;
	private Label sensitivityRatingTitle;
	private Slider speedModifier;
	private Label speedModifierTitle;
	private Slider healthModifier;
	private Label healthModifierTitle;
	private TextButton confirmDiffButton;
	private boolean confirmed;
	private Skin skin;
	
	private Table beginTable;
	private TextButton beginButton;
	
	private TextButton back;
	private Image loadingCircle;
	private long startTime, endTime;
	
	private Thread mapGenThread;
	
	public AnalyzePage(Skin skin, AssetManager assets) {
		super("Results", skin);
		this.skin = skin;
		
		songInfo = new Table(skin);
		songInfo.align(Align.top);
		songInfo.pad(15f);
		songInfo.setBackground(skin.getDrawable("large-pane"));
		addActor(songInfo);
		
		difficultyTable = new Table(skin);
		difficultyTable.setBackground(skin.getDrawable("large-pane"));
		addActor(difficultyTable);
		
		diffTitle = new Label("Difficulty", skin);
		difficultyTable.add(diffTitle).expandX().left();
		
		difficultyTable.row();
		
		sensitivityRating = new Slider(-5f, 5f, 1f, false, skin);
		sensitivityRating.setValue(0f);
		sensitivityRating.addListener(new ChangeListener() {
			
			@Override
			public void changed(ChangeEvent event, Actor actor) {
				sensitivityRatingTitle.setText("Base Difficulty: " + sensitivityRating.getValue());
			}
		});
		
		sensitivityRatingTitle = new Label("Base Difficulty: " + sensitivityRating.getValue(), skin, "sub-font", skin.getColor("default"));
		difficultyTable.add(sensitivityRatingTitle);
		difficultyTable.row();
		difficultyTable.add(sensitivityRating).fillX();
		
		difficultyTable.row();
		
		speedModifier = new Slider(1f, 3f, 0.25f, false, skin);
		speedModifier.setValue(1f);
		speedModifier.addListener(new ChangeListener() {
			@Override
			public void changed(ChangeEvent event, Actor actor) {
				speedModifierTitle.setText("Speed Modifier: x" + speedModifier.getValue());
			}
		});
		speedModifierTitle = new Label("Speed Modifier: x" + speedModifier.getValue(), skin, "sub-font", skin.getColor("default"));
		difficultyTable.add(speedModifierTitle);
		difficultyTable.row();
		difficultyTable.add(speedModifier).fillX();
		
		difficultyTable.row();

		healthModifier = new Slider(0f, 5f, 1f, false, skin);
		healthModifier.setValue(0f);
		healthModifier.addListener(new ChangeListener() {
			
			@Override
			public void changed(ChangeEvent event, Actor actor) {
				healthModifierTitle.setText("Health modifier: +" + healthModifier.getValue());
			}
		});
		healthModifierTitle = new Label("Health modifier: +" + healthModifier.getValue(), skin, "sub-font", skin.getColor("default"));
		difficultyTable.add(healthModifierTitle);
		difficultyTable.row();
		difficultyTable.add(healthModifier).fillX().spaceBottom(15f);
		
		difficultyTable.row();
		
		confirmDiffButton = new TextButton("Confirm", skin);
		confirmDiffButton.setDisabled(true);
		confirmDiffButton.addListener(new ChangeListener() {
			@Override
			public void changed(ChangeEvent event, Actor actor) {
				info[2].setText("Confirmed.");
				confirmed = true;
				confirmDiffButton.setDisabled(true);
				sensitivityRating.setDisabled(true);
				speedModifier.setDisabled(true);
				healthModifier.setDisabled(true);
				
				if (audioAnalyzer.containsData() ) {
					finalizeData();
				}
			}
		});
		difficultyTable.add(confirmDiffButton);
		
		difficultyTable.pack();
		
		beginTable = new Table(skin);
		beginTable.pad(15f);
		beginButton = new TextButton("Begin", skin);
		beginTable.add(beginButton);
		beginTable.setBackground(skin.getDrawable("large-pane"));
		beginTable.pack();
		addActor(beginTable);
		
		loadingCircle = new Image(assets.get("cybercircle1.png", Texture.class));
		loadingCircle.setPosition((getWidth()-loadingCircle.getWidth())/2, (getHeightBelowTitle()-loadingCircle.getHeight())/2);
		loadingCircle.setColor(0.8f,0.8f,0.8f,0.7f);
		loadingCircle.setOrigin(loadingCircle.getWidth()/2, loadingCircle.getHeight()/2);
		loadingCircle.addAction(Actions.forever(Actions.rotateBy(-360f, 4f)));
		addActor(loadingCircle);
		loadingCircle.toBack();
		
		back = new TextButton("Back", skin);
		back.setPosition(getWidth()-back.getWidth()-15f, getHeightBelowTitle());
		back.addListener(new ChangeListener() {
			@Override
			public void changed(ChangeEvent event, Actor actor) {
				miniSender.send(MiniEvents.BACK);
				if (audioAnalyzer != null) {
					audioAnalyzer.stop();
				}
			}
		});
		
		info = new Label[6];
		for (int i = 0; i < info.length; i++) {
			info[i] = new Label(null, skin, "sub-font", skin.getColor("default"));
		}
		
		addActor(back);
	}
	
	public void setSong(AudioData music, AudioInfo audioInfo, MiniListener listener) {
		confirmed = false;
		confirmDiffButton.setDisabled(false);
		sensitivityRating.setDisabled(false);
		speedModifier.setDisabled(false);
		healthModifier.setDisabled(false);
		
		songInfo.clear();
		songInfo.defaults().align(Align.left | Align.top);
		audioAnalyzer = new AudioAnalyzer();
		audioAnalyzer.sender.addListener(this);
		
		this.music = music;
		
		audioAnalyzer.startAnalyticalThread(music);
		songInfo.add(new ScrollText(audioInfo.getSongName(), skin, true)).expandX().fillX().spaceBottom(20f);
		
		for (int i = 0; i < info.length; i++) {
			info[i].setColor(1f, 1f, 1f, 0f);
			info[i].setText(null);
			songInfo.row();
			songInfo.add(info[i]);
		}
		
		songInfo.pack();
		songInfo.setWidth(getWidth()/2f);
		songInfo.setPosition((getWidth()-songInfo.getWidth())/2f, (getHeightBelowTitle()-songInfo.getHeight())/2f);
		difficultyTable.setPosition(songInfo.getX(), -difficultyTable.getHeight());
		difficultyTable.setWidth(songInfo.getWidth());
		beginTable.setPosition(difficultyTable.getX(), -beginTable.getHeight());
		beginTable.setWidth(difficultyTable.getWidth());
		
		startTime = System.currentTimeMillis();
		info[0].addAction(Actions.color(Color.BLACK, 2.5f));
	}
	
	
	@Override
	public void act(float delta) {
		super.act(delta);
	}
	
	public boolean hasAudioData() {
		if (music != null) {
			return true;
		} else {
			return false;
		}
	}
	
	public void clearAudioData() {
		music = null;
	}

	@Override
	public void handle(MiniEvents ID) {
		switch (ID) {
		case ANALYZER_ITERATED:
			if (audioAnalyzer.getProgress() == 50) {
				songInfo.addAction(Actions.moveTo(songInfo.getX(), getHeight()/2f, 0.75f, Interpolation.linear));
				difficultyTable.addAction(Actions.moveTo(songInfo.getX(), songInfo.getY()-difficultyTable.getHeight(),0.8f, Interpolation.linear));
				info[2].setText("Awaiting confirmation...");
				info[2].addAction(Actions.color(Color.BLACK, 0.75f));
				confirmDiffButton.setDisabled(false);
			}
			info[0].setText("Initial analysis: " + audioAnalyzer.getProgress() + "%");
			break;
		case SPECTRAL_FLUX_DONE:
			endTime = System.currentTimeMillis();
			info[1].setText("Done. Analyze time: " + ((endTime - startTime)/1000f) + "s");
			info[1].addAction(Actions.color(Color.BLACK, 0.75f));
			if (confirmed) {
				finalizeData();
			}
			break;
		case MUSIC_DATA_CLEANED:
			info[3].setText("data cleaning done.");
			info[4].addAction(Actions.color(Color.BLACK, 0.75f));
			mapGenAlgorithm = new RhythmMapAlgorithm(audioAnalyzer, speedModifier.getValue(), healthModifier.getValue());
			mapGenAlgorithm.getSender().addListener(this);
			mapGenThread = new Thread(mapGenAlgorithm);
			mapGenThread.start();
			startTime = System.currentTimeMillis();
			break;
		case MAPGEN_ITERATED:
			info[4].setText("Generating map: " + mapGenAlgorithm.getProgress() + "%");
			break;
		case MAP_GENERATED:
			endTime = System.currentTimeMillis();
			info[5].setText("Done. Generation time: " + ((endTime - startTime)/1000f) + "s");
			info[5].addAction(Actions.color(Color.BLACK, 0.75f));
			songInfo.addAction(Actions.moveTo(songInfo.getX(), getHeightBelowTitle()-songInfo.getHeight(), 0.75f, Interpolation.linear));
			difficultyTable.addAction(Actions.sequence(Actions.delay(0.4f), Actions.moveTo(songInfo.getX(), getHeightBelowTitle()-songInfo.getHeight()-difficultyTable.getHeight()-10f,0.8f, Interpolation.linear)));
			beginTable.addAction(Actions.sequence(Actions.delay(0.5f), Actions.moveTo(difficultyTable.getX(), getHeightBelowTitle()-songInfo.getHeight()-difficultyTable.getHeight()-beginTable.getHeight()-20f,0.8f, Interpolation.linear)));
		default:
			break;
		}
	}
	
	private void finalizeData() {
		Gdx.app.debug("analyze", "confirmed data finalization.");
		audioAnalyzer.runThresholdCleaning(sensitivityRating.getValue());
		info[3].setText("finalizing data...");
		info[3].addAction(Actions.color(Color.BLACK, 0.75f));
	}
}
