/*
 * Copyright 2013 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.world.selection;

import org.terasology.asset.Assets;
import org.terasology.entitySystem.entity.EntityManager;
import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.entitySystem.systems.BaseComponentSystem;
import org.terasology.entitySystem.systems.RegisterMode;
import org.terasology.entitySystem.systems.RegisterSystem;
import org.terasology.entitySystem.systems.RenderSystem;
import org.terasology.math.geom.Vector2i;
import org.terasology.math.geom.Vector3i;
import org.terasology.registry.In;
import org.terasology.rendering.assets.texture.Texture;
import org.terasology.world.selection.BlockSelectionComponent;

import java.util.HashMap;
import java.util.Map;

/**
 * System to render registered BlockSelections.
 * <br><br>
 * This system is not currently thread-safe.
 *
 */
@RegisterSystem(RegisterMode.CLIENT)
public class BlockSelectionRenderSystem extends BaseComponentSystem implements RenderSystem {
    @In
    private EntityManager entityManager;

    /**
     * This map will contain one reusable selection renderer per texture width/height pair.
     * This should be a reasonable compromise between no caching and caching too many renderers.
     * While it is possible that the number of cached renderers could grow out of control over time,
     * in practice most textures should be a standard size.
     */
    private Map<Vector2i, BlockSelectionRenderer> cachedBlockSelectionRendererByTextureDimensionsMap = new HashMap<Vector2i, BlockSelectionRenderer>();

    @Override
    public void renderOverlay() {
        for (EntityRef entity : entityManager.getEntitiesWith(BlockSelectionComponent.class)) {
            BlockSelectionComponent blockSelectionComponent = entity.getComponent(BlockSelectionComponent.class);
            if (blockSelectionComponent.shouldRender) {
                Texture texture = blockSelectionComponent.texture;
                if (null == texture) {
                    texture = Assets.getTexture("engine:selection").get();
                }

                Vector2i textureDimensions = new Vector2i(texture.getWidth(), texture.getHeight());
                BlockSelectionRenderer selectionRenderer = cachedBlockSelectionRendererByTextureDimensionsMap.get(textureDimensions);
                if (null == selectionRenderer) {
                    selectionRenderer = new BlockSelectionRenderer(texture);
                    cachedBlockSelectionRendererByTextureDimensionsMap.put(textureDimensions, selectionRenderer);
                } else {
                    selectionRenderer.setEffectsTexture(texture);
                }

                renderOverlayForOneBlockSelection(blockSelectionComponent, selectionRenderer);
            }
        }
    }

    private void renderOverlayForOneBlockSelection(BlockSelectionComponent blockSelectionComponent,
                                                   BlockSelectionRenderer selectionRenderer) {
        selectionRenderer.beginRenderOverlay();
        if (blockSelectionComponent.currentSelection == null) {
            if (blockSelectionComponent.startPosition != null) {
                selectionRenderer.renderMark(blockSelectionComponent.startPosition);
            }
        } else {
            Vector3i size = blockSelectionComponent.currentSelection.size();
            Vector3i block = new Vector3i();
            for (int z = 0; z < size.z; z++) {
                for (int y = 0; y < size.y; y++) {
                    for (int x = 0; x < size.x; x++) {
                        block.set(x, y, z);
                        block.add(blockSelectionComponent.currentSelection.min());
                        selectionRenderer.renderMark(block);
                    }
                }
            }
        }
        selectionRenderer.endRenderOverlay();

    }

    @Override
    public void renderFirstPerson() {
    }

    @Override
    public void renderShadows() {
    }

    @Override
    public void renderOpaque() {
    }

    @Override
    public void renderAlphaBlend() {
    }
}
