/*
 * Copyright 2018 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

package org.skia.skottie;

import android.animation.Animator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceView;
import android.view.TextureView;

import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import java.io.FileNotFoundException;
import java.io.InputStream;

import org.skia.skottielib.R;

public class SkottieView extends FrameLayout {

    private SkottieAnimation mAnimation;
    private View mBackingView;
    private int mBackgroundColor;
    // Repeat follows Animator API, infinite is represented by -1 (see Animator.DURATION_INFINITE)
    private int mRepeatCount;
    private static final int BACKING_VIEW_TEXTURE = 0;
    private static final int BACKING_VIEW_SURFACE = 1;
    private final String LOG_TAG = "SkottieView";

    /*
     * Build function for SkottieViews backed with a texture view
     * Is the same as calling for a default SkottieView
     */
    public SkottieView buildAsTexture(Context context) {
        return new SkottieView(context);
    }

    /*
     * Build function for SkottieViews backed with a surface view
     * Backs the animation surface with a SurfaceView instead, requires background color
     */
    public SkottieView buildAsSurface(Context context, int backgroundColor) {
        SkottieView s = new SkottieView(context);
        s.mBackingView = new SurfaceView(context);
        s.mBackgroundColor = backgroundColor;
        return s;
    }

    // Basic SkottieView, backing view defaults to TextureView
    public SkottieView(Context context) {
        super(context);
        mBackingView = new TextureView(context);
        initBackingView();
    }

    public SkottieView(Context context, AttributeSet attrs) {
        this(context, attrs, 0, 0);
    }

    public SkottieView(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    // SkottieView constructor when initialized in XML layout
    public SkottieView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs);
        TypedArray a = context.getTheme()
            .obtainStyledAttributes(attrs, R.styleable.SkottieView, defStyleAttr, defStyleRes);
        try {
            // set mRepeatCount
            mRepeatCount = a.getInteger(R.styleable.SkottieView_android_repeatCount, 0);
            // set backing view and background color
            switch (a.getInteger(R.styleable.SkottieView_backing_view, -1)) {
                case BACKING_VIEW_TEXTURE:
                    mBackingView = new TextureView(context);
                    ((TextureView) mBackingView).setOpaque(false);
                    mBackgroundColor = a.getColor(R.styleable.SkottieView_background_color, 0);
                    break;
                case BACKING_VIEW_SURFACE:
                    if (!a.hasValue(R.styleable.SkottieView_background_color)) {
                        throw new RuntimeException("background_color attribute "
                            + "needed for SurfaceView");
                    }
                    mBackingView = new SurfaceView(context);
                    mBackgroundColor = a.getColor(R.styleable.SkottieView_background_color, -1);
                    if (Color.alpha(mBackgroundColor) != 255) {
                        throw new RuntimeException("background_color cannot be transparent");
                    }
                    break;
                default:
                    throw new RuntimeException("backing_view attribute needed to "
                        + "specify between texture_view or surface_view");
            }
            // set source
            int src = a.getResourceId(R.styleable.SkottieView_src, -1);
            if (src != -1) {
                setSource(src);
            }
        } finally {
            a.recycle();
        }
        initBackingView();
    }

    private void initBackingView() {
        mBackingView.setLayoutParams(new ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT));
        addView(mBackingView);
    }

    public void setSource(InputStream inputStream) {
        mAnimation = setSourceHelper(inputStream);
    }

    public void setSource(int resId) {
        InputStream inputStream = mBackingView.getResources().openRawResource(resId);
        mAnimation = setSourceHelper(inputStream);
    }

    public void setSource(Context context, Uri uri) throws FileNotFoundException {
        InputStream inputStream = context.getContentResolver().openInputStream(uri);
        mAnimation = setSourceHelper(inputStream);
    }

    private SkottieAnimation setSourceHelper(InputStream inputStream) {
        SkottieAnimation.Config config = null;
        SkottieAnimation animation;
        // if there is already an animation, save config and finalize it so as to not confuse GL
        if (mAnimation != null) {
            config = mAnimation.getBackingViewConfig();
            try {
                mAnimation.finalize();
            } catch (Throwable t) {
                Log.e(LOG_TAG, "existing animation couldn't finalize before setting new src");
            }
        }
        if (mBackingView instanceof TextureView) {
            animation = SkottieRunner.getInstance()
                .createAnimation(((TextureView) mBackingView), inputStream, mBackgroundColor, mRepeatCount);
        } else {
            animation = SkottieRunner.getInstance()
                .createAnimation(((SurfaceView) mBackingView), inputStream, mBackgroundColor, mRepeatCount);
        }
        // restore config settings from previous animation if needed
        if (config != null) {
            animation.setBackingViewConfig(config);
            animation.setProgress(0f);
        }
        return animation;
    }

    protected SkottieAnimation getSkottieAnimation() {
        return mAnimation;
    }

    public void removeListener(Animator.AnimatorListener listener) {
        mAnimation.removeListener(listener);
    }

    public void addListener(Animator.AnimatorListener listener) {
        mAnimation.addListener(listener);
    }

    // progress: a float from 0 to 1 representing the percent into the animation
    public void seek(float progress) {
        if(mAnimation != null) {
            mAnimation.setProgress(progress);
        }
    }

    public void play() {
        if(mAnimation != null) {
            mAnimation.resume();
        }
    }

    public void pause() {
        if(mAnimation != null) {
            mAnimation.pause();
        }
    }

    public void start() {
        if(mAnimation != null) {
            mAnimation.start();
        }
    }

    public void stop() {
        if(mAnimation != null) {
            mAnimation.end();
        }
    }

    public float getProgress() {
        if(mAnimation != null) {
            return mAnimation.getProgress();
        }
        return -1;
    }

    public void setRepeatCount(int repeatCount) {
        mRepeatCount = repeatCount;
    }

    public void setBackgroundColor(int colorRGB) {
        mBackgroundColor = colorRGB;
    }

    static public void setMaxCacheSize(int maxCacheSize) {
        SkottieRunner.getInstance().setMaxCacheSize(maxCacheSize);
    }
}
