package org.ntlab.radishforandroidstudio.cactusClient.models;

import net.arnx.jsonic.JSON;
import net.arnx.jsonic.TypeReference;

import org.ntlab.radishforandroidstudio.cactusClient.connections.PlayersConnection;
import org.ntlab.radishforandroidstudio.framework.gameMain.Actor;
import org.ntlab.radishforandroidstudio.framework.gameMain.GameBaseModel;
import org.ntlab.radishforandroidstudio.framework.gameMain.RealTime3DFragment;
import org.ntlab.radishforandroidstudio.framework.model3D.ModelFactory;
import org.ntlab.radishforandroidstudio.framework.model3D.Object3D;
import org.ntlab.radishforandroidstudio.framework.model3D.Property3D;
import org.ntlab.radishforandroidstudio.framework.model3D.Universe;
import org.ntlab.radishforandroidstudio.framework.network.CallBack;
import org.ntlab.radishforandroidstudio.java3d.Appearance;
import org.ntlab.radishforandroidstudio.java3d.Material;

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

/**
 * 自キャラ以外の全操作キャラを管理するモデル
 *
 * @author s.iwatani
 */
public class OtherPlayerCharactersModel implements GameBaseModel, CallBack {
    private Universe universe;
    private RealTime3DFragment fragment;
    private ArrayList<Actor> otherCharacters = new ArrayList<>();
    private PlayersConnection con;
    private int nextConnectRenaimdTime = 0;
    private int connectInterval = 300;
    private Map<String, Integer> visibleCharacters = new HashMap<>();
    private String instanceId;
    private String playerId;

    public OtherPlayerCharactersModel(RealTime3DFragment fragment, Universe universe) {
        this.fragment = fragment;
        this.universe = universe;
    }

    public void setInstanceId(String id) {
        this.instanceId = id;
    }

    public void setPlayerId(String id) {
        playerId = id;
    }

    /**
     * キャラクターの状態を更新する
     *
     * @author s.iwatani
     * @param interval 前回の更新からの時間差
     */
    @Override
    public void update(double interval) {
        nextConnectRenaimdTime -= interval;
        if (nextConnectRenaimdTime <= 0) {
            nextConnectRenaimdTime = connectInterval;
            con = new PlayersConnection();
            con.addQueryParam("instanceId", instanceId);
            con.setCallBack(this);
            con.doGet();
        }
    }

    @Override
    public void onResponse(String response) {
        Map<String, Integer> lastVisibleCharacters = new HashMap<>(visibleCharacters);
        visibleCharacters.clear();
        JSON json = new JSON();
        Map<String, Player> m = json.decode(response, new TypeReference<Map<String, Player>>(){});
        for (Map.Entry<String, Player> entry: m.entrySet()) {
            visibleCharacters.put(entry.getKey(), 1);
            ArrayList<Property3D> properties = new ArrayList<>();
            Player player = entry.getValue();

            // 自分自身は無視する
            System.out.println(entry.getKey() + ", " + playerId);
            if (entry.getKey().equals(playerId)) continue;

            // 情報の取得
//            Map position = (Map)player.get("position");
//            Map angle = (Map)player.get("angle");
//            Position3D positionProp = new Position3D(((BigDecimal)position.get("x")).doubleValue(), ((BigDecimal)position.get("y")).doubleValue(), ((BigDecimal)position.get("z")).doubleValue());
//            Quaternion3D quaProp = new Quaternion3D(((BigDecimal)angle.get("x")).doubleValue(), ((BigDecimal)angle.get("y")).doubleValue(), ((BigDecimal)angle.get("z")).doubleValue(), ((BigDecimal)angle.get("w")).doubleValue());

            properties.add(player.getPosition());
            properties.add(player.getAngle());

            if (!universe.doHaveObj(entry.getKey())) {
                Appearance ap1 = new Appearance();
                Material mat = new Material();
                mat.setDiffuseColor(0.0f, 0.3f, 1.0f);
                mat.setAmbientColor(0.0f, 0.0f, 0.0f);
                mat.setEmissiveColor(0.0f, 0.0f, 0.0f);
                mat.setSpecularColor(0.0f, 0.0f, 0.0f);
                mat.setShininess(5.0f);
                ap1.setMaterial(mat);

                Object3D pochaBody = null;
                try {
                    pochaBody = ModelFactory.loadModel(fragment.getResources(), "pocha.stl", ap1).createObject();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                OtherPlayerCharacter chara = new OtherPlayerCharacter(pochaBody);
                universe.place(entry.getKey(), chara);
                universe.place(chara);
            }
            universe.apply(entry.getKey(), properties);
        }

        // 見えなくなったキャラクターの削除
        for (String key : lastVisibleCharacters.keySet()) {
            if (visibleCharacters.get(key) == null) {
                universe.displace(key);
            }
        }
    }
}
