/* == This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
 *
 *   Copyright 2012, Enno Gottschalk <mrmaffen@googlemail.com>
 *
 *   Tomahawk is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   Tomahawk is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
 */
package org.tomahawk.tomahawk_android.fragments;

import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.animation.ValueAnimator;
import com.sothree.slidinguppanel.SlidingUpPanelLayout;

import org.tomahawk.libtomahawk.collection.CollectionManager;
import org.tomahawk.libtomahawk.collection.Image;
import org.tomahawk.libtomahawk.collection.PlaylistEntry;
import org.tomahawk.libtomahawk.database.DatabaseHelper;
import org.tomahawk.libtomahawk.resolver.Query;
import org.tomahawk.libtomahawk.utils.ImageUtils;
import org.tomahawk.libtomahawk.utils.ViewUtils;
import org.tomahawk.tomahawk_android.R;
import org.tomahawk.tomahawk_android.TomahawkApp;
import org.tomahawk.tomahawk_android.activities.TomahawkMainActivity;
import org.tomahawk.tomahawk_android.adapters.AlbumArtSwipeAdapter;
import org.tomahawk.tomahawk_android.adapters.Segment;
import org.tomahawk.tomahawk_android.adapters.TomahawkListAdapter;
import org.tomahawk.tomahawk_android.services.PlaybackService;
import org.tomahawk.tomahawk_android.utils.AnimationUtils;
import org.tomahawk.tomahawk_android.utils.FragmentUtils;
import org.tomahawk.tomahawk_android.views.AlbumArtViewPager;
import org.tomahawk.tomahawk_android.views.PlaybackFragmentFrame;

import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

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

/**
 * This {@link android.support.v4.app.Fragment} represents our Playback view in which the user can
 * play/stop/pause. It is being shown as the topmost fragment in the {@link PlaybackFragment}'s
 * {@link se.emilsjolander.stickylistheaders.StickyListHeadersListView}.
 */
public class PlaybackFragment extends TomahawkFragment {

    private AlbumArtSwipeAdapter mAlbumArtSwipeAdapter;

    private AlbumArtViewPager mAlbumArtViewPager;

    private int mOriginalViewPagerHeight;

    private Toast mToast;

    public abstract static class ShowContextMenuListener {

        public abstract void onShowContextMenu(Query query);

        public abstract void onDoubleTap(Query query);
    }

