package de.ctdo.crashtest.mpd;

import de.ctdo.crashtest.log.Logger;
import org.bff.javampd.MPD;
import org.bff.javampd.MPDDatabase;
import org.bff.javampd.MPDPlayer;
import org.bff.javampd.MPDPlaylist;
import org.bff.javampd.exception.MPDConnectionException;
import org.bff.javampd.exception.MPDDatabaseException;
import org.bff.javampd.exception.MPDPlayerException;
import org.bff.javampd.exception.MPDPlaylistException;
import org.bff.javampd.objects.MPDSong;

import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

/**
 * A MPD abstraction to the org.bff.javampd library
 */
public class MPDController implements  IMPDController {
    private MPD mpd;

    public MPDController(String host) {
        try {
            mpd = new MPD(host, 6600);
        } catch (UnknownHostException e) {
            Logger.sLog("MPD error: " + e.getMessage());
        } catch (MPDConnectionException e) {
            Logger.sLog("MPD error: " + e.getMessage());
        }
    }

    /**
     * Play a song, defined by artist and track title
     * Song gets added to current playlist and is played.
     * @param artist Artist of the track to play
     * @param title  Title of the track to play
     */
    @Override
    public void playSong(final String artist, final String title) {
        if(mpd != null) {
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    addToPlayListIfNeeded(artist, title);

                    try {

                        MPDPlaylist playlist = mpd.getMPDPlaylist();

                        for(MPDSong song: playlist.getSongList()) {

                            if(song.getArtist() != null && song.getTitle() != null) {
                                if(song.getArtist().getName().toLowerCase().equals(artist.toLowerCase()) &&
                                        song.getTitle().toLowerCase().equals(title.toLowerCase())) {

                                    MPDPlayer player = mpd.getMPDPlayer();
                                    player.stop();
                                    player.playId(song);
                                    break;
                                }
                            }
                        }

                    } catch (MPDConnectionException e) {
                        Logger.sLog("MPD error: " + e.getMessage());
                    } catch (MPDPlayerException e) {
                        Logger.sLog("MPD error: " + e.getMessage());
                    }
                }
            };

            synchronized (mpd) {
                new Thread(r).start();
            }
        }
    }
    
    private void addToPlayListIfNeeded(final String artist, final String title) {
        MPDDatabase db = mpd.getMPDDatabase();
        MPDPlaylist playlist = mpd.getMPDPlaylist();

        try {
            List<MPDSong> tracks = new ArrayList<MPDSong>(db.findArtist(artist));

            for(MPDSong song: tracks) {
                if(song.getName() != null &&
                   song.getName().toLowerCase().contains(title.toLowerCase())) {

                    if(!playlist.getSongList().contains(song)) {
                        playlist.addSong(song);
                    }
                    break;
                }
            }

        } catch (MPDConnectionException e) {
            Logger.sLog("MPD error: " + e.getMessage());
        } catch (MPDDatabaseException e) {
            Logger.sLog("MPD error: " + e.getMessage());
        } catch (MPDPlaylistException e) {
            Logger.sLog("MPD error: " + e.getMessage());
        }
    }

    /**
     * Sets the current mpd volume
     * @param volume  the volume in percent (0-100)
     */
    @Override
    public void setVolume(final int volume) {
        if(mpd != null) {

            Runnable r = new Runnable() {
                @Override
                public void run() {
                    try {
                        mpd.getMPDPlayer().setVolume(volume);
                    } catch (MPDConnectionException e) {
                        Logger.sLog("MPD error: " + e.getMessage());
                    } catch (MPDPlayerException e) {
                        Logger.sLog("MPD error: " + e.getMessage());
                    }
                }
            };

            synchronized (mpd) {
                new Thread(r).start();
            }
        }
    }
}
