/*
 * Copyright 2016 MovingBlocks
 *
 * 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.terasology.rendering.opengl.fbms;

import org.lwjgl.opengl.Display;
import org.terasology.assets.ResourceUrn;
import org.terasology.config.Config;
import org.terasology.config.RenderingConfig;
import org.terasology.context.Context;
import org.terasology.rendering.oculusVr.OculusVrHelper;
import org.terasology.rendering.opengl.AbstractFBOsManager;
import org.terasology.rendering.opengl.DefaultDynamicFBOs;
import static org.terasology.rendering.opengl.DefaultDynamicFBOs.FINAL;
import static org.terasology.rendering.opengl.DefaultDynamicFBOs.READ_ONLY_GBUFFER;
import static org.terasology.rendering.opengl.DefaultDynamicFBOs.WRITE_ONLY_GBUFFER;
import org.terasology.rendering.opengl.FBO;
import org.terasology.rendering.opengl.FBOConfig;
import org.terasology.rendering.opengl.ScreenGrabber;

/**
 * TODO: Add javadocs
 * TODO: Better naming
 */
public class DisplayResolutionDependentFBOs extends AbstractFBOsManager {
    private FBO.Dimensions fullScale;
    private RenderingConfig renderingConfig;
    private ScreenGrabber screenGrabber;

    public DisplayResolutionDependentFBOs(Context context) {
        renderingConfig = context.get(Config.class).getRendering();
        screenGrabber = context.get(ScreenGrabber.class);
        fullScale = new FBO.Dimensions(Display.getWidth(), Display.getHeight());
        generateDefaultFBOs();
    }

    @Override
    public FBO request(FBOConfig fboConfig) {
        FBO fbo;
        ResourceUrn fboName = fboConfig.getName();
        if (fboConfigs.containsKey(fboName)) {
            if (!fboConfig.equals(fboConfigs.get(fboName))) {
                throw new IllegalArgumentException("Requested FBO is already available with different configuration");
            }
            fbo = fboLookup.get(fboConfig.getName());
        } else {
            fbo = generateWithDimensions(fboConfig, fullScale.multiplyBy(fboConfig.getScale()));
        }
        retain(fboName);
        return fbo;
    }

    private void generateDefaultFBOs() {
        generateDefaultFBO(READ_ONLY_GBUFFER);
        generateDefaultFBO(WRITE_ONLY_GBUFFER);
        generateDefaultFBO(FINAL);
    }

    private void generateDefaultFBO(DefaultDynamicFBOs defaultDynamicFBO) {
        FBOConfig fboConfig = defaultDynamicFBO.getConfig();
        FBO fbo = generateWithDimensions(fboConfig, fullScale.multiplyBy(fboConfig.getScale()));
        defaultDynamicFBO.setFbo(fbo);
    }

    /**
     * Invoked before real-rendering starts
     * TODO: how about completely removing this, and make Display observable and this FBM as an observer
     */
    public void update() {
        updateFullScale();
        if (get(READ_ONLY_GBUFFER.getName()).dimensions().areDifferentFrom(fullScale)) {
            disposeAllFBOs();
            createFBOs();
            updateDefaultFBOs();
        }
    }

    private void updateDefaultFBOs() {
        READ_ONLY_GBUFFER.setFbo(fboLookup.get(READ_ONLY_GBUFFER.getName()));
        WRITE_ONLY_GBUFFER.setFbo(fboLookup.get(WRITE_ONLY_GBUFFER.getName()));
        FINAL.setFbo(fboLookup.get(FINAL.getName()));
    }

    private void disposeAllFBOs() {
        for (ResourceUrn urn : fboConfigs.keySet()) {
            fboLookup.get(urn).dispose();
            fboLookup.remove(urn);
        }
        fboLookup.clear();
    }

    private void createFBOs() {
        for (FBOConfig fboConfig : fboConfigs.values()) {
            generateWithDimensions(fboConfig, fullScale.multiplyBy(fboConfig.getScale()));
        }

        notifySubscribers();
    }

    private void updateFullScale() {
        if (screenGrabber.isNotTakingScreenshot()) {
            fullScale = new FBO.Dimensions(Display.getWidth(), Display.getHeight());
            if (renderingConfig.isOculusVrSupport()) {
                fullScale.multiplySelfBy(OculusVrHelper.getScaleFactor());
            }
        } else {
            fullScale = new FBO.Dimensions(
                    renderingConfig.getScreenshotSize().getWidth(Display.getWidth()),
                    renderingConfig.getScreenshotSize().getHeight(Display.getHeight())
            );
        }

        fullScale.multiplySelfBy(renderingConfig.getFboScale() / 100f);
    }

    // TODO: Pairing FBOs for swapping functionality
    public void swapReadWriteBuffers() {
        FBO fbo = READ_ONLY_GBUFFER.getFbo();
        READ_ONLY_GBUFFER.setFbo(WRITE_ONLY_GBUFFER.getFbo());
        WRITE_ONLY_GBUFFER.setFbo(fbo);
        fboLookup.put(READ_ONLY_GBUFFER.getName(), READ_ONLY_GBUFFER.getFbo());
        fboLookup.put(WRITE_ONLY_GBUFFER.getName(), WRITE_ONLY_GBUFFER.getFbo());
    }
}

@@ -1954,24 +1954,482 @@
 s();%0A    %7D%0A%0A
+    private void generateDefaultFBOs() %7B%0A        generateDefaultFBO(READ_ONLY_GBUFFER);%0A        generateDefaultFBO(WRITE_ONLY_GBUFFER);%0A        generateDefaultFBO(FINAL);%0A    %7D%0A%0A    private void generateDefaultFBO(DefaultDynamicFBOs defaultDynamicFBO) %7B%0A        FBOConfig fboConfig = defaultDynamicFBO.getConfig();%0A        FBO fbo = generateWithDimensions(fboConfig, fullScale.multiplyBy(fboConfig.getScale()));%0A        defaultDynamicFBO.setFbo(fbo);%0A    %7D%0A%0A
     @Overrid
@@ -2430,16 +2430,16 @@
 verride%0A
-
     publ
@@ -3020,466 +3020,8 @@
  %7D%0A%0A
-    private void generateDefaultFBOs() %7B%0A        generateDefaultFBO(READ_ONLY_GBUFFER);%0A        generateDefaultFBO(WRITE_ONLY_GBUFFER);%0A        generateDefaultFBO(FINAL);%0A    %7D%0A%0A    private void generateDefaultFBO(DefaultDynamicFBOs defaultDynamicFBO) %7B%0A        FBOConfig fboConfig = defaultDynamicFBO.getConfig();%0A        FBO fbo = generateWithDimensions(fboConfig, fullScale.multiplyBy(fboConfig.getScale()));%0A        defaultDynamicFBO.setFbo(fbo);%0A    %7D%0A%0A
     
@@ -3774,24 +3774,24 @@
 keySet()) %7B%0A
+
             
@@ -3824,43 +3824,8 @@
 ();%0A
-            fboLookup.remove(urn);%0A
     

Move request method in DisplayResolutionDependentFBOs, minor changes