/*
 * Copyright (c) 2011, Oracle  and/or its affiliates. All rights reserved.
 *
 * Use is subject to license terms.
 */

package com.sun.javafx.tk.quantum;

import java.nio.IntBuffer;

import com.sun.glass.ui.Application;
import com.sun.glass.ui.Pixels;
import com.sun.prism.Graphics;
import com.sun.prism.RTTexture;
import com.sun.prism.impl.BufferUtil;
import com.sun.prism.impl.Disposer;
import com.sun.prism.impl.PrismSettings;


/**
 * @author Morris Meyer
 */
public class UploadingPainter extends ViewPainter implements Runnable {

    private Application app = Application.GetApplication();
    private Pixels      pix;
    private IntBuffer   textureBits;
    private RTTexture   rttexture;

    protected UploadingPainter(ViewScene view, PrismPen pen) {
        super(view, pen);
    }

    private final Runnable  upload = new Runnable() {
        @Override public void run() {
            if (view.isClosed() == false) {
                view.uploadPixels(pix);
            }
        }
    };

    void disposeRTTexture() {
        if (rttexture != null) {
            rttexture.dispose();
            rttexture = null;
        }
    }

    @Override public void run() {
        try {
            if (PrismSettings.threadCheck) {
                assert !renderLock.isHeldByCurrentThread();
                renderLock.lock();
            }
            
            valid = validateStageGraphics();

            if (!valid) {
                if (verbose) {
                    System.err.println("UploadingPainter: validateStageGraphics failed");
                }
                return;
            }
            
            if (view != null) {
                /*
                 * As Glass is responsible for creating the rendering contexts,
                 * pen.begin should be done prior to the Prism calls.
                 */
                pen.begin();
            }

            boolean needsReset = (rttexture == null) || (viewWidth != penWidth) || (viewHeight != penHeight);
            
            if (needsReset) {
                context = factory.createRenderingContext(null);
            }
            
            context.begin();
            
            if (needsReset) {
                disposeRTTexture();
                rttexture = factory.createRTTexture(viewWidth, viewHeight);
                if (rttexture == null) {
                    context.end();
                    return;
                }
                penWidth    = viewWidth;
                penHeight   = viewHeight;
                textureBits = null;
            }
            Graphics g = rttexture.createGraphics();
            if (g == null) {
                disposeRTTexture();
                scene.entireSceneNeedsRepaint();
                return;
            }
            paintImpl(g);

            if (liveRepaint.get() == false) {
                collector.releaseScene(scene);
            }
            
            int rawbits[] = rttexture.getPixels();
            
            if (rawbits != null) {
                pix = app.createPixels(viewWidth, viewHeight, IntBuffer.wrap(rawbits));
            } else {
                if (textureBits == null) {
                    textureBits = BufferUtil.newIntBuffer(viewWidth * viewHeight);
                }
                
                if (textureBits != null) {
                    if (rttexture.readPixels(textureBits)) {
                        pix = app.createPixels(viewWidth, viewHeight, textureBits);
                    } else {
                        /* device lost */
                        scene.entireSceneNeedsRepaint();
                        disposeRTTexture();
                    }
                }
            }
            
            if (pix != null) {
                /* transparent pixels created and ready for upload */
                Application.postOnEventQueue(upload);
            }
                
        } catch (Throwable th) {
            th.printStackTrace(System.err);
        } finally {
            if (valid && context != null) {
                Disposer.cleanUp();
                context.end();            
            }
            if (valid && view != null && view.isClosed() == false) {
                pen.end(); 
            }

            pen.getPainting().set(false);

            if (PrismSettings.threadCheck) {
                renderLock.unlock();
            }
        }
    }
}