package de.tobias.playpad;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;

import de.tobias.playpad.audio.AudioHandler;
import de.tobias.playpad.pad.PadStatus;
import de.tobias.playpad.pad.conntent.PadContent;
import de.tobias.utils.util.Worker;
import javafx.application.Platform;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.util.Duration;

public class NativeAudioMacHandler extends AudioHandler {

	private static final int SLEEP_TIME_POSITION = 100;

	private static int counter = 0;

	private final int id;
	private ObjectProperty<Duration> positionProperty;
	private ObjectProperty<Duration> durationProperty;
	private boolean isLoaded;

	private static Thread positionThread;
	private static List<NativeAudioMacHandler> playedHandlers = new ArrayList<>();

	static {
		positionThread = new Thread(() ->
		{
			while (true) {
				try {
					if (playedHandlers.isEmpty()) {
						synchronized (positionThread) {
							positionThread.wait();
						}
					}

					for (Iterator<NativeAudioMacHandler> iterator = playedHandlers.iterator(); iterator.hasNext();) {
						NativeAudioMacHandler handler = iterator.next();
						Duration seconds = Duration.seconds(NativeAudio.getPosition(handler.id));

						Platform.runLater(() -> handler.positionProperty.set(seconds));
					}

					Thread.sleep(SLEEP_TIME_POSITION);
				} catch (InterruptedException e) {
				} catch (ConcurrentModificationException e) {
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});

		positionThread.start();
	}

	public NativeAudioMacHandler(PadContent content) {
		super(content);

		id = counter++;
		positionProperty = new SimpleObjectProperty<>();
		durationProperty = new SimpleObjectProperty<>();
	}

	@Override
	public void play() {
		NativeAudio.play(id);

		boolean start = false;
		if (playedHandlers.isEmpty()) {
			start = true;
		}

		if (!playedHandlers.contains(this))
			playedHandlers.add(this);
		if (start) {
			synchronized (positionThread) {
				positionThread.notify();
			}
		}
	}

	@Override
	public void pause() {
		NativeAudio.pause(id);
		if (playedHandlers.contains(this))
			playedHandlers.remove(this);
	}

	@Override
	public void stop() {
		NativeAudio.stop(id);
		if (playedHandlers.contains(this))
			playedHandlers.remove(this);
	}

	@Override
	public Duration getPosition() {
		return positionProperty.get();
	}

	@Override
	public ReadOnlyObjectProperty<Duration> positionProperty() {
		return positionProperty;
	}

	@Override
	public Duration getDuration() {
		return durationProperty.get();
	}

	@Override
	public ReadOnlyObjectProperty<Duration> durationProperty() {
		return durationProperty;
	}

	@Override
	public void setVolume(double volume, double masterVolume, double customVolume) {
		double vol = customVolume * volume * masterVolume;
		NativeAudio.setVolume(id, vol);

	}

	@Override
	public boolean isMediaLoaded() {
		return isLoaded;
	}

	@Override
	public void loadMedia(Path[] paths) {
		Platform.runLater(() ->
		{
			if (getContent().getPad().isPadVisible()) {
				getContent().getPad().getController().getView().showBusyView(true);
			}
		});
		Worker.runLater(() ->
		{
			isLoaded = NativeAudio.load(id, paths[0].toString().replace(" ", "%20"));
			if (isLoaded) {
				Platform.runLater(() ->
				{
					durationProperty.set(Duration.seconds(NativeAudio.getDuration(id)));
					getContent().getPad().setStatus(PadStatus.READY);
					if (getContent().getPad().isPadVisible()) {
						getContent().getPad().getController().getView().showBusyView(false);
					}
				});
			}
		});
	}

	@Override
	public void unloadMedia() {
		NativeAudio.dispose(id);
	}

}