package org.ntlab.radishforandroidstudio.cactusClient.models;


import org.ntlab.radishforandroidstudio.framework.gameMain.OvergroundActor;
import org.ntlab.radishforandroidstudio.framework.model3D.Object3D;
import org.ntlab.radishforandroidstudio.framework.model3D.Position3D;
import org.ntlab.radishforandroidstudio.framework.model3D.Quaternion3D;

import net.arnx.jsonic.JSONHint;

import java.io.Serializable;

public class Player extends Entity3D implements Serializable {
    private String instanceID;
    private String characterID;
    private String areaURI;
    private Position3D position;
    private Quaternion3D angle;
    private CameraState cameraState;
    private EmoteState emoteState;
    @JSONHint(ignore = true)
    public static final int UNIQUE_ID_LENGTH = 12;

    private Player() {
        // JSONDecode時の呼び出し用
    }

    public Player(String instanceID, String characterID, CameraState cameraState,
                  EmoteState.EmoteType animationClassToStart) {
        setInstanceID(instanceID);
        setCharacterID(characterID);
        setCameraState(cameraState);
        setAnimationClassToStart(animationClassToStart);
        Character character = getCharacter(characterID);
        readCharacterData(character);
        initPlaceable(character.getModelID());
    }

    private void initPlaceable(int modelID) {
        // こんな感じで当該コンストラクタの最後でplaceableの注入を行う
        Object3D body = CharacterModelManager.getInstance().getCharacterModel(modelID).createObject();
        setPlaceable(new OvergroundActor(body, null));
        // 所属するInstanceが持つUniverseにplaceableを配置する
        String[] instanceURISplit = instanceID.split("/"); // ……/instances/{instanceId}
        String instanceId = instanceURISplit[instanceURISplit.length - 1];
        Instances.getInstance().getInstance(instanceId).getUniverse().place(this.getPlaceable());
    }

    public String getInstanceID() {
        return instanceID;
    }

    public String getCharacterID() {
        return characterID;
    }

    public String getAreaURI() {
        return areaURI;
    }

    public Position3D getPosition() {
        return position;
    }

    public Quaternion3D getAngle() {
        return angle;
    }

    public CameraState getCameraState() {
        return cameraState;
    }

    public EmoteState getEmoteState() {
        return emoteState;
    }

    public void setInstanceID(String instanceID) {
        this.instanceID = instanceID;
    }

    public void setCharacterID(String characterID) {
        this.characterID = characterID;
    }

    public void setAreaURI(String areaURI) {
        this.areaURI = areaURI;
    }

    public void setPosition(Position3D position) {
        this.position = position;
    }

    public void setAngle(Quaternion3D angle) {
        this.angle = angle;
    }

    public void setCameraState(CameraState cameraState) {
        this.cameraState = cameraState;
    }

    public void setEmoteState(EmoteState emoteState) {
        this.emoteState = emoteState;
    }

    public void setAnimationClassToStart(EmoteState.EmoteType animationClassToStart) {
        setEmoteState(new EmoteState(animationClassToStart));
    }

    public Player update(String characterURI, Position3D position, Quaternion3D angle, CameraState cameraState,
                         EmoteState.EmoteType animationClassToStart) {
        setCharacterID(characterURI);
        setPosition(position);
        setAngle(angle);
        setCameraState(cameraState);
        updateEmoteType(animationClassToStart);
        updateAreaURI();
        return this;
    }

    private void updateAreaURI() {
        String[] areaURISplit = areaURI.split("/"); // ……/instances/{instanceId}/areas/{areaId}
        int splitSize = areaURISplit.length;
        String instanceId = areaURISplit[splitSize - 3];
        String previousAreaId = areaURISplit[splitSize - 1];
        Instance instance = Instances.getInstance().getInstance(instanceId);
        Area previousArea = instance.getArea(previousAreaId);
        if (!previousArea.isSurroundingPosition(position)) {
            // キャラクターのポジションを用いてどのエリア内にいるかを判定して当該エリアのURIに更新する
            setAreaURI(findAreaURI(instance));
        }
    }

    private String findAreaURI(Instance instance) {
        // キャラクターのポジションを用いてどのエリア内にいるかを判定して当該エリアのURIに更新する
        for (String areaId : instance.getAreas().keySet()) {
            Area area = instance.getArea(areaId);
            if (area.isSurroundingPosition(position)) {
                int subStringEndIndex = areaURI.length() - Area.UNIQUE_ID_LENGTH; // …/{instanceId}/areas/ まで
                return areaURI.substring(0, subStringEndIndex) + areaId;
            }
        }
        return "";
    }

    private void updateEmoteType(EmoteState.EmoteType animationClassToStart) {
        emoteState.setEmoteType(animationClassToStart);
    }

    public void changeCharacter(String characterURI) {
        writeCharacterData(this.characterID);
        readCharacterData(characterURI);
    }

    public void destroy() {
        writeCharacterData(characterID);
    }

    private Character getCharacter(String characterURI) {
        String[] characterURISplit = characterURI.split("/"); // ……/instances/{instanceId}/characters/{characterId}
        int splitSize = characterURISplit.length;
        String characterId = characterURISplit[splitSize - 1];
        String instanceId = characterURISplit[splitSize - 3];
        return Instances.getInstance().getInstance(instanceId).getCharacter(characterId);
    }

    private void readCharacterData(Character character) {
        setPosition(character.getPosition());
        setAngle(character.getQuaternion3D());
        setAreaURI(character.getAreaURI());
        setCharacterID(characterID);
    }

    private void readCharacterData(String characterURI) {
        Character character = getCharacter(characterURI);
        readCharacterData(character);
    }

    private void writeCharacterData(String characterURI) {
        Character character = getCharacter(characterURI);
        character.update(position, angle, null, areaURI); // model(第3引数)の更新は出来ない
    }
}