package org.forks.jsonrpc;

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

import org.json.JSONArray;
import org.json.JSONObject;

import static org.forks.jsonrpc.Helper.*;
import static org.forks.jsonrpc.RpcFacade.rpcCall;

public final class RpcObjectMeta {
    private final String mName;
    private final Map<String, RpcPropertyMeta> mProps;

    public RpcObjectMeta(String name, Map<String, RpcPropertyMeta> props) {
        super();
        mName = name;
        mProps = props;
    }

    public String getName() {
        return mName;
    }

    public Map<String, RpcPropertyMeta> getProps() {
        return mProps;
    }

    public static RpcObjectMeta parse(JSONObject jsonObj)
            throws JsonRpcException {
        String name = getString(jsonObj, "name");
        JSONArray propsJson = getJsonArray(jsonObj, "props");
        Map<String, RpcPropertyMeta> props = RpcPropertyMeta.parse(propsJson);
        return new RpcObjectMeta(name, props);
    }

    private static Map<String, RpcObjectMeta> sCache = new HashMap<String, RpcObjectMeta>();

    public static RpcObjectMeta get(String objPath) throws JsonRpcException {
        RpcObjectMeta result;
        synchronized (sCache) {
            result = sCache.get(objPath);
            if (result != null) {
                return result;
            }
        }

        result = getFromServer(objPath);
        synchronized (sCache) {
            sCache.put(objPath, result);
        }

        return result;
    }

    private static RpcObjectMeta getFromServer(String objPath)
            throws JsonRpcException {
        String getMethod = "/sbin/ObjectMeta/Get";
        String method = RpcFacade.toFullErtPathByPrefixedErt(objPath, getMethod);
        JsonRpcResult result = rpcCall(method, objPath);
        return parse(result.getJsonObject());
    }

    // only used in unit test
    static void registerMeta(String objPath, RpcObjectMeta meta) {
        if (sCache.put(objPath, meta) != null) {
            throw new JsonRpcRuntimeException(objPath);
        }
    }

    static void reset() {
        sCache.clear();
    }
}
