/* Copyright 2015 Samsung Electronics Co., LTD
 *
 * 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 org.gearvrf.scene_objects;

import org.gearvrf.GVRContext;
import org.gearvrf.GVRDrawFrameListener;
import org.gearvrf.GVRExternalTexture;
import org.gearvrf.GVRMaterial;
import org.gearvrf.GVRMaterial.GVRShaderType;
import org.gearvrf.GVRMesh;
import org.gearvrf.GVRSceneObject;
import org.gearvrf.GVRTexture;
import org.gearvrf.scene_objects.view.GVRView;

import android.graphics.Canvas;
import android.graphics.SurfaceTexture;
import android.view.Surface;

/**
 * This class represents a {@linkplain GVRSceneObject Scene object} that shows a {@link View}
 * into the scene with an arbitrarily complex geometry.
 * See {@link GVRView}
 */
public class GVRViewSceneObject extends GVRSceneObject implements
        GVRDrawFrameListener {

    private final Surface mSurface;
    private final SurfaceTexture mSurfaceTexture;
    private final GVRView mView;

    /**
     * Shows any view into the {@linkplain GVRViewSceneObject scene object} with an arbitrarily complex
     * geometry.
     * 
     * @param gvrContext current {@link GVRContext}
     * @param gvrView The {@link GVRView} to be shown.
     * @param mesh a {@link GVRMesh} - see
     *            {@link GVRContext#loadMesh(org.gearvrf.GVRAndroidResource)} and
     *            {@link GVRContext#createQuad(float, float)}
     */
    public GVRViewSceneObject(GVRContext gvrContext, GVRView gvrView, GVRMesh mesh) {
        super(gvrContext, mesh);

        gvrContext.registerDrawFrameListener(this);
        GVRTexture texture = new GVRExternalTexture(gvrContext);

        // TODO: Shader type maybe defined by some GVRView.getShaderType()
        // according to view type
        GVRMaterial material = new GVRMaterial(gvrContext, GVRShaderType.OES.ID);
        material.setMainTexture(texture);
        getRenderData().setMaterial(material);

        mSurfaceTexture = new SurfaceTexture(texture.getId());
        mSurface = new Surface(mSurfaceTexture);
        mSurfaceTexture.setDefaultBufferSize(gvrView.getView().getWidth(),
                gvrView.getView().getHeight());

        gvrView.setSceneObject(this);

        gvrView.getView().postInvalidate();
        mView = gvrView;
    }

    public GVRView getView() {
        return mView;
    }

    /**
     * Shows view in a 2D, rectangular {@linkplain GVRViewSceneObject scene object.}
     * 
     * @param gvrContext current {@link GVRContext}
     * @param gvrView The {@link GVRView} to be shown.
     * @param width the rectangle's width
     * @param height the rectangle's height
     */
    public GVRViewSceneObject(GVRContext gvrContext, GVRView gvrView,
            float width, float height) {
        this(gvrContext, gvrView, gvrContext.createQuad(width, height));
    }

    @Override
    public void onDrawFrame(float frameTime) {
        mSurfaceTexture.updateTexImage();
    }

    /**
     * Gets a Android {@link Canvas} for drawing into this {@link GVRViewSceneObject Scene object}.
     * After drawing into the provided Android {@link Canvas}, the caller must invoke {@linkplain
     * GVRViewSceneObject#unlockCanvasAndPost(Android {@link Canvas}) to post the new contents to the scene
     * object. See - Android {@link Surface#lockCanvas(android.graphics.Rect)}
     */
    public Canvas lockCanvas() {
        return mSurface.lockCanvas(null);
    }

    /**
     * Posts the new contents of the Android {@link Canvas} to the scene object and releases the
     * Android {@link Canvas}.
     *
     * @param canvas The canvas previously obtained from {@link GVRViewSceneObject#lockCanvas()} See
     *            - Android {@link Surface#unlockCanvasAndPost(Canvas)}
     */
    public void unlockCanvasAndPost(Canvas canvas) {
        mSurface.unlockCanvasAndPost(canvas);
    }
}

@@ -639,16 +639,53 @@
 jects;%0A%0A
+import java.lang.ref.WeakReference;%0A%0A
 import o
@@ -707,16 +707,16 @@
 ontext;%0A
-
 import o
@@ -1349,48 +1349,8 @@
 ect 
-implements%0A        GVRDrawFrameListener 
 %7B%0A%0A 
@@ -2031,60 +2031,8 @@
 );%0A%0A
-        gvrContext.registerDrawFrameListener(this);%0A
     
@@ -2606,24 +2606,129 @@
 Height());%0A%0A
+        gvrContext.registerDrawFrameListener(new GVRDrawFrameListenerImpl(gvrContext, mSurfaceTexture));%0A
         gvrV
@@ -3387,118 +3387,8 @@
  %7D%0A%0A
-    @Override%0A    public void onDrawFrame(float frameTime) %7B%0A        mSurfaceTexture.updateTexImage();%0A    %7D%0A%0A
     
@@ -4239,24 +4239,24 @@
 s canvas) %7B%0A
-
         mSur
@@ -4294,11 +4294,805 @@
 );%0A    %7D
+%0A%0A    private static final class GVRDrawFrameListenerImpl implements GVRDrawFrameListener %7B%0A        GVRDrawFrameListenerImpl(final GVRContext gvrContext, final SurfaceTexture surfaceTexture) %7B%0A            mSurfaceTextureRef = new WeakReference%3CSurfaceTexture%3E(surfaceTexture);%0A            mGvrContext = gvrContext;%0A        %7D%0A%0A        @Override%0A        public void onDrawFrame(float frameTime) %7B%0A            final SurfaceTexture surfaceTexture = mSurfaceTextureRef.get();%0A            if (null != surfaceTexture) %7B%0A                surfaceTexture.updateTexImage();%0A            %7D else %7B%0A                mGvrContext.unregisterDrawFrameListener(this);%0A            %7D%0A        %7D%0A%0A        private final WeakReference%3CSurfaceTexture%3E mSurfaceTextureRef;%0A        private final GVRContext mGvrContext;%0A    %7D
 %0A%7D%0A

Fix leaking GVRViewSceneObjects