package org.ntlab.radishforandroidstudio.cactusClient.models;

import java.util.HashMap;
import java.util.HashSet;

import org.ntlab.radishforandroidstudio.framework.model3D.Object3D;
import org.ntlab.radishforandroidstudio.framework.model3D.Position3D;
import org.ntlab.radishforandroidstudio.framework.model3D.Quaternion3D;
import org.ntlab.radishforandroidstudio.framework.model3D.Universe;
import org.ntlab.radishforandroidstudio.framework.physics.AngularVelocity3D;
import org.ntlab.radishforandroidstudio.framework.physics.Ground;
import org.ntlab.radishforandroidstudio.framework.physics.Velocity3D;

import net.arnx.jsonic.JSONHint;

/**
 * インスタンス
 *
 * @author r-isitani
 *
 */
public class Instance extends Entity {
    private String name;
    private State state;
    private int stageID;

    private Universe universe;
    private Ground stage;
    private HashMap<String, Area> areaMap = new HashMap<>();
    private HashMap<String, Object> objMap = new HashMap<>();
    private HashMap<String, Character> characterMap = new HashMap<>();
    @JSONHint(ignore = true)
    public static final int UNIQUE_ID_LENGTH = 12;

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

    public Instance(String name, int stageID) {
        setName(name);
        setState(Instance.State.AVAILABLE);
        setStageID(stageID);
        // initUniverse();
    }

    private void initUniverse() {
        universe = new Universe();
        // ステージの3Dデータを読み込み配置する
        Object3D stageObj = StageModelManager.getInstance().getStage(stageID).createObject();
        stage = new Ground(stageObj);
        universe.place(stage);
    }

    public String getName() {
        return name;
    }

    public State getState() {
        return state;
    }

    public int getStageID() {
        return stageID;
    }

    @JSONHint(ignore = true)
    public Universe getUniverse() {
        return universe;
    }

    @JSONHint(ignore = true)
    public HashMap<String, Area> getAreas() {
        return areaMap;
    }

    public Area getArea(String areaId) {
        return areaMap.get(areaId);
    }

    @JSONHint(ignore = true)
    public HashMap<String, Object> getObjects() {
        return objMap;
    }

    public Object getObject(String objId) {
        return objMap.get(objId);
    }

    @JSONHint(ignore = true)
    public HashMap<String, Character> getCharacters() {
        return characterMap;
    }

    public Character getCharacter(String characterId) {
        return characterMap.get(characterId);
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setState(State state) {
        this.state = state;
    }

    public void setStageID(int stageURI) {
        this.stageID = stageURI;
    }

    public HashMap<String, Area> createArea(String name, Plain[] region, HashSet<Area.Allowed> permissions) {
        String id = RandomStringGenerator.generateUniqueString(Area.UNIQUE_ID_LENGTH,
                RandomStringGenerator.ALPHA_NUMERIC, areaMap.keySet());
        Area area = new Area(name, region, permissions);
        areaMap.put(id, area);
        HashMap<String, Area> returnedMap = new HashMap<>();
        returnedMap.put(id, area);
        return returnedMap;
    }

    public HashMap<String, Object> createObject(Position3D position, Velocity3D velocity,
                                                AngularVelocity3D angularVelocity, Quaternion3D angle, Object.Attribute attribute, int modelID) {
        String id = RandomStringGenerator.generateUniqueString(Object.UNIQUE_ID_LENGTH,
                RandomStringGenerator.ALPHA_NUMERIC, objMap.keySet());
        Object object = new Object(position, velocity, angularVelocity, angle, attribute, modelID);
        objMap.put(id, object);
        universe.place(object.getPlaceable());
        HashMap<String, Object> returnedMap = new HashMap<>();
        returnedMap.put(id, object);
        return returnedMap;
    }

    public HashMap<String, Character> createCharacter(String instanceId, String accountURI, String name,
                                                      Position3D position, Quaternion3D angle, int modelID) {
        String id = RandomStringGenerator.generateUniqueString(Character.UNIQUE_ID_LENGTH,
                RandomStringGenerator.ALPHA_NUMERIC, characterMap.keySet());
        Character character = new Character(instanceId, accountURI, name, position, angle, modelID);
        characterMap.put(id, character);
        HashMap<String, Character> returnedMap = new HashMap<>();
        returnedMap.put(id, character);
        return returnedMap;
    }

    public Instance update(Instance.State state) {
        setState(state);
        return this;
    }

    public Character updateCharacter(String characterId, Position3D position, Quaternion3D angle, String modelID) {
        Character character = characterMap.get(characterId);
        character.update(position, angle, modelID, null); // areaURI(第4引数)の更新は呼び出し先で自動で行われる
        return character;
    }

    public Character destroyCharacter(String characterId) {
        return characterMap.remove(characterId);
    }

    public Area destroyArea(String areaId) {
        return areaMap.remove(areaId);
    }

    public Object destroyObject(String objId) {
        return objMap.remove(objId);
    }

    public static enum State {
        AVAILABLE, MAINTENANCE;
    }
}