package electrosphere.entity.types.terrain;

import org.joml.Vector3d;

import electrosphere.client.terrain.cells.DrawCell;
import electrosphere.client.terrain.cells.VoxelTextureAtlas;
import electrosphere.client.terrain.manager.ClientTerrainManager;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.renderer.meshgen.TerrainChunkModelGeneration;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
import electrosphere.server.datacell.Realm;

/**
 * Utilities for creating terrain chunk entities
 */
public class TerrainChunk {
    

    /**
     * Creates a client terrain chunk based on weights and values provided
     * @param chunkData the chunk data to generate with
     * @param levelOfDetail Increasing value that increments level of detail. 0 would be full resolution, 1 would be half resolution and so on. Only generates physics if levelOfDetail is 0
     * @return The terrain chunk entity
     */
    public static Entity clientCreateTerrainChunkEntity(TransvoxelChunkData chunkData, int levelOfDetail, VoxelTextureAtlas atlas){
        
        TerrainChunkData data;
        if(levelOfDetail == DrawCell.FULL_DETAIL_LOD){
            data = TerrainChunkModelGeneration.generateTerrainChunkData(chunkData.terrainGrid, chunkData.textureGrid, levelOfDetail);
        } else {
            data = TransvoxelModelGeneration.generateTerrainChunkData(chunkData);
        }
        String modelPath = ClientTerrainManager.queueTerrainGridGeneration(data, atlas);

        Entity rVal = EntityCreationUtils.createClientSpatialEntity();
        EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath);
        if(data.vertices.size() > 0 && levelOfDetail == DrawCell.FULL_DETAIL_LOD){
            PhysicsEntityUtils.clientAttachTerrainChunkRigidBody(rVal, data);
        }

        rVal.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
        rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);

        return rVal;
    }

    /**
     * Creates a terrain chunk entity on the server
     * @param realm The realm
     * @param position The position of the chunk
     * @param weights The weights for the terrain chunk
     * @param values The values of each voxel in the chunk
     * @return The terrain entity
     */
    public static Entity serverCreateTerrainChunkEntity(Realm realm, Vector3d position, float[][][] weights, int[][][] values){
        
        TerrainChunkData data = TerrainChunkModelGeneration.generateTerrainChunkData(weights, values, DrawCell.FULL_DETAIL_LOD);

        Entity rVal = EntityCreationUtils.createServerEntity(realm, position);
        if(data.vertices.size() > 0){
            PhysicsEntityUtils.serverAttachTerrainChunkRigidBody(rVal, data);
            rVal.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
            ServerEntityUtils.initiallyPositionEntity(realm, rVal, position);
                    // physicsObject = PhysicsUtils.attachTerrainRigidBody(physicsEntity,heightmap,true);
        // Realm realm = Globals.realmManager.getEntityRealm(physicsEntity);
        // realm.getCollisionEngine().registerPhysicsEntity(physicsEntity);

        }


        //position entity
        //this needs to be called at the end of this function.
        //Burried underneath this is function call to initialize a server side entity.
        //The server initialization logic checks what type of entity this is, if this function is called prior to its type being stored
        //the server will not be able to synchronize it properly.
        ServerEntityUtils.initiallyPositionEntity(realm,rVal,position);


        return rVal;
    }

}
