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;
import java.util.Random;

/**
 * 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) {
        System.out.println("playSong: " + artist + " - " + title);
        if(mpd != null) {

            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());
            }

        }
    }

    /**
     * Add a song to current mpd playlist
     * @param artist Artist of the track to play
     * @param title  Title of the track to play
     */
    @Override
    public void addToPlayList(final String artist, final String title) {
        if(mpd != null) {

            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())) {
                        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());
            }
        }
    }

    @Override
    public void skipRandomStart() {
        if(mpd != null) {
            MPDPlayer player = mpd.getMPDPlayer();

            try {
                int length;
                MPDSong song = player.getCurrentSong();
                if(song!= null) {
                    length = song.getLength();
                    int skip = new Random().nextInt(length/2);
                    player.seek(skip);
                }
            } catch (MPDConnectionException e) {
                e.printStackTrace();
            } catch (MPDPlayerException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Sets the current mpd volume
     * @param volume  the volume in percent (0-100)
     */
    @Override
    public void setVolume(final int volume) {
        if(mpd != null) {
            try {
                mpd.getMPDPlayer().setVolume(volume);
            } catch (MPDConnectionException e) {
                Logger.sLog("MPD error: " + e.getMessage());
            } catch (MPDPlayerException e) {
                Logger.sLog("MPD error: " + e.getMessage());
            }
        }
    }

    /**
     * Clears the current mpd playlist
     */
    @Override
    public void clearPlaylist() {
        if(mpd != null) {
            try {
                MPDPlaylist playlist = mpd.getMPDPlaylist();
                playlist.clearPlaylist();
                mpd.getMPDPlayer().setRandom(false);
                mpd.getMPDPlayer().setXFade(1);
            } catch (MPDConnectionException e) {
                Logger.sLog("MPD error: " + e.getMessage());
            } catch (MPDPlaylistException e) {
                Logger.sLog("MPD error: " + e.getMessage());
            } catch (MPDPlayerException e) {
                Logger.sLog("MPD error: " + e.getMessage());
            }
        }
    }

    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());
        }
    }

}
