/*
 * Copyright 2015 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.logic.players;

import org.terasology.entitySystem.entity.EntityBuilder;
import org.terasology.entitySystem.entity.EntityManager;
import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.entitySystem.entity.lifecycleEvents.OnActivatedComponent;
import org.terasology.entitySystem.entity.lifecycleEvents.OnChangedComponent;
import org.terasology.entitySystem.event.ReceiveEvent;
import org.terasology.entitySystem.systems.BaseComponentSystem;
import org.terasology.entitySystem.systems.RegisterMode;
import org.terasology.entitySystem.systems.RegisterSystem;
import org.terasology.logic.characters.GazeAuthoritySystem;
import org.terasology.logic.console.commandSystem.annotations.Command;
import org.terasology.logic.location.Location;
import org.terasology.logic.location.LocationComponent;
import org.terasology.logic.permission.PermissionManager;
import org.terasology.logic.players.event.ResetCameraEvent;
import org.terasology.math.geom.Quat4f;
import org.terasology.math.geom.Vector3f;
import org.terasology.network.ClientComponent;
import org.terasology.registry.In;

@RegisterSystem(RegisterMode.CLIENT)
public class CameraClientSystem extends BaseComponentSystem {
    @In
    LocalPlayer localPlayer;
    @In
    EntityManager entityManager;

    @ReceiveEvent
    public void onAutoMountCamera(OnChangedComponent event, EntityRef client, AutoMountCameraComponent autoMountCameraComponent, ClientComponent clientComponent) {
        if (clientComponent.camera.exists()) {
            client.send(new ResetCameraEvent());
        }
    }

    @ReceiveEvent
    public void ensureCameraEntityCreated(OnActivatedComponent event, EntityRef entityRef, ClientComponent clientComponent) {
        if (!clientComponent.camera.exists()) {
            EntityBuilder builder = entityManager.newBuilder("engine:camera");
            builder.setPersistent(false);
            clientComponent.camera = builder.build();
            entityRef.saveComponent(clientComponent);
        }
    }

    @Command(shortDescription = "Reset the camera position", requiredPermission = PermissionManager.NO_PERMISSION)
    public void resetCamera() {
        localPlayer.getClientEntity().send(new ResetCameraEvent());
    }

    @ReceiveEvent
    public void resetCamera(ResetCameraEvent resetCameraEvent, EntityRef client, AutoMountCameraComponent autoMountCameraComponent, ClientComponent clientComponent) {
        EntityRef targetEntityForCamera = GazeAuthoritySystem.getGazeEntityForCharacter(clientComponent.character);
        LocationComponent cameraLocation = clientComponent.camera.getComponent(LocationComponent.class);
        Vector3f cameraPosition;
        if (cameraLocation == null) {
            cameraPosition = Vector3f.zero();
        } else {
            cameraPosition = cameraLocation.getLocalPosition();
        }
        Location.attachChild(targetEntityForCamera, clientComponent.camera, cameraPosition, new Quat4f(Quat4f.IDENTITY));
    }
}

@@ -1473,32 +1473,96 @@
 missionManager;%0A
+import org.terasology.logic.players.event.OnPlayerSpawnedEvent;%0A
 import org.teras
@@ -1986,25 +1986,57 @@
 oid 
-onAutoMountCamera
+ensureCameraEntityCreatedOnChangedClientComponent
 (OnC
@@ -2178,89 +2178,94 @@
 if (
-clientComponent.camera.exists()) %7B%0A            client.send(new ResetCameraEvent()
+localPlayer.getClientEntity().equals(client)) %7B%0A            ensureCameraEntityCreated(
 );%0A 
@@ -2339,16 +2339,41 @@
 yCreated
+OnActivateClientComponent
 (OnActiv
@@ -2418,90 +2418,421 @@
 ef, 
-ClientComponent clientComponent) %7B%0A        if (!clientComponent.camera.exists()) %7B
+AutoMountCameraComponent autoMountCameraComponent, ClientComponent clientComponent) %7B%0A        if (localPlayer.getClientEntity().equals(entityRef)) %7B%0A            ensureCameraEntityCreated();%0A        %7D%0A    %7D%0A%0A    void ensureCameraEntityCreated() %7B%0A        if (!localPlayer.getCameraEntity().exists()) %7B%0A            ClientComponent clientComponent = localPlayer.getClientEntity().getComponent(ClientComponent.class);
 %0A   
@@ -3015,25 +3015,45 @@
         
-e
+localPlayer.getClientE
 ntity
-Ref
+()
 .saveCom
@@ -3077,16 +3077,43 @@
 onent);%0A
+            mountCamera();%0A
         
@@ -3426,38 +3426,41 @@
 vent, EntityRef 
-cli
 ent
+ityRef
 , AutoMountCamer
@@ -3523,32 +3523,645 @@
 entComponent) %7B%0A
+        if (localPlayer.getClientEntity().equals(entityRef)) %7B%0A            clientComponent.camera.destroy();%0A            clientComponent.camera = EntityRef.NULL;%0A            // this will trigger a ClientComponent change which will in turn trigger a remount%0A            localPlayer.getClientEntity().saveComponent(clientComponent);%0A        %7D%0A    %7D%0A%0A    @Command(shortDescription = %22Mounts the camera to the character%22, requiredPermission = PermissionManager.NO_PERMISSION)%0A    public void mountCamera() %7B%0A        ClientComponent clientComponent = localPlayer.getClientEntity().getComponent(ClientComponent.class);%0A
         EntityRe
@@ -4700,11 +4700,234 @@
 );%0A    %7D
+%0A%0A    @ReceiveEvent%0A    public void resetCameraOnCharacterSpawn(OnPlayerSpawnedEvent event, EntityRef character) %7B%0A        if (localPlayer.getCharacterEntity().equals(character)) %7B%0A            resetCamera();%0A        %7D%0A    %7D
 %0A%7D%0A

Fix camera linking to a respawned character.