    private final ShowContextMenuListener mShowContextMenuListener = new ShowContextMenuListener() {

        @Override
        public void onShowContextMenu(Query query) {
            FragmentUtils.showContextMenu((TomahawkMainActivity) getActivity(), query, null, true,
                    true);
        }

        @Override
        public void onDoubleTap(Query query) {
            final ImageView imageView =
                    (ImageView) getView().findViewById(R.id.imageview_favorite_doubletap);
            if (DatabaseHelper.get().isItemLoved(query)) {
                ImageUtils.loadDrawableIntoImageView(TomahawkApp.getContext(), imageView,
                        R.drawable.ic_action_unfavorite_large);
            } else {
                ImageUtils.loadDrawableIntoImageView(TomahawkApp.getContext(), imageView,
                        R.drawable.ic_action_favorite_large);
            }
            AnimationUtils.fade(imageView, AnimationUtils.DURATION_CONTEXTMENU, true);
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    AnimationUtils.fade(imageView, AnimationUtils.DURATION_CONTEXTMENU, false);
                }
            };
            new Handler().postDelayed(r, 2000);
            CollectionManager.get().toggleLovedItem(query);
        }
    };

    @SuppressWarnings("unused")
    public void onEventMainThread(TomahawkMainActivity.SlidingLayoutChangedEvent event) {
        switch (event.mSlideState) {
            case COLLAPSED:
            case EXPANDED:
                if (mAlbumArtSwipeAdapter != null) {
                    mAlbumArtSwipeAdapter.notifyDataSetChanged();
                }
                if (getListView() != null) {
                    getListView().smoothScrollToPosition(0);
                }
                break;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setRestoreScrollPosition(false);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        return inflater.inflate(R.layout.playback_fragment, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        ViewUtils.afterViewGlobalLayout(new ViewUtils.ViewRunnable(view) {
            @Override
            public void run() {
                if (getListView() != null) {
                    mHeaderScrollableHeight =
                            getLayedOutView().getHeight() - mHeaderNonscrollableHeight;
                    setupScrollableSpacer(getListAdapter(), getListView(), mAlbumArtViewPager);
                    setupNonScrollableSpacer(getListView());
                }
            }
        });

        getListView().setFastScrollEnabled(false);

        mAlbumArtViewPager = (AlbumArtViewPager) view.findViewById(R.id.albumart_viewpager);
        mAlbumArtViewPager.setShowContextMenuListener(mShowContextMenuListener);
        mAlbumArtViewPager
                .setPlaybackService(((TomahawkMainActivity) getActivity()).getPlaybackService());

        PlaybackFragmentFrame playbackFragmentFrame = (PlaybackFragmentFrame) view.getParent();
        playbackFragmentFrame.setListView(getListView());
        playbackFragmentFrame.setPanelLayout(
                ((TomahawkMainActivity) getActivity()).getSlidingUpPanelLayout());

        if (mContainerFragmentClass == null) {
            getActivity().setTitle("");
        }

        //Set listeners on our buttons
        view.findViewById(R.id.imageButton_shuffle).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onShuffleClicked();
            }
        });
        view.findViewById(R.id.imageButton_repeat).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onRepeatClicked();
            }
        });
        View closeButton = view.findViewById(R.id.close_button);
        closeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SlidingUpPanelLayout slidingLayout =
                        ((TomahawkMainActivity) getActivity()).getSlidingUpPanelLayout();
                slidingLayout.collapsePanel();
            }
        });
        TextView closeButtonText = (TextView) closeButton.findViewById(R.id.close_button_text);
        closeButtonText.setText(getString(R.string.button_close).toUpperCase());

        SharedPreferences preferences =
                PreferenceManager.getDefaultSharedPreferences(getActivity());
        if (!preferences.getBoolean(
                TomahawkMainActivity.COACHMARK_PLAYBACKFRAGMENT_NAVIGATION_DISABLED, false)) {
            final View coachMark = ViewUtils.ensureInflation(view,
                    R.id.playbackfragment_navigation_coachmark_stub,
                    R.id.playbackfragment_navigation_coachmark);
            coachMark.findViewById(R.id.close_button).setOnClickListener(
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            coachMark.setVisibility(View.GONE);
                        }
                    });
            coachMark.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public void onResume() {
        super.onResume();

        PlaybackService playbackService = ((TomahawkMainActivity) getActivity())
                .getPlaybackService();

        onPlaylistChanged();

        mAlbumArtSwipeAdapter = new AlbumArtSwipeAdapter((TomahawkMainActivity) getActivity(),
                getActivity().getLayoutInflater(), mAlbumArtViewPager);
        mAlbumArtSwipeAdapter.setPlaybackService(playbackService);
        mAlbumArtViewPager.setAdapter(mAlbumArtSwipeAdapter);

        setupAlbumArtAnimation();

        refreshTrackInfo();
        refreshRepeatButtonState();
        refreshShuffleButtonState();
        updateAdapter();
    }

    /**
     * Called every time an item inside a ListView or GridView is clicked
     *
     * @param view the clicked view
     * @param item the Object which corresponds to the click
     */
    @Override
    public void onItemClick(View view, Object item) {
        PlaybackService playbackService = ((TomahawkMainActivity) getActivity())
                .getPlaybackService();
        if (playbackService != null) {
            if (item instanceof PlaylistEntry) {
                PlaylistEntry entry = (PlaylistEntry) item;
                if (entry.getQuery().isPlayable()) {
                    // if the user clicked on an already playing track
                    if (playbackService.getCurrentEntry() == entry) {
                        playbackService.playPause();
                    } else {
                        playbackService.setCurrentEntry(entry);
                    }
                }
            }
        }
    }

    /**
     * Called every time an item inside a ListView or GridView is long-clicked
     *
     * @param item the Object which corresponds to the long-click
     */
    @Override
    public boolean onItemLongClick(View view, Object item) {
        if (item != null) {
            TomahawkMainActivity activity = (TomahawkMainActivity) getActivity();
            AnimationUtils
                    .fade(activity.getPlaybackPanel(), AnimationUtils.DURATION_CONTEXTMENU, false);
            return FragmentUtils
                    .showContextMenu((TomahawkMainActivity) getActivity(), item, null, false, true);
        }
        return false;
    }

    /**
     * If the PlaybackService signals, that it is ready, this method is being called
     */
    @Override
    public void onPlaybackServiceReady() {
        super.onPlaybackServiceReady();

        PlaybackService playbackService = ((TomahawkMainActivity) getActivity())
                .getPlaybackService();
        if (playbackService != null) {
            if (mAlbumArtSwipeAdapter != null) {
                mAlbumArtSwipeAdapter.setPlaybackService(playbackService);
                refreshTrackInfo();
                refreshRepeatButtonState();
                refreshShuffleButtonState();
            }
            mAlbumArtViewPager.setPlaybackService(playbackService);
        }
        onPlaylistChanged();
    }

    /**
     * Called when the PlaybackServiceBroadcastReceiver received a Broadcast indicating that the
     * track has changed inside our PlaybackService
     */
    @Override
    public void onTrackChanged() {
        super.onTrackChanged();

        refreshTrackInfo();
        updateAdapter();
    }

    /**
     * Called when the PlaybackServiceBroadcastReceiver received a Broadcast indicating that the
     * playlist has changed inside our PlaybackService
     */
    @Override
    public void onPlaylistChanged() {
        super.onPlaylistChanged();

        forceResolveVisibleItems(false);
        updateAdapter();

        refreshRepeatButtonState();
        refreshShuffleButtonState();
        if (mAlbumArtSwipeAdapter != null) {
            mAlbumArtSwipeAdapter.updatePlaylist();
        }
    }

    /**
     * Called when the PlaybackServiceBroadcastReceiver in PlaybackFragment received a Broadcast
     * indicating that the playState (playing or paused) has changed inside our PlaybackService
     */
    @Override
    public void onPlaystateChanged() {
        super.onPlaystateChanged();

        if (mAlbumArtSwipeAdapter != null) {
            mAlbumArtSwipeAdapter.updatePlaylist();
        }
    }

    /**
     * Update this {@link TomahawkFragment}'s {@link TomahawkListAdapter} content
     */
    @Override
    protected void updateAdapter() {
        if (!mIsResumed) {
            return;
        }

        PlaybackService playbackService =
                ((TomahawkMainActivity) getActivity()).getPlaybackService();
        if (playbackService != null) {
            List<Segment> segments = new ArrayList<>();
            List entries = new ArrayList();
            entries.add(playbackService.getCurrentEntry());
            Segment segment = new Segment.Builder(entries).build();
            segment.setShowNumeration(true, 0);
            segments.add(segment);

            entries = new ArrayList();
            entries.addAll(playbackService.getQueue().getEntries());
            entries.remove(playbackService
                    .getCurrentEntry()); // don't show queue entry if currently playing
            segment = new Segment.Builder(entries).build();
            segment.setShowAsQueued(true);
            segments.add(segment);

            if (playbackService.getPlaylist().size() > 1) {
                int currentIndex;
                if (playbackService.getQueue().getIndexOfEntry(playbackService.getCurrentEntry())
                        > 0) {
                    currentIndex = playbackService.getQueueStartPos();
                } else {
                    currentIndex = playbackService.getPlaylist()
                            .getIndexOfEntry(playbackService.getCurrentEntry());
                }
                segment = new Segment.Builder(playbackService.getPlaylist())
                        .offset(Math.max(1, currentIndex + 1))
                        .build();
                segment.setShowNumeration(true, 1);
                segments.add(segment);
            }
            fillAdapter(segments, mAlbumArtViewPager, null);
        }
    }

    private void setupAlbumArtAnimation() {
        if (mAlbumArtViewPager != null) {
            ViewUtils.afterViewGlobalLayout(new ViewUtils.ViewRunnable(mAlbumArtViewPager) {
                @Override
                public void run() {
                    if (mOriginalViewPagerHeight <= 0) {
                        mOriginalViewPagerHeight = mAlbumArtViewPager.getHeight();
                    }

                    // now calculate the animation goal and instantiate the animation
                    int playbackPanelHeight = TomahawkApp.getContext().getResources()
                            .getDimensionPixelSize(R.dimen.playback_panel_height);
                    ValueAnimator animator = ObjectAnimator
                            .ofFloat(getLayedOutView(), "y", playbackPanelHeight,
                                    getLayedOutView().getHeight() / -4)
                            .setDuration(10000);
                    animator.setInterpolator(new AccelerateDecelerateInterpolator());
                    addAnimator(ANIM_ALBUMART_ID, animator);

                    refreshAnimations();
                }
            });
        }
    }

    /**
     * Called when the shuffle button is clicked.
     */
    public void onShuffleClicked() {
        final PlaybackService playbackService = ((TomahawkMainActivity) getActivity())
                .getPlaybackService();
        if (playbackService != null) {
            playbackService.setShuffled(!playbackService.isShuffled());

            if (mToast != null) {
                mToast.cancel();
            }
            mToast = Toast.makeText(getActivity(), getString(playbackService.isShuffled()
                    ? R.string.shuffle_on_label
                    : R.string.shuffle_off_label), Toast.LENGTH_SHORT);
            mToast.show();
        }
    }

    /**
     * Called when the repeat button is clicked.
     */
    public void onRepeatClicked() {
        final PlaybackService playbackService = ((TomahawkMainActivity) getActivity())
                .getPlaybackService();
        if (playbackService != null) {
            int repeatMode = playbackService.getRepeatingMode();
            if (repeatMode == PlaybackService.NOT_REPEATING) {
                playbackService.setRepeatingMode(PlaybackService.REPEAT_ALL);
            } else if (repeatMode == PlaybackService.REPEAT_ALL) {
                playbackService.setRepeatingMode(PlaybackService.REPEAT_ONE);
            } else if (repeatMode == PlaybackService.REPEAT_ONE) {
                playbackService.setRepeatingMode(PlaybackService.NOT_REPEATING);
            }
        }
    }

    /**
     * Refresh the information in this fragment to reflect that of the current Track, if possible
     * (meaning mPlaybackService is not null).
     */
    protected void refreshTrackInfo() {
        final PlaybackService playbackService = ((TomahawkMainActivity) getActivity())
                .getPlaybackService();
        if (playbackService != null) {
            refreshTrackInfo(playbackService.getCurrentQuery());
        } else {
            refreshTrackInfo(null);
        }
    }

    /**
     * Refresh the information in this fragment to reflect that of the given Track.
     *
     * @param query the query to which the track info view stuff should be updated to
     */
    protected void refreshTrackInfo(final Query query) {
        if (getView() != null) {
            final TomahawkMainActivity activity = (TomahawkMainActivity) getActivity();
            final PlaybackService playbackService = activity.getPlaybackService();
            if (query != null && playbackService != null) {
                /*
                This logic makes sure, that if a track is being skipped by the user, it doesn't do this
                for eternity. Because a press of the next button would cause the AlbumArtSwipeAdapter
                to display a swipe to the next track, which would then cause another skipping to the
                next track. That's why we have to make a difference between a swipe by the user, and a
                programmatically called swipe.
                */
                mAlbumArtViewPager.setPlaybackService(playbackService);
                mAlbumArtSwipeAdapter.setPlaybackService(playbackService);

                // Make all buttons clickable
                getView().findViewById(R.id.imageButton_shuffle).setClickable(true);
                getView().findViewById(R.id.imageButton_repeat).setClickable(true);

                ImageView bgImageView =
                        (ImageView) getView().findViewById(R.id.background);
                ImageUtils.loadBlurredImageIntoImageView(TomahawkApp.getContext(), bgImageView,
                        playbackService.getCurrentQuery().getImage(),
                        Image.getSmallImageSize(), R.color.playerview_default_bg);
            } else {
                // Make all buttons not clickable
                getView().findViewById(R.id.imageButton_shuffle).setClickable(false);
                getView().findViewById(R.id.imageButton_repeat).setClickable(false);
            }
        }
    }

    /**
     * Refresh the information in this fragment to reflect that of the current repeatButton state.
     */
    protected void refreshRepeatButtonState() {
        if (getView() != null) {
            ImageButton imageButton = (ImageButton) getView().findViewById(R.id.imageButton_repeat);
            if (imageButton != null) {
                PlaybackService playbackService = ((TomahawkMainActivity) getActivity())
                        .getPlaybackService();
                if (playbackService != null) {
                    if (playbackService.getRepeatingMode() == PlaybackService.REPEAT_ALL) {
                        ImageUtils.loadDrawableIntoImageView(TomahawkApp.getContext(),
                                imageButton, R.drawable.repeat_all, R.color.tomahawk_red);
                    } else if (playbackService.getRepeatingMode() == PlaybackService.REPEAT_ONE) {
                        ImageUtils.loadDrawableIntoImageView(TomahawkApp.getContext(),
                                imageButton, R.drawable.repeat_one, R.color.tomahawk_red);
                    } else {
                        ImageUtils.loadDrawableIntoImageView(TomahawkApp.getContext(),
                                imageButton, R.drawable.repeat_all);
                    }
                } else {
                    ImageUtils.clearTint(imageButton.getDrawable());
                }
            }
        }
    }

    /**
     * Refresh the information in this fragment to reflect that of the current shuffleButton state.
     */
    protected void refreshShuffleButtonState() {
        if (getView() != null) {
            ImageButton imageButton = (ImageButton) getView()
                    .findViewById(R.id.imageButton_shuffle);
            if (imageButton != null) {
                PlaybackService playbackService = ((TomahawkMainActivity) getActivity())
                        .getPlaybackService();
                if (playbackService != null && playbackService.isShuffled()) {
                    ImageUtils.setTint(imageButton.getDrawable(), R.color.tomahawk_red);
                } else {
                    ImageUtils.clearTint(imageButton.getDrawable());
                }
            }
        }
    }

    @Override
    public void animate(int position) {
        super.animate(position);
        TomahawkMainActivity activity = (TomahawkMainActivity) getActivity();
        if (activity.getSlidingOffset() > 0f) {
            activity.getPlaybackPanel().animate(position + 10000);
        }
    }
}
