/*
 * Copyright 2016-present Open Networking Foundation
 *
 * 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 org.onosproject.cpman.gui;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.LocalDateTime;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.NodeId;
import org.onosproject.cpman.ControlLoadSnapshot;
import org.onosproject.cpman.ControlMetricType;
import org.onosproject.cpman.ControlPlaneMonitorService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.device.DeviceService;
import org.onosproject.ui.RequestHandler;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.chart.ChartModel;
import org.onosproject.ui.chart.ChartRequestHandler;

import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.LongStream;

import static org.onosproject.cpman.ControlResource.CONTROL_MESSAGE_METRICS;
import static org.onosproject.cpman.ControlResource.Type.CONTROL_MESSAGE;

/**
 * Message handler for control plane monitoring view related messages.
 */
public class CpmanViewMessageHandler extends UiMessageHandler {

    private static final String CPMAN_DATA_REQ = "cpmanDataRequest";
    private static final String CPMAN_DATA_RESP = "cpmanDataResponse";
    private static final String CPMANS = "cpmans";

    private static final String DEVICE_IDS = "deviceIds";

    // TODO: we assume that server side always returns 20 data points
    // to feed 20 minutes time slots, later this should make to be configurable
    private static final int NUM_OF_DATA_POINTS = 20;

    private static final int MILLI_CONV_UNIT = 1000;

    private static final String TIME_FORMAT = "HH:mm";

    private long timestamp = 0L;

    @Override
    protected Collection<RequestHandler> createRequestHandlers() {
        return ImmutableSet.of(
                new ControlMessageRequest()
        );
    }

    private final class ControlMessageRequest extends ChartRequestHandler {

        private ControlMessageRequest() {
            super(CPMAN_DATA_REQ, CPMAN_DATA_RESP, CPMANS);
        }

        @Override
        protected String[] getSeries() {
            return CONTROL_MESSAGE_METRICS.stream().map(type ->
                    StringUtils.lowerCase(type.name())).toArray(String[]::new);
        }

        @Override
        protected void populateChart(ChartModel cm, ObjectNode payload) {
            String uri = string(payload, "devId");
            ControlPlaneMonitorService cpms = get(ControlPlaneMonitorService.class);
            ClusterService cs = get(ClusterService.class);
            DeviceService ds = get(DeviceService.class);
            NodeId localNodeId = cs.getLocalNode().id();

            if (!Strings.isNullOrEmpty(uri)) {
                DeviceId deviceId = DeviceId.deviceId(uri);
                if (cpms.availableResourcesSync(localNodeId, CONTROL_MESSAGE).contains(deviceId.toString())) {
                    Map<ControlMetricType, Long[]> data = generateMatrix(cpms, cs, deviceId);
                    LocalDateTime ldt = new LocalDateTime(timestamp * MILLI_CONV_UNIT);

                    populateMetrics(cm, data, ldt, NUM_OF_DATA_POINTS);

                    Set<DeviceId> deviceIds = Sets.newHashSet();
                    ds.getAvailableDevices().forEach(device -> deviceIds.add(device.id()));
                    attachDeviceList(cm, deviceIds);
                }
            } else {
                Set<String> deviceIds = cpms.availableResourcesSync(localNodeId, CONTROL_MESSAGE);
                for (String deviceId : deviceIds) {
                    Map<ControlMetricType, Long> data =
                            populateDeviceMetrics(cpms, cs, DeviceId.deviceId(deviceId));
                    Map<String, Object> local = Maps.newHashMap();
                    for (ControlMetricType cmt : CONTROL_MESSAGE_METRICS) {
                        local.put(StringUtils.lowerCase(cmt.name()), data.get(cmt));
                    }

                    local.put(LABEL, deviceId);
                    populateMetric(cm.addDataPoint(deviceId), local);
                }
            }
        }

        private Map<ControlMetricType, Long> populateDeviceMetrics(ControlPlaneMonitorService cpms,
                                                                   ClusterService cs, DeviceId deviceId) {
            Map<ControlMetricType, Long> data = Maps.newHashMap();
            for (ControlMetricType cmt : CONTROL_MESSAGE_METRICS) {
                ControlLoadSnapshot cls = cpms.getLoadSync(cs.getLocalNode().id(),
                        cmt, NUM_OF_DATA_POINTS, TimeUnit.MINUTES, Optional.of(deviceId));
                data.put(cmt, Math.round(LongStream.of(cls.recent()).average().getAsDouble()));
                timestamp = cls.time();
            }
            return data;
        }

        private Map<ControlMetricType, Long[]> generateMatrix(ControlPlaneMonitorService cpms,
                                                              ClusterService cs, DeviceId deviceId) {
            Map<ControlMetricType, Long[]> data = Maps.newHashMap();
            for (ControlMetricType cmt : CONTROL_MESSAGE_METRICS) {
                ControlLoadSnapshot cls = cpms.getLoadSync(cs.getLocalNode().id(),
                        cmt, NUM_OF_DATA_POINTS, TimeUnit.MINUTES, Optional.of(deviceId));

                // TODO: in some cases, the number of returned data set is
                // less than what we expected (expected -1)
                // As a workaround, we simply fill the slot with 0 values,
                // such a bug should be fixed with updated RRD4J lib...
                data.put(cmt, ArrayUtils.toObject(fillData(cls.recent(), NUM_OF_DATA_POINTS)));
                timestamp = cls.time();
            }
            return data;
        }

        private long[] fillData(long[] origin, int expected) {
            if (origin.length == expected) {
                return origin;
            } else {
                long[] filled = new long[expected];
                for (int i = 0; i < expected; i++) {
                    if (i == 0) {
                        filled[i] = 0;
                    } else {
                        filled[i] = origin[i - 1];
                    }
                }
                return filled;
            }
        }

        private void populateMetrics(ChartModel cm,
                                     Map<ControlMetricType, Long[]> data,
                                     LocalDateTime time, int numOfDp) {
            for (int i = 0; i < numOfDp; i++) {
                Map<String, Object> local = Maps.newHashMap();
                for (ControlMetricType cmt : CONTROL_MESSAGE_METRICS) {
                    local.put(StringUtils.lowerCase(cmt.name()), data.get(cmt)[i]);
                }

                String calculated = time.minusMinutes(numOfDp - i).toString(TIME_FORMAT);

                local.put(LABEL, calculated);
                populateMetric(cm.addDataPoint(calculated), local);
            }
        }

        private void populateMetric(ChartModel.DataPoint dataPoint,
                                    Map<String, Object> data) {
            data.forEach(dataPoint::data);
        }

        private void attachDeviceList(ChartModel cm, Set<DeviceId> deviceIds) {
            ArrayNode array = arrayNode();
            deviceIds.forEach(id -> array.add(id.toString()));
            cm.addAnnotation(DEVICE_IDS, array);
        }
    }
}
