package zero1hd.rhythmbullet.desktop.screens.main;

import java.util.Observable;
import java.util.Observer;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.ParticleEffect;
import com.badlogic.gdx.graphics.g2d.ParticleEffectPool;
import com.badlogic.gdx.graphics.g2d.ParticleEffectPool.PooledEffect;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.Actor;
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.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Array;

import zero1hd.rhythmbullet.RhythmBullet;
import zero1hd.rhythmbullet.audio.MusicController;
import zero1hd.rhythmbullet.audio.AudioMetadataController;
import zero1hd.rhythmbullet.audio.visualizer.DoubleHorizontalVisualizer;
import zero1hd.rhythmbullet.desktop.audio.PCMObtainer;
import zero1hd.rhythmbullet.graphics.ui.Page;
import zero1hd.rhythmbullet.graphics.ui.components.MusicControls;
import zero1hd.rhythmbullet.graphics.ui.components.ScrollingText;
import zero1hd.rhythmbullet.util.ScreenConfiguration;

public class MainPage extends Page implements Observer {
	private MusicController mc;
	private AudioMetadataController amc;
	
	private Label versionLabel;
	private Image title;
	
	private Table menuTable;
	private TextButton playButton;
	private TextButton optionsButton;
	private TextButton quitButton;
	
	private MusicControls musicControls;
	private ScrollingText scrollText;
	
	private DoubleHorizontalVisualizer dhv;
	
	private boolean playParticles = true;
	private ParticleEffectPool particlePool;
	private Array<PooledEffect> particles;
	private float particleScale;
	
	public MainPage(MusicController musicController, AudioMetadataController mmc, AssetManager assetManager, Skin skin, ScreenConfiguration screenConfiguration, ChangeListener playButtonListener, ChangeListener optionsButtonListener) {
		super(0, 0);
		this.mc = musicController;
		this.mc.addObserver(this);
		mc.getMusicList().addObserver(this);
		this.amc = mmc;
		this.amc.addObserver(this);

		dhv = new DoubleHorizontalVisualizer((int) getWidth(), (int) 0, getHeight(), 0, screenConfiguration.getTargetFramesPerSecond(), mc, new PCMObtainer(mc));
		dhv.setPosition(0, (int) ((getHeight() - dhv.getHeight())/2f));
		
		title = new Image(assetManager.get("title.png", Texture.class));
		title.setScale((getHeight()/3f)/title.getHeight());
		if (title.getWidth()*title.getScaleX() > getWidth() - getWidth()*0.075f) {
			title.setScale((getWidth()*(1f-0.075f))/title.getWidth()*getScaleX());
		}
		title.setPosition((getWidth()-title.getWidth()*title.getScaleX())/2f, (getHeight()-title.getHeight()*title.getScaleY())/2f);
		addActor(title);
		
		versionLabel = new Label("Version: " + RhythmBullet.VERSION, skin, "sub-font", skin.getColor("default"));
		versionLabel.setPosition(3, 3);
		addActor(versionLabel);
		
		menuTable = new Table();
		menuTable.setSize(getWidth(), title.getY());
		menuTable.align(Align.center);
		menuTable.defaults().space(10f);
		addActor(menuTable);
		playButton = new TextButton("Start!", skin);
		playButton.addListener(playButtonListener);
		menuTable.add(playButton).width(Gdx.graphics.getWidth()*0.2f);
		
		menuTable.row();
		
		optionsButton = new TextButton("Options", skin, "sub");
		optionsButton.addListener(optionsButtonListener);
		menuTable.add(optionsButton).fillX();
		
		menuTable.row();
		
		quitButton = new TextButton("Quit", skin, "sub");
		quitButton.addListener(new ChangeListener() {
			@Override
			public void changed(ChangeEvent event, Actor actor) {
				Gdx.app.exit();
			}
		});
		menuTable.add(quitButton).fillX();
		
		musicControls = new MusicControls(skin, mc);
		musicControls.setPosition((getWidth()-musicControls.getWidth() - 15f), 15f);
		addActor(musicControls);
		
		scrollText = new ScrollingText("...", "...", skin, false, true, 1f/screenConfiguration.getTargetFramesPerSecond());
		scrollText.setWidth(0.5f*getWidth());
		scrollText.setPosition(15, getHeight() - scrollText.getHeight()-30f);
		addActor(scrollText);
		
		if (mc.getMusicList().isSearched() && amc.isSameSizeMusicList()) {
			scrollText.setText("Currently playing: " + amc.getAudioMetadata(mc.getCurrentMusicFileHandle()).getTitle(), null);
			dhv.updateMusic();
		}
		
		particles = new Array<>();
		ParticleEffect particle = assetManager.get("beateffect.p", ParticleEffect.class);
		particleScale = getWidth()/particle.findEmitter("main").getSpawnWidth().getHighMax();
		particlePool = new ParticleEffectPool(assetManager.get("beateffect.p", ParticleEffect.class), 0, 16);
		
	}
	
