/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * 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 com.alibaba.nacos.core.monitor;

import com.alibaba.nacos.core.utils.Loggers;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;

import java.util.concurrent.ConcurrentHashMap;

/**
 * Metrics unified usage center.
 *
 * @author <a href="mailto:liuyixiao0821@gmail.com">liuyixiao</a>
 * @author xiweng.yy
 */
@SuppressWarnings("all")
public final class NacosMeterRegistryCenter {
    
    // stable registries.
    public static final String CORE_STABLE_REGISTRY = "CORE_STABLE_REGISTRY";
    
    public static final String CONFIG_STABLE_REGISTRY = "CONFIG_STABLE_REGISTRY";
    
    public static final String NAMING_STABLE_REGISTRY = "NAMING_STABLE_REGISTRY";
    
    // dynamic registries.
    public static final String TOPN_CONFIG_CHANGE_REGISTRY = "TOPN_CONFIG_CHANGE_REGISTRY";
    
    public static final String TOPN_SERVICE_CHANGE_REGISTRY = "TOPN_SERVICE_CHANGE_REGISTRY";
    
    // control plugin registeres.
    public static final String CONTROL_DENIED_REGISTRY = "CONTROL_DENIED_REGISTRY";

    public static final String LOCK_STABLE_REGISTRY = "LOCK_STABLE_REGISTRY";

    private static final ConcurrentHashMap<String, CompositeMeterRegistry> METER_REGISTRIES = new ConcurrentHashMap<>();
    
    private static CompositeMeterRegistry METER_REGISTRY = null;
    
    static {
        try {
            METER_REGISTRY = Metrics.globalRegistry;
        } catch (Throwable t) {
            Loggers.CORE.warn("Metrics init failed :", t);
        }
        registry(CORE_STABLE_REGISTRY, CONFIG_STABLE_REGISTRY, NAMING_STABLE_REGISTRY, TOPN_CONFIG_CHANGE_REGISTRY,
                TOPN_SERVICE_CHANGE_REGISTRY, CONTROL_DENIED_REGISTRY, LOCK_STABLE_REGISTRY);
        
    }
    
    private static void registry(String... names) {
        for (String name : names) {
            CompositeMeterRegistry compositeMeterRegistry = new CompositeMeterRegistry();
            if (METER_REGISTRY != null) {
                compositeMeterRegistry.add(METER_REGISTRY);
            }
            METER_REGISTRIES.put(name, compositeMeterRegistry);
        }
    }
    
    public static Counter counter(String registry, String name, Iterable<Tag> tags) {
        CompositeMeterRegistry compositeMeterRegistry = METER_REGISTRIES.get(registry);
        if (compositeMeterRegistry != null) {
            return METER_REGISTRIES.get(registry).counter(name, tags);
        }
        return null;
    }
    
    public static Counter counter(String registry, String name, String... tags) {
        CompositeMeterRegistry compositeMeterRegistry = METER_REGISTRIES.get(registry);
        if (compositeMeterRegistry != null) {
            return METER_REGISTRIES.get(registry).counter(name, tags);
        }
        return null;
    }
    
    public static <T extends Number> T gauge(String registry, String name, Iterable<Tag> tags, T number) {
        CompositeMeterRegistry compositeMeterRegistry = METER_REGISTRIES.get(registry);
        if (compositeMeterRegistry != null) {
            return METER_REGISTRIES.get(registry).gauge(name, tags, number);
        }
        return null;
    }
    
    public static Timer timer(String registry, String name, Iterable<Tag> tags) {
        CompositeMeterRegistry compositeMeterRegistry = METER_REGISTRIES.get(registry);
        if (compositeMeterRegistry != null) {
            return METER_REGISTRIES.get(registry).timer(name, tags);
        }
        return null;
    }
    
    public static Timer timer(String registry, String name, String... tags) {
        CompositeMeterRegistry compositeMeterRegistry = METER_REGISTRIES.get(registry);
        if (compositeMeterRegistry != null) {
            return METER_REGISTRIES.get(registry).timer(name, tags);
        }
        return null;
    }
    
    public static DistributionSummary summary(String registry, String name, Iterable<Tag> tags) {
        CompositeMeterRegistry compositeMeterRegistry = METER_REGISTRIES.get(registry);
        if (compositeMeterRegistry != null) {
            return METER_REGISTRIES.get(registry).summary(name, tags);
        }
        return null;
    }
    
    public static DistributionSummary summary(String registry, String name, String... tags) {
        CompositeMeterRegistry compositeMeterRegistry = METER_REGISTRIES.get(registry);
        if (compositeMeterRegistry != null) {
            return METER_REGISTRIES.get(registry).summary(name, tags);
        }
        return null;
    }
    
    public static void clear(String registry) {
        METER_REGISTRIES.get(registry).clear();
    }
    
    /**
     * Just for test. Don't register meter by getMeterRegistry.
     *
     * @param registry
     * @return CompositeMeterRegistry in NacosMeterRegistryCenter.
     */
    public static CompositeMeterRegistry getMeterRegistry(String registry) {
        return METER_REGISTRIES.get(registry);
    }
}
