package com.radiostream.player;

import com.radiostream.javascript.bridge.PlaylistBridge;
import com.radiostream.networking.MetadataBackend;
import com.radiostream.networking.models.SongResult;

import org.jdeferred.DoneFilter;
import org.jdeferred.DonePipe;
import org.jdeferred.Promise;
import org.jdeferred.impl.DeferredObject;

import java.util.ArrayList;
import java.util.List;

import timber.log.Timber;

public class Playlist {
    private String mPlaylistName;
    private MetadataBackend mMetadataBackend;
    private SongFactory mSongFactory;

    private List<Song> mSongs = new ArrayList<Song>();
    private int mIndex = 0;

    public Playlist(String playlistName, MetadataBackend metadataBackend, SongFactory songFactory) {
        mPlaylistName = playlistName;
        mMetadataBackend = metadataBackend;
        mSongFactory = songFactory;
    }

    private Promise<Void, Exception, Void> reloadIfNeededForSongIndex(int index) {
        Timber.i("checking if reload is needed. songs count: %d Current index: %d", mSongs.size(), mIndex);
        if(index >= mSongs.size()) {
            Timber.i("reloading songs");

            return mMetadataBackend.fetchPlaylist(mPlaylistName).then(new DoneFilter<List<SongResult>, Void>() {
                @Override
                public Void filterDone(List<SongResult> result) {
                    if (result.size() == 0) {
                        throw new RuntimeException("Empty playlists are currently unhandled");
                    }

                    for (SongResult songResult : result) {
                        mSongs.add(mSongFactory.build(songResult));
                    }

                    return null;
                }
            });
        } else {
            Timber.i("no reload required");
            return new DeferredObject<Void, Exception, Void>().resolve(null).promise();
        }
    }

    public Promise<Song, Exception, Void> peekCurrentSong() {
        Timber.i("function start");
        
        return peekSong(mIndex);
    }

    public Promise<Song, Exception, Void> peekNextSong() {
        Timber.i("function start");

        return peekSong(mIndex + 1);
    }

    public boolean isCurrentSong(Song song) {
        if(mIndex < mSongs.size()) {
            Timber.i("checking if given song '%s' is the current song", song.toString());
            return mSongs.get(mIndex) == song;
        } else {
            Timber.i("current index %d out of songs bounds %d - this can't be the current song", mIndex, mSongs.size());
            // it can't be the current song - current index is already beyond the bounds of the playlist
            return false;
        }
    }

    public void nextSong() {
        Timber.i("function start. From %d to %d", mIndex, mIndex+1);
        mIndex++;
    }

    private Promise<Song, Exception, Void> peekSong(final int index) {
        Timber.i("function start. index: %d", index);

        return reloadIfNeededForSongIndex(index).then(new DonePipe<Void, Song, Exception, Void>() {
            @Override
            public Promise<Song, Exception, Void> pipeDone(Void result) {
                DeferredObject<Song, Exception, Void> deferredObject = new DeferredObject<>();
                Song resolve = mSongs.get(index);
                Timber.i("peeked next song: %s", resolve.toString());
                return deferredObject.resolve(resolve).promise();
            }
        });
    }

    public PlaylistBridge toBridgeObject() {
        final PlaylistBridge playlistBridge = new PlaylistBridge();
        playlistBridge.name = mPlaylistName;
        return playlistBridge;
    }

    public void close() {
        Timber.i("closing all songs");
        for(Song song : mSongs) {
            song.close();
        }
    }
}

@@ -1058,16 +1058,17 @@
       if
+ 
 (index %3E
@@ -1206,22 +1206,20 @@
 new Done
-Filter
+Pipe
 %3CList%3CSo
@@ -1228,16 +1228,33 @@
 Result%3E,
+ Void, Exception,
  Void%3E()
@@ -1309,19 +1309,43 @@
 lic 
-Void filter
+Promise%3CVoid, Exception, Void%3E pipe
 Done
@@ -1446,25 +1446,135 @@
     
-throw new Runtime
+Timber.e(%22empty playlist was returned%22);%0A                        return new DeferredObject%3CVoid, Exception, Void%3E().reject(new 
 Exce
@@ -1599,33 +1599,20 @@
 ists
- are currently unhandled%22
+%22)).promise(
 );%0A 
@@ -1811,19 +1811,82 @@
 return n
-ull
+ew DeferredObject%3CVoid, Exception, Void%3E().resolve(null).promise()
 ;%0A      
@@ -2177,24 +2177,16 @@
 tart%22);%0A
-        
 %0A       
@@ -2414,16 +2414,17 @@
       if
+ 
 (mIndex 
@@ -2958,17 +2958,19 @@
 , mIndex
-+
+ + 
 1);%0A    
@@ -3403,24 +3403,50 @@
 Object%3C%3E();%0A
+                try %7B%0A    
             
@@ -3479,24 +3479,28 @@
 get(index);%0A
+    
             
@@ -3569,24 +3569,28 @@
             
+ 
+   
 return defer
@@ -3619,32 +3619,191 @@
 lve).promise();%0A
+                %7D catch (Exception e) %7B%0A                    Timber.e(e, %22peek failed%22);%0A                    return deferredObject.reject(e);%0A                %7D%0A
             %7D%0A  
@@ -4091,16 +4091,17 @@
      for
+ 
 (Song so

handle empty playlists