/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.support.v4.media;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.RemoteControlClient;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewTreeObserver;

class TransportMediatorJellybeanMR2
        implements RemoteControlClient.OnGetPlaybackPositionListener,
        RemoteControlClient.OnPlaybackPositionUpdateListener {
    final Context mContext;
    final AudioManager mAudioManager;
    final View mTargetView;
    final TransportMediatorCallback mTransportCallback;
    final String mReceiverAction;
    final IntentFilter mReceiverFilter;
    final Intent mIntent;
    final ViewTreeObserver.OnWindowAttachListener mWindowAttachListener =
            new ViewTreeObserver.OnWindowAttachListener() {
                @Override
                public void onWindowAttached() {
                    windowAttached();
                }
                @Override
                public void onWindowDetached() {
                    windowDetached();
                }
            };
    final ViewTreeObserver.OnWindowFocusChangeListener mWindowFocusListener =
            new ViewTreeObserver.OnWindowFocusChangeListener() {
                @Override
                public void onWindowFocusChanged(boolean hasFocus) {
                    if (hasFocus) gainFocus();
                    else loseFocus();
                }
            };
    final BroadcastReceiver mMediaButtonReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            try {
                KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
                mTransportCallback.handleKey(event);
            } catch (ClassCastException e) {
                Log.w("TransportController", e);
            }
        }
    };
    AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener
            = new AudioManager.OnAudioFocusChangeListener() {
        @Override
        public void onAudioFocusChange(int focusChange) {
            mTransportCallback.handleAudioFocusChange(focusChange);
        }
    };

    PendingIntent mPendingIntent;
    RemoteControlClient mRemoteControl;
    boolean mFocused;
    int mPlayState = 0;
    boolean mAudioFocused;

    public TransportMediatorJellybeanMR2(Context context, AudioManager audioManager,
            View view, TransportMediatorCallback transportCallback) {
        mContext = context;
        mAudioManager = audioManager;
        mTargetView = view;
        mTransportCallback = transportCallback;
        mReceiverAction = context.getPackageName() + ":transport:" + System.identityHashCode(this);
        mIntent = new Intent(mReceiverAction);
        mIntent.setPackage(context.getPackageName());
        mReceiverFilter = new IntentFilter();
        mReceiverFilter.addAction(mReceiverAction);
        mTargetView.getViewTreeObserver().addOnWindowAttachListener(mWindowAttachListener);
        mTargetView.getViewTreeObserver().addOnWindowFocusChangeListener(mWindowFocusListener);
    }

    public Object getRemoteControlClient() {
        return mRemoteControl;
    }

    public void destroy() {
        windowDetached();
        mTargetView.getViewTreeObserver().removeOnWindowAttachListener(mWindowAttachListener);
        mTargetView.getViewTreeObserver().removeOnWindowFocusChangeListener(mWindowFocusListener);
    }

    void windowAttached() {
        mContext.registerReceiver(mMediaButtonReceiver, mReceiverFilter);
        mPendingIntent = PendingIntent.getBroadcast(mContext, 0, mIntent,
                PendingIntent.FLAG_CANCEL_CURRENT);
        mRemoteControl = new RemoteControlClient(mPendingIntent);
        mRemoteControl.setOnGetPlaybackPositionListener(this);
        mRemoteControl.setPlaybackPositionUpdateListener(this);
    }

    void gainFocus() {
        if (!mFocused) {
            mFocused = true;
            mAudioManager.registerMediaButtonEventReceiver(mPendingIntent);
            mAudioManager.registerRemoteControlClient(mRemoteControl);
            if (mPlayState == RemoteControlClient.PLAYSTATE_PLAYING) {
                takeAudioFocus();
            }
        }
    }

    void takeAudioFocus() {
        if (!mAudioFocused) {
            mAudioFocused = true;
            mAudioManager.requestAudioFocus(mAudioFocusChangeListener,
                    AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
        }
    }

    public void startPlaying() {
        if (mPlayState != RemoteControlClient.PLAYSTATE_PLAYING) {
            mPlayState = RemoteControlClient.PLAYSTATE_PLAYING;
            mRemoteControl.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
        }
        if (mFocused) {
            takeAudioFocus();
        }
    }

    @Override
    public long onGetPlaybackPosition() {
        return mTransportCallback.getPlaybackPosition();
    }

    @Override
    public void onPlaybackPositionUpdate(long newPositionMs) {
        mTransportCallback.playbackPositionUpdate(newPositionMs);
    }

    public void refreshState(boolean playing, long position, int transportControls) {
        if (mRemoteControl != null) {
            mRemoteControl.setPlaybackState(playing ? RemoteControlClient.PLAYSTATE_PLAYING
                    : RemoteControlClient.PLAYSTATE_STOPPED, position, playing ? 1 : 0);
            mRemoteControl.setTransportControlFlags(transportControls);
        }
    }

    public void pausePlaying() {
        if (mPlayState == RemoteControlClient.PLAYSTATE_PLAYING) {
            mPlayState = RemoteControlClient.PLAYSTATE_PAUSED;
            mRemoteControl.setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED);
        }
        dropAudioFocus();
    }

    public void stopPlaying() {
        if (mPlayState != RemoteControlClient.PLAYSTATE_STOPPED) {
            mPlayState = RemoteControlClient.PLAYSTATE_STOPPED;
            mRemoteControl.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED);
        }
        dropAudioFocus();
    }

    void dropAudioFocus() {
        if (mAudioFocused) {
            mAudioFocused = false;
            mAudioManager.abandonAudioFocus(mAudioFocusChangeListener);
        }
    }

    void loseFocus() {
        dropAudioFocus();
        if (mFocused) {
            mFocused = false;
            mAudioManager.unregisterRemoteControlClient(mRemoteControl);
            mAudioManager.unregisterMediaButtonEventReceiver(mPendingIntent);
        }
    }

    void windowDetached() {
        loseFocus();
        if (mPendingIntent != null) {
            mContext.unregisterReceiver(mMediaButtonReceiver);
            mPendingIntent.cancel();
            mPendingIntent = null;
            mRemoteControl = null;
        }
    }
}
