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.sql.SQLOutput;
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) {
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    synchronized (mpd) {


                        doPlaySong(artist,title);
                    }
                }
            };

            //new Thread(r).start();
            r.run();
        }
    }

    private void doPlaySong(final String artist, final String title) {
        try {
            MPDPlaylist playlist = mpd.getMPDPlaylist();
            MPDPlayer player = mpd.getMPDPlayer();

            int tries = 3;

            while(tries>0) {
                addToPlayListIfNeeded(artist, title);

                for(MPDSong song: playlist.getSongList()) {
                    if(checkSong(song, artist, title)) {
                        System.out.println("MPD: stopping, playing, go...");
                        player.stop();
                        player.playId(song);
                        break;
                    }
                }

                // now check, if it is playing

                MPDSong song = player.getCurrentSong();

                if(checkSong(song, artist, title)) {
                    System.out.println("MPD: song is correctly playing");
                    return;
                } else {
                    System.out.println("MPD: wrong track is playing");
                }

                System.out.println("MPD: next try");
                tries--;
            }

            Logger.sLog("MPD error: track not in playlist or not found... cannot play");

        } catch (MPDConnectionException e) {
            Logger.sLog("MPD error: " + e.getMessage());
        } catch (MPDPlayerException e) {
            Logger.sLog("MPD error: " + e.getMessage());
        }
    }
    
    private boolean checkSong(final MPDSong song, final String artist, final String title) {
        if(song != null) {
            if(song.getArtist() != null && song.getTitle() != null) {
                if(song.getArtist().getName().toLowerCase().contentEquals(artist.toLowerCase()) &&
                    song.getTitle().toLowerCase().contentEquals(title.toLowerCase())) {
                    return true;
                }
            } else {
                System.out.println("MPD: song is nullb");
            }
        } else {
            System.out.println("MPD: track title or artist is null " + artist + " - " + title);
        }
        return false;
    }

    /**
     * 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) {
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    synchronized (mpd) {
                        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());
                        }
                    }
                }
            };

            //new Thread(r).start();
            r.run();
        }
    }

    @Override
    public void skipRandomStart() {
        if(mpd != null) {
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    synchronized (mpd) {
                        MPDPlayer player = mpd.getMPDPlayer();

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

            //new Thread(r).start();
            r.run();
        }
    }

    /**
     * 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() {
                    synchronized (mpd) {
                        try {
                            mpd.getMPDPlayer().setVolume(volume);
                        } catch (MPDConnectionException e) {
                            Logger.sLog("MPD error: " + e.getMessage());
                        } catch (MPDPlayerException e) {
                            Logger.sLog("MPD error: " + e.getMessage());
                        }
                    }
                }
            };
            //new Thread(r).start();
            r.run();
        }
    }

    /**
     * Clears the current mpd playlist
     */
    @Override
    public void clearPlaylist() {
        if(mpd != null) {
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    synchronized (mpd) {
                        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());
                        }
                    }
                }
            };

            //new Thread(r).start();
            r.run();
        }
    }

    private void addToPlayListIfNeeded(final String artist, final String title) {
        MPDDatabase db = mpd.getMPDDatabase();
        MPDPlaylist playlist = mpd.getMPDPlaylist();

        int count;

        for(count = 0; count < 3; count++) {

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

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

}
