/*
 * Copyright 2015 Hippo Seven
 *
 * 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 com.hippo.ehviewer.gallery.glrenderer;

import android.graphics.Bitmap;
import android.support.annotation.NonNull;
import android.util.Log;

import com.hippo.ehviewer.gallery.gifdecoder.GifDecoder;

public class GifTexture extends TiledTexture {

    private static final String TAG = GifTexture.class.getSimpleName();

    private static TiledTexture.Uploader sUploader;
    private static InfiniteThreadExecutor sThreadExecutor;

    private GifDecoder mGifDecoder;
    private boolean mRunning = false;

    private GifDecodeTask mGifDecodeTask;

    public static void initialize(TiledTexture.Uploader uploader, InfiniteThreadExecutor threadExecutor) {
        sUploader = uploader;
        sThreadExecutor = threadExecutor;
    }

    public static void uninitialize() {
        sUploader = null;
        sThreadExecutor = null;
    }

    class GifDecodeTask implements Runnable {

        private long mLastTime = 0;
        private volatile boolean mSleeping = false;
        private volatile boolean mClear = false;

        public boolean isSleeping() {
            return mSleeping;
        }

        public void clearByMyself() {
            mClear = true;
        }

        @Override
        public void run() {
            GifDecoder gifDecoder = mGifDecoder;

            while (mRunning && sUploader != null) {
                gifDecoder.advance();
                Bitmap bitmap = gifDecoder.getNextFrame();
                if (bitmap == null) {
                    Log.d(TAG, "Can't get bitmap, GifDecoder state = " + gifDecoder.getStatus());
                    mRunning = false;
                    break;
                }

                setBitmap(bitmap);
                if (sUploader == null) {
                    break;
                }
                sUploader.addTexture(GifTexture.this);

                long delay = gifDecoder.getNextDelay();
                long time = System.currentTimeMillis();
                if (mLastTime != 0) {
                    delay -= time - mLastTime;
                }
                mLastTime = time;
                if (delay > 5) {
                    mSleeping = true;
                    try {
                        Thread.sleep(delay);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                    mSleeping = false;
                }
            }
            mGifDecodeTask = null;

            if (mClear) {
                gifDecoder.clear();
            }
        }
    }

    public GifTexture(@NonNull GifDecoder gifDecoder, @NonNull Bitmap bitmap) {
        super(bitmap);

        mGifDecoder = gifDecoder;
    }

    public void start() {
        if (!mRunning) {
            mRunning = true;
            if (mGifDecodeTask == null) {
                mGifDecodeTask = new GifDecodeTask();
                sThreadExecutor.execute(mGifDecodeTask);
            }
        }
    }

    public void stop() {
        if (mRunning) {
            mRunning = false;
            mGifDecodeTask = null;

            mGifDecoder.resetFrameIndex();
            mGifDecoder.advance();
            Bitmap bitmap = mGifDecoder.getNextFrame();
            if (bitmap != null) {
                setBitmap(bitmap);
                sUploader.addTexture(GifTexture.this);
            }
        }
    }

    @Override
    public void recycle() {
        mRunning = false;
        if (mGifDecodeTask == null || mGifDecodeTask.isSleeping()) {
            mGifDecoder.clear();
        } else {
            mGifDecodeTask.clearByMyself();
        }
        mGifDecoder = null;
        mGifDecodeTask = null;

        super.recycle();
    }
}

@@ -796,16 +796,66 @@
 coder;%0A%0A
+import java.util.concurrent.locks.ReentrantLock;%0A%0A
 public c
@@ -1148,24 +1148,85 @@
 ing = false;
+%0A    private final ReentrantLock mLock = new ReentrantLock();
 %0A%0A    privat
@@ -1670,153 +1670,22 @@
 an m
-Sleeping = false;%0A        private volatile boolean mClear = false;%0A%0A        public boolean isSleeping() %7B%0A            return mSleeping;%0A        %7D
+Clear = false;
 %0A%0A  
@@ -1898,32 +1898,63 @@
 ader != null) %7B%0A
+                mLock.lock();%0A%0A
                 
@@ -2322,32 +2322,70 @@
 ader == null) %7B%0A
+                    mRunning = false;%0A
                 
@@ -2714,24 +2714,25 @@
 ime = time;%0A
+%0A
             
@@ -2739,62 +2739,57 @@
     
-if (delay %3E 5) %7B%0A                    mSleeping = true;
+mLock.unlock();%0A%0A                if (delay %3E 5) %7B
 %0A   
@@ -2971,47 +2971,8 @@
   %7D%0A
-                    mSleeping = false;%0A
     
@@ -3644,32 +3644,73 @@
 deTask = null;%0A%0A
+            if (!mLock.isLocked()) %7B%0A    
             mGif
@@ -3740,32 +3740,36 @@
 ();%0A            
+  
+  
 mGifDecoder.adva
@@ -3767,32 +3767,36 @@
 oder.advance();%0A
+    
             Bitm
@@ -3839,32 +3839,36 @@
 ();%0A            
+    
 if (bitmap != nu
@@ -3865,32 +3865,36 @@
 tmap != null) %7B%0A
+    
                 
@@ -3932,46 +3932,139 @@
     
-sUploader.addTexture(GifTexture.this);
+    if (sUploader != null) %7B%0A                        sUploader.addTexture(GifTexture.this);%0A                    %7D%0A                %7D
 %0A   
@@ -4151,32 +4151,33 @@
 unning = false;%0A
+%0A
         if (mGif
@@ -4177,111 +4177,24 @@
 f (m
-GifDecodeTask == null %7C%7C mGifDecodeTask.isSleeping()) %7B%0A            mGifDecoder.clear();%0A        %7D else
+Lock.isLocked())
  %7B%0A 
@@ -4237,32 +4237,83 @@
 elf();%0A        %7D
+ else %7B%0A            mGifDecoder.clear();%0A        %7D%0A
 %0A        mGifDec

Fix GifTexture lock