/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.cassandra.net;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.config.EncryptionOptions;
import org.apache.cassandra.locator.InetAddressAndPort;
import org.apache.cassandra.metrics.InternodeOutboundMetrics;
import org.apache.cassandra.metrics.MessagingMetrics;
import org.apache.cassandra.security.SSLFactory;
import org.apache.cassandra.utils.MBeanWrapper;

public class MessagingServiceMBeanImpl implements MessagingServiceMBean
{
    public static final String MBEAN_NAME = "org.apache.cassandra.net:type=MessagingService";

    // we use CHM deliberately instead of NBHM, as both are non-blocking for readers (which this map mostly is used for)
    // and CHM permits prompter GC
    public final ConcurrentMap<InetAddressAndPort, OutboundConnections> channelManagers = new ConcurrentHashMap<>();
    public final ConcurrentMap<InetAddressAndPort, InboundMessageHandlers> messageHandlers = new ConcurrentHashMap<>();

    public final EndpointMessagingVersions versions = new EndpointMessagingVersions();
    public final MessagingMetrics metrics = new MessagingMetrics();

    MessagingServiceMBeanImpl(boolean testOnly)
    {
        if (!testOnly)
        {
            MBeanWrapper.instance.registerMBean(this, MBEAN_NAME);
            metrics.scheduleLogging();
        }
    }

    @Override
    public Map<String, Integer> getLargeMessagePendingTasks()
    {
        Map<String, Integer> pendingTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            pendingTasks.put(entry.getKey().toString(false), entry.getValue().large.pendingCount());
        return pendingTasks;
    }

    @Override
    public Map<String, Long> getLargeMessageCompletedTasks()
    {
        Map<String, Long> completedTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            completedTasks.put(entry.getKey().toString(false), entry.getValue().large.sentCount());
        return completedTasks;
    }

    @Override
    public Map<String, Long> getLargeMessageDroppedTasks()
    {
        Map<String, Long> droppedTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            droppedTasks.put(entry.getKey().toString(false), entry.getValue().large.dropped());
        return droppedTasks;
    }

    @Override
    public Map<String, Integer> getSmallMessagePendingTasks()
    {
        Map<String, Integer> pendingTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            pendingTasks.put(entry.getKey().toString(false), entry.getValue().small.pendingCount());
        return pendingTasks;
    }

    @Override
    public Map<String, Long> getSmallMessageCompletedTasks()
    {
        Map<String, Long> completedTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            completedTasks.put(entry.getKey().toString(false), entry.getValue().small.sentCount());
        return completedTasks;
    }

    @Override
    public Map<String, Long> getSmallMessageDroppedTasks()
    {
        Map<String, Long> droppedTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            droppedTasks.put(entry.getKey().toString(false), entry.getValue().small.dropped());
        return droppedTasks;
    }

    @Override
    public Map<String, Integer> getGossipMessagePendingTasks()
    {
        Map<String, Integer> pendingTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            pendingTasks.put(entry.getKey().toString(false), entry.getValue().urgent.pendingCount());
        return pendingTasks;
    }

    @Override
    public Map<String, Long> getGossipMessageCompletedTasks()
    {
        Map<String, Long> completedTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            completedTasks.put(entry.getKey().toString(false), entry.getValue().urgent.sentCount());
        return completedTasks;
    }

    @Override
    public Map<String, Long> getGossipMessageDroppedTasks()
    {
        Map<String, Long> droppedTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            droppedTasks.put(entry.getKey().toString(false), entry.getValue().urgent.dropped());
        return droppedTasks;
    }

    @Override
    public Map<String, Integer> getLargeMessagePendingTasksWithPort()
    {
        Map<String, Integer> pendingTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            pendingTasks.put(entry.getKey().toString(), entry.getValue().large.pendingCount());
        return pendingTasks;
    }

    @Override
    public Map<String, Long> getLargeMessageCompletedTasksWithPort()
    {
        Map<String, Long> completedTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            completedTasks.put(entry.getKey().toString(), entry.getValue().large.sentCount());
        return completedTasks;
    }

    @Override
    public Map<String, Long> getLargeMessageDroppedTasksWithPort()
    {
        Map<String, Long> droppedTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            droppedTasks.put(entry.getKey().toString(), entry.getValue().large.dropped());
        return droppedTasks;
    }

    @Override
    public Map<String, Integer> getSmallMessagePendingTasksWithPort()
    {
        Map<String, Integer> pendingTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            pendingTasks.put(entry.getKey().toString(), entry.getValue().small.pendingCount());
        return pendingTasks;
    }

    @Override
    public Map<String, Long> getSmallMessageCompletedTasksWithPort()
    {
        Map<String, Long> completedTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            completedTasks.put(entry.getKey().toString(), entry.getValue().small.sentCount());
        return completedTasks;
    }

    @Override
    public Map<String, Long> getSmallMessageDroppedTasksWithPort()
    {
        Map<String, Long> droppedTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            droppedTasks.put(entry.getKey().toString(), entry.getValue().small.dropped());
        return droppedTasks;
    }

    @Override
    public Map<String, Integer> getGossipMessagePendingTasksWithPort()
    {
        Map<String, Integer> pendingTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            pendingTasks.put(entry.getKey().toString(), entry.getValue().urgent.pendingCount());
        return pendingTasks;
    }

    @Override
    public Map<String, Long> getGossipMessageCompletedTasksWithPort()
    {
        Map<String, Long> completedTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            completedTasks.put(entry.getKey().toString(), entry.getValue().urgent.sentCount());
        return completedTasks;
    }

    @Override
    public Map<String, Long> getGossipMessageDroppedTasksWithPort()
    {
        Map<String, Long> droppedTasks = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
            droppedTasks.put(entry.getKey().toString(), entry.getValue().urgent.dropped());
        return droppedTasks;
    }

    @Override
    public Map<String, Integer> getDroppedMessages()
    {
        return metrics.getDroppedMessages();
    }

    @Override
    public long getTotalTimeouts()
    {
        return InternodeOutboundMetrics.totalExpiredCallbacks.getCount();
    }

    // these are not messages that time out on sending, but callbacks that timedout without receiving a response
    @Override
    public Map<String, Long> getTimeoutsPerHost()
    {
        Map<String, Long> result = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
        {
            String ip = entry.getKey().toString(false);
            long recent = entry.getValue().expiredCallbacks();
            result.put(ip, recent);
        }
        return result;
    }

    // these are not messages that time out on sending, but callbacks that timedout without receiving a response
    @Override
    public Map<String, Long> getTimeoutsPerHostWithPort()
    {
        Map<String, Long> result = new HashMap<>(channelManagers.size());
        for (Map.Entry<InetAddressAndPort, OutboundConnections> entry : channelManagers.entrySet())
        {
            String ip = entry.getKey().toString();
            long recent = entry.getValue().expiredCallbacks();
            result.put(ip, recent);
        }
        return result;
    }

    @Override
    public Map<String, Double> getBackPressurePerHost()
    {
        throw new UnsupportedOperationException("This feature has been removed");
    }

    @Override
    public void setBackPressureEnabled(boolean enabled)
    {
        throw new UnsupportedOperationException("This feature has been removed");
    }

    @Override
    public boolean isBackPressureEnabled()
    {
        return false;
    }

    @Override
    public void reloadSslCertificates() throws IOException
    {
        final EncryptionOptions.ServerEncryptionOptions serverOpts = DatabaseDescriptor.getInternodeMessagingEncyptionOptions();
        final EncryptionOptions clientOpts = DatabaseDescriptor.getNativeProtocolEncryptionOptions();
        SSLFactory.validateSslCerts(serverOpts, clientOpts);
        SSLFactory.checkCertFilesForHotReloading(serverOpts, clientOpts);
    }

    @Override
    public int getVersion(String address) throws UnknownHostException
    {
        return versions.get(address);
    }
}