	@Override
	public void act(float delta) {
		dhv.act(delta);
		super.act(delta);
	}
	
	@Override
	public void draw(Batch batch, float parentAlpha) {
		dhv.draw(batch, parentAlpha);
		updateParticles(batch);
		super.draw(batch, parentAlpha);
	}
	
	private void updateParticles(Batch batch) {
		if (playParticles) {
			if (particles.size < 16 && dhv.isSignificantBeat()) {
				PooledEffect particle = particlePool.obtain();
				particle.scaleEffect(particleScale);
				particles.add(particle);
			}
			if (particles.size > 0) {
				for (int i = particles.size - 1; i >= 0 && particles.size > 0; i--) {
					PooledEffect particle = particles.get(i);
					particle.draw(batch, Gdx.graphics.getDeltaTime());
					if (particle.isComplete()) {
						particles.removeIndex(i);
						particle.free();
					}
				}
			}
		}
	}
	
	public void stopParticles() {
		playParticles = false;
	}
	
	@Override
	public void dispose() {
		dhv.dispose();
		mc.getMusicList().deleteObserver(this);
		for (int i = particles.size - 1; i >= 0 && particles.size > 0; i--) {
			particles.get(i).free();
			particles.clear();
		}
		super.dispose();
	}
	
	@Override
	public void setCameraPositionToPage(Vector3 cameraPosition) {
		getStage().setScrollFocus(null);
		playParticles = true;
		super.setCameraPositionToPage(cameraPosition);
	}
	
	@Override
	public void update(Observable o, Object arg) {
		if (o == mc) {
			if (arg == mc.states.LOADED) {
				if (amc.isSameSizeMusicList()) {
					scrollText.setText("Currently playing: " + amc.getAudioMetadata(mc.getCurrentMusicFileHandle()).getTitle(), null);
				} else {
					scrollText.setText("Currently playing: " + mc.getCurrentMusicFileHandle().nameWithoutExtension().replace('_', ' '), null);
				}
			} else if (arg == mc.states.PAUSED) {
				if (amc.isSameSizeMusicList()) {
					scrollText.setText("Currently paused: " + amc.getAudioMetadata(mc.getCurrentMusicFileHandle()).getTitle(), null);
				} else {
					scrollText.setText("Currently paused: " + mc.getCurrentMusicFileHandle().nameWithoutExtension().replace('_', ' '), null);
				}
			}
	    } else if (o == amc) {
	    	if (amc.isSameSizeMusicList()) {
				scrollText.setText("Currently playing: " + amc.getAudioMetadata(mc.getCurrentMusicFileHandle()).getTitle(), null);
	    	}
	    } else if (o == mc.getMusicList()) {
	    	if (arg == mc.getMusicList().states.EMPTY) {
	    		scrollText.setText("Couldn't find MP3/WAV files", null);
	    	} else if (arg == mc.getMusicList().states.LOADING) {
	    		scrollText.setText("Loading...", null);
	    	}
	    }
	}
}
