
package org.zarroboogs.weibo.support.asyncdrawable;

import org.zarroboogs.utils.ImageUtility;
import org.zarroboogs.utils.file.FileDownloaderHttpHelper;
import org.zarroboogs.utils.file.FileLocationMethod;
import org.zarroboogs.utils.file.FileManager;
import org.zarroboogs.weibo.BeeboApplication;
import org.zarroboogs.weibo.R;
import org.zarroboogs.weibo.asynctask.MyAsyncTask;
import org.zarroboogs.weibo.bean.MessageBean;
import org.zarroboogs.weibo.bean.UserBean;
import org.zarroboogs.weibo.fragment.base.AbsBaseTimeLineFragment;
import org.zarroboogs.weibo.hot.hean.HotMblogBean;
import org.zarroboogs.weibo.setting.SettingUtils;
import org.zarroboogs.weibo.support.utils.ThemeUtility;

import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.view.View;
import android.view.animation.Animation;
import android.widget.ImageView;

import java.lang.ref.WeakReference;
import java.util.ArrayList;

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public class TimeLineBitmapDownloader {

    private int defaultPictureResId;

    private Handler handler;

    static volatile boolean pauseDownloadWork = false;

    static final Object pauseDownloadWorkLock = new Object();

    static volatile boolean pauseReadWork = false;

    static final Object pauseReadWorkLock = new Object();

    private static final Object lock = new Object();

    private static TimeLineBitmapDownloader instance;

    private TimeLineBitmapDownloader(Handler handler) {
        this.handler = handler;
        this.defaultPictureResId = ThemeUtility.getResourceId(R.attr.listview_pic_bg);
    }

    public static TimeLineBitmapDownloader getInstance() {
        synchronized (lock) {
            if (instance == null) {
                instance = new TimeLineBitmapDownloader(new Handler(Looper.getMainLooper()));
            }
        }
        return instance;
    }

    public static void refreshThemePictureBackground() {
        synchronized (lock) {
            instance = new TimeLineBitmapDownloader(new Handler(Looper.getMainLooper()));
        }
    }

    /**
     * Pause any ongoing background work. This can be used as a temporary measure to improve
     * performance. For example background work could be paused when a ListView or GridView is being
     * scrolled using a {@link android.widget.AbsListView.OnScrollListener} to keep scrolling
     * smooth.
     * <p/>
     * If work is paused, be sure setPauseDownloadWork(false) is called again before your fragment
     * or activity is destroyed (for example during {@link android.app.Activity#onPause()}), or
     * there is a risk the background thread will never finish.
     */
    public void setPauseDownloadWork(boolean pauseWork) {
        synchronized (pauseDownloadWorkLock) {
            TimeLineBitmapDownloader.pauseDownloadWork = pauseWork;
            if (!TimeLineBitmapDownloader.pauseDownloadWork) {
                pauseDownloadWorkLock.notifyAll();
            }
        }
    }

    public void setPauseReadWork(boolean pauseWork) {
        synchronized (pauseReadWorkLock) {
            TimeLineBitmapDownloader.pauseReadWork = pauseWork;
            if (!TimeLineBitmapDownloader.pauseReadWork) {
                pauseReadWorkLock.notifyAll();
            }
        }
    }

    protected Bitmap getBitmapFromMemCache(String key) {
        if (TextUtils.isEmpty(key)) {
            return null;
        } else {
            return BeeboApplication.getInstance().getBitmapCache().get(key);
        }
    }

    public void downloadAvatar(ImageView view, UserBean user) {
        downloadAvatar(view, user, false);
    }

    public void downloadAvatar(ImageView view, UserBean user, AbsBaseTimeLineFragment fragment) {
        boolean isFling = fragment.isListViewFling();
        downloadAvatar(view, user, isFling);
    }

    public void downloadAvatar(ImageView view, UserBean user, boolean isFling) {

        if (user == null) {
            view.setImageResource(defaultPictureResId);
            return;
        }

        String url;
        FileLocationMethod method;
        if (SettingUtils.getEnableBigAvatar()) {
            url = user.getAvatar_large();
            method = FileLocationMethod.avatar_large;
        } else {
            url = user.getAvatar_large();
            method = FileLocationMethod.avatar_small;
        }
        displayImageView(view, url, method, isFling, false);
    }

    public void downContentPic(ImageView view, MessageBean msg, AbsBaseTimeLineFragment fragment) {
        String picUrl;

        boolean isFling = fragment.isListViewFling();

        if (SettingUtils.getEnableBigPic()) {
            picUrl = msg.getOriginal_pic();
            displayImageView(view, picUrl, FileLocationMethod.picture_large, isFling, false);

        } else {
            picUrl = msg.getThumbnail_pic();
            displayImageView(view, picUrl, FileLocationMethod.picture_thumbnail, isFling, false);

        }
    }

    public void displayMultiPicture(IWeiboDrawable view, String picUrl, FileLocationMethod method,
                                    AbsBaseTimeLineFragment fragment) {

        boolean isFling = fragment.isListViewFling();

        display(view, picUrl, method, isFling, true);

    }

    public void displayMultiPicture(IWeiboDrawable view, String picUrl, FileLocationMethod method) {

        display(view, picUrl, method, false, true);

    }


    public void downContentPic(IWeiboDrawable view, HotMblogBean msg, AbsBaseTimeLineFragment fragment) {
        String picUrl;

        boolean isFling = fragment.isListViewFling();

        if (SettingUtils.getEnableBigPic()) {
            picUrl = msg.getOriginal_pic();
            display(view, picUrl, FileLocationMethod.picture_large, isFling, false);

        } else {
            picUrl = msg.getThumbnail_pic();
            display(view, picUrl, FileLocationMethod.picture_thumbnail, isFling, false);

        }
    }

    public void downContentPic(IWeiboDrawable view, MessageBean msg, AbsBaseTimeLineFragment fragment) {
        String picUrl;

        boolean isFling = fragment.isListViewFling();

        if (SettingUtils.getEnableBigPic()) {
            picUrl = msg.getOriginal_pic();
            display(view, picUrl, FileLocationMethod.picture_large, isFling, false);

        } else {
            picUrl = msg.getThumbnail_pic();
            display(view, picUrl, FileLocationMethod.picture_thumbnail, isFling, false);

        }
    }

    /**
     * when user open weibo detail, the activity will setResult to previous Activity, timeline will
     * refresh at the time user press back button to display the latest repost count and comment
     * count. But sometimes, weibo detail's pictures are very large that bitmap memory cache has
     * cleared those timeline bitmap to save memory, app have to read bitmap from sd card again,
     * then app play annoying animation , this method will check whether we should read again or
     * not.
     */
    private boolean shouldReloadPicture(ImageView view, String urlKey) {
        if (urlKey.equals(view.getTag())
                && view.getDrawable() != null
                && view.getDrawable() instanceof BitmapDrawable
                && (view.getDrawable() != null && ((BitmapDrawable) view.getDrawable()).getBitmap() != null)) {
            // AppLogger.d("shouldReloadPicture=false");
            return false;
        } else {
            view.setTag(null);
            // AppLogger.d("shouldReloadPicture=true");
            return true;
        }
    }

    private void displayImageView(final ImageView view, final String urlKey, final FileLocationMethod method,
                                  boolean isFling, boolean isMultiPictures) {
        view.clearAnimation();

        if (!shouldReloadPicture(view, urlKey)) {
            return;
        }

        final Bitmap bitmap = getBitmapFromMemCache(urlKey);
        if (bitmap != null) {
            view.setImageBitmap(bitmap);
            view.setTag(urlKey);
            if (view.getAlpha() != 1.0f) {
                view.setAlpha(1.0f);
            }
            cancelPotentialDownload(urlKey, view);
        } else {

            if (isFling) {
                view.setImageResource(defaultPictureResId);
                return;
            }

            if (!cancelPotentialDownload(urlKey, view)) {
                return;
            }

            final LocalOrNetworkChooseWorker newTask = new LocalOrNetworkChooseWorker(view, urlKey, method, isMultiPictures);
            PictureBitmapDrawable downloadedDrawable = new PictureBitmapDrawable(newTask);
            view.setImageDrawable(downloadedDrawable);

            // listview fast scroll performance
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {

                    if (getBitmapDownloaderTask(view) == newTask) {
                        newTask.executeOnNormal();
                    }
                    return;

                }
            }, 400);

        }

    }

    private void display(final IWeiboDrawable view, final String urlKey, final FileLocationMethod method,
                         boolean isFling, boolean isMultiPictures) {
        view.getImageView().clearAnimation();

        if (!shouldReloadPicture(view.getImageView(), urlKey)) {
            return;
        }

        final Bitmap bitmap = getBitmapFromMemCache(urlKey);
        if (bitmap != null) {
            view.setImageBitmap(bitmap);
            view.getImageView().setTag(urlKey);
            if (view.getProgressBar() != null) {
                view.getProgressBar().setVisibility(View.INVISIBLE);
            }
            if (view.getImageView().getAlpha() != 1.0f) {
                view.getImageView().setAlpha(1.0f);
            }
            view.setGifFlag(ImageUtility.isThisPictureGif(urlKey));
            cancelPotentialDownload(urlKey, view.getImageView());
        } else {

            if (isFling) {
                view.getImageView().setImageResource(defaultPictureResId);
                if (view.getProgressBar() != null) {
                    view.getProgressBar().setVisibility(View.INVISIBLE);
                }
                view.setGifFlag(ImageUtility.isThisPictureGif(urlKey));
                return;
            }

            if (!cancelPotentialDownload(urlKey, view.getImageView())) {
                return;
            }

            final LocalOrNetworkChooseWorker newTask = new LocalOrNetworkChooseWorker(view, urlKey, method, isMultiPictures);
            PictureBitmapDrawable downloadedDrawable = new PictureBitmapDrawable(newTask);
            view.setImageDrawable(downloadedDrawable);

            // listview fast scroll performance
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {

                    if (getBitmapDownloaderTask(view.getImageView()) == newTask) {
                        newTask.executeOnNormal();
                    }
                    return;

                }
            }, 400);

        }

    }

    public void totalStopLoadPicture() {

    }

    private static boolean cancelPotentialDownload(String url, ImageView imageView) {
        IPictureWorker bitmapDownloaderTask = getBitmapDownloaderTask(imageView);

        if (bitmapDownloaderTask != null) {
            String bitmapUrl = bitmapDownloaderTask.getUrl();
            if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
                if (bitmapDownloaderTask instanceof MyAsyncTask) {
                    ((MyAsyncTask) bitmapDownloaderTask).cancel(true);
                }
            } else {
                return false;
            }
        }
        return true;
    }

    private static IPictureWorker getBitmapDownloaderTask(ImageView imageView) {
        if (imageView != null) {
            Drawable drawable = imageView.getDrawable();
            if (drawable instanceof PictureBitmapDrawable) {
                PictureBitmapDrawable downloadedDrawable = (PictureBitmapDrawable) drawable;
                return downloadedDrawable.getBitmapDownloaderTask();
            }
        }
        return null;
    }

    public void display(final ImageView imageView, final int width, final int height, final String url,
                        final FileLocationMethod method) {
        ArrayList<ImageView> imageViewArrayList = new ArrayList<ImageView>();
        imageViewArrayList.add(imageView);
        display(imageViewArrayList, width, height, url, method, null);

    }

    public void display(final ArrayList<ImageView> imageView, final int width, final int height, final String url,
                        final FileLocationMethod method,
                        final ArrayList<Animation> animations) {
        if (TextUtils.isEmpty(url)) {
            return;
        }

        final Bitmap bitmap = getBitmapFromMemCache(url);
        if (bitmap != null && bitmap.getHeight() == height && bitmap.getWidth() == width) {
            for (int i = 0; i < imageView.size(); i++) {
                ImageView imageView1 = imageView.get(i);
                imageView1.setImageDrawable(new BitmapDrawable(BeeboApplication.getInstance().getResources(), bitmap));
                if (animations != null && animations.size() > i) {
                    Animation animation = animations.get(i);
                    imageView1.startAnimation(animation);
                }
            }
            return;
        }

        new MyAsyncTask<Void, Bitmap, Bitmap>() {

            @Override
            protected Bitmap doInBackground(Void... params) {
                Bitmap bitmap = null;

                String path = FileManager.getFilePathFromUrl(url, method);

                if (!(ImageUtility.isThisBitmapCanRead(path) && TaskCache.isThisUrlTaskFinished(url))) {

                    boolean downloaded = TaskCache.waitForPictureDownload(url, null,
                            FileManager.generateDownloadFileName(url), method);
                    if (downloaded) {
                        path = FileManager.getFilePathFromUrl(url, method);
                    }
                }

                if (!TextUtils.isEmpty(path)) {
                    bitmap = ImageUtility.readNormalPic(path, width, height);
                }
                return bitmap;
            }

            @Override
            protected void onPostExecute(Bitmap bitmap) {
                super.onPostExecute(bitmap);
                if (bitmap != null) {
                    BeeboApplication.getInstance().getBitmapCache().put(url, bitmap);
                    for (int i = 0; i < imageView.size(); i++) {
                        ImageView imageView1 = imageView.get(i);
                        imageView1.setImageDrawable(new BitmapDrawable(BeeboApplication.getInstance().getResources(), bitmap));
                        if (animations != null && animations.size() > i) {
                            Animation animation = animations.get(i);
                            imageView1.startAnimation(animation);
                        }
                    }

                }
            }
        }.executeOnExecutor(MyAsyncTask.THREAD_POOL_EXECUTOR);
    }

    public static class DownloadCallback {

        public void onSubmitJobButNotBegin() {

        }

        public void onSubmitJobButAlreadyBegin() {

        }

        public void onBegin() {

        }

        public void onUpdate(int value, int max) {

        }

        public void onComplete(String localPath) {

        }

    }

    public void download(final Activity activity, final String url, final FileLocationMethod method,
                         final DownloadCallback callback) {
        downloadInner(activity, url, method, callback);
    }

    public void download(final Fragment fragment, final String url, final FileLocationMethod method,
                         final DownloadCallback callback) {
        downloadInner(fragment, url, method, callback);
    }

    private void downloadInner(final Object object, final String url, final FileLocationMethod method,
                               final DownloadCallback callback) {

        if (TextUtils.isEmpty(url)) {
            return;
        }

        if (TaskCache.isThisUrlTaskFinished(url)) {
            callback.onSubmitJobButNotBegin();
        } else {
            callback.onSubmitJobButAlreadyBegin();
        }

        new MyAsyncTask<Void, Integer, String>() {

            WeakReference<Object> activityRef;

            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                activityRef = new WeakReference<Object>(object);
                callback.onBegin();
            }

            @Override
            protected String doInBackground(Void... params) {

                String path = FileManager.getFilePathFromUrl(url, method);

                if (!(ImageUtility.isThisBitmapCanRead(path) && TaskCache.isThisUrlTaskFinished(url))) {
                    boolean downloaded = TaskCache.waitForPictureDownload(url,
                            new FileDownloaderHttpHelper.DownloadListener() {
                                @Override
                                public void pushProgress(final int progress, final int max) {
                                    handler.post(new Runnable() {
                                        @Override
                                        public void run() {
                                            onProgressUpdate(progress, max);
                                        }
                                    });
                                }

                                @Override
                                public void completed() {

                                }

                                @Override
                                public void cancel() {

                                }
                            }, FileManager.getFilePathFromUrl(url, method), method);
                    if (downloaded) {
                        path = FileManager.getFilePathFromUrl(url, method);
                    }
                }

                return path;

            }

            @Override
            protected void onProgressUpdate(Integer... values) {
                super.onProgressUpdate(values);
                if (!isComponentLifeCycleFinished()) {
                    int progress = values[0];
                    int max = values[1];
                    callback.onUpdate(progress, max);
                }
            }

            @Override
            protected void onPostExecute(String value) {
                super.onPostExecute(value);
                if (!isComponentLifeCycleFinished()) {
                    callback.onComplete(value);
                }

            }

            boolean isComponentLifeCycleFinished() {
                Object object = activityRef.get();
                if (object == null) {
                    return true;
                }

                if (object instanceof Fragment) {
                    Fragment fragment = (Fragment) object;
                    if (fragment.getActivity() == null) {
                        return true;
                    }
                } else if (object instanceof Activity) {
                    Activity activity = (Activity) object;
                    if (activity.isDestroyed()) {
                        return true;
                    }
                }

                return false;
            }

        }.executeOnExecutor(MyAsyncTask.THREAD_POOL_EXECUTOR);
    }
}
