/*
 * Copyright 2015-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.rest.resources;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import org.onlab.util.ItemNotFoundException;
import org.onosproject.app.ApplicationService;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.IndexTableId;
import org.onosproject.rest.AbstractWebResource;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.StreamSupport;

import static org.onlab.util.Tools.nullIsIllegal;
import static org.onlab.util.Tools.nullIsNotFound;
import static org.onlab.util.Tools.readTreeFromStream;

/**
 * Query and program flow rules.
 */

@Path("flows")
public class FlowsWebResource extends AbstractWebResource {

    @Context
    private UriInfo uriInfo;

    private static final String DEVICE_NOT_FOUND = "Device is not found";
    private static final String FLOW_NOT_FOUND = "Flow is not found";
    private static final String APP_ID_NOT_FOUND = "Application Id is not found";
    private static final String FLOW_ARRAY_REQUIRED = "Flows array was not specified";
    private static final String FLOWS = "flows";
    private static final String DEVICE_ID = "deviceId";
    private static final String FLOW_ID = "flowId";

    /**
     * Gets all flow entries. Returns array of all flow rules in the system.
     *
     * @return 200 OK with a collection of flows
     * @onos.rsModel FlowEntries
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getFlows() {
        ObjectNode root = mapper().createObjectNode();
        ArrayNode flowsNode = root.putArray(FLOWS);
        FlowRuleService service = get(FlowRuleService.class);
        Iterable<Device> devices = get(DeviceService.class).getDevices();
        for (Device device : devices) {
            Iterable<FlowEntry> flowEntries = service.getFlowEntries(device.id());
            if (flowEntries != null) {
                for (FlowEntry entry : flowEntries) {
                    flowsNode.add(codec(FlowEntry.class).encode(entry, this));
                }
            }
        }

        return ok(root).build();
    }

     /**
     * Gets all pending flow entries. Returns array of all pending flow rules in the system.
     *
     * @return 200 OK with a collection of flows
     * @onos.rsModel FlowEntries
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("pending")
    public Response getPendingFlows() {
        ObjectNode root = mapper().createObjectNode();
        ArrayNode flowsNode = root.putArray(FLOWS);
        FlowRuleService service = get(FlowRuleService.class);
        Iterable<Device> devices = get(DeviceService.class).getDevices();
        for (Device device : devices) {
            Iterable<FlowEntry> flowEntries = service.getFlowEntries(device.id());
            if (flowEntries != null) {
                for (FlowEntry entry : flowEntries) {
                    if ((entry.state() == FlowEntry.FlowEntryState.PENDING_ADD) ||
                       (entry.state() == FlowEntry.FlowEntryState.PENDING_REMOVE)) {
                       flowsNode.add(codec(FlowEntry.class).encode(entry, this));
                    }
                }
            }
        }

        return ok(root).build();
    }

     /**
     * Gets all flow entries for a table. Returns array of all flow rules for a table.
     * @param tableId table identifier
     * @return 200 OK with a collection of flows
     * @onos.rsModel FlowEntries
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("table/{tableId}")
    public Response getTableFlows(@PathParam("tableId") int tableId) {
        ObjectNode root = mapper().createObjectNode();
        ArrayNode flowsNode = root.putArray(FLOWS);
        FlowRuleService service = get(FlowRuleService.class);
        Iterable<Device> devices = get(DeviceService.class).getDevices();
        for (Device device : devices) {
            Iterable<FlowEntry> flowEntries = service.getFlowEntries(device.id());
            if (flowEntries != null) {
                for (FlowEntry entry : flowEntries) {
                    if (((IndexTableId) entry.table()).id() == tableId) {
                       flowsNode.add(codec(FlowEntry.class).encode(entry, this));
                    }
                }
            }
        }

        return ok(root).build();
    }

    /**
     * Creates new flow rules. Creates and installs a new flow rules.<br>
     * Flow rule criteria and instruction description:
     * https://wiki.onosproject.org/display/ONOS/Flow+Rules
     *
     * @param appId application id
     * @param stream flow rules JSON
     * @return status of the request - CREATED if the JSON is correct,
     * BAD_REQUEST if the JSON is invalid
     * @onos.rsModel FlowsBatchPost
     */
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response createFlows(@QueryParam("appId") String appId, InputStream stream) {
        FlowRuleService service = get(FlowRuleService.class);
        ObjectNode root = mapper().createObjectNode();
        ArrayNode flowsNode = root.putArray(FLOWS);
        try {
            ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
            ArrayNode flowsArray = nullIsIllegal((ArrayNode) jsonTree.get(FLOWS),
                                                 FLOW_ARRAY_REQUIRED);

            if (appId != null) {
                flowsArray.forEach(flowJson -> ((ObjectNode) flowJson).put("appId", appId));
            }

            List<FlowRule> rules = codec(FlowRule.class).decode(flowsArray, this);

            service.applyFlowRules(rules.toArray(new FlowRule[rules.size()]));
            rules.forEach(flowRule -> {
                ObjectNode flowNode = mapper().createObjectNode();
                flowNode.put(DEVICE_ID, flowRule.deviceId().toString())
                        .put(FLOW_ID, Long.toString(flowRule.id().value()));
                flowsNode.add(flowNode);
            });
        } catch (IOException ex) {
            throw new IllegalArgumentException(ex);
        }
        return Response.ok(root).build();
    }

    /**
     * Gets flow entries of a device. Returns array of all flow rules for the
     * specified device.
     *
     * @param deviceId device identifier
     * @return 200 OK with a collection of flows of given device
     * @onos.rsModel FlowEntries
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    // TODO: we need to add "/device" suffix to the path to differentiate with appId
    @Path("{deviceId}")
    public Response getFlowByDeviceId(@PathParam("deviceId") String deviceId) {
        FlowRuleService service = get(FlowRuleService.class);
        ObjectNode root = mapper().createObjectNode();
        ArrayNode flowsNode = root.putArray(FLOWS);
        Iterable<FlowEntry> flowEntries =
                service.getFlowEntries(DeviceId.deviceId(deviceId));

        if (flowEntries == null || !flowEntries.iterator().hasNext()) {
            throw new ItemNotFoundException(DEVICE_NOT_FOUND);
        }
        for (FlowEntry entry : flowEntries) {
            flowsNode.add(codec(FlowEntry.class).encode(entry, this));
        }
        return ok(root).build();
    }

    /**
     * Gets flow rules. Returns the flow entry specified by the device id and
     * flow rule id.
     *
     * @param deviceId device identifier
     * @param flowId   flow rule identifier
     * @return 200 OK with a collection of flows of given device and flow
     * @onos.rsModel FlowEntries
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("{deviceId}/{flowId}")
    public Response getFlowByDeviceIdAndFlowId(@PathParam("deviceId") String deviceId,
                                               @PathParam("flowId") long flowId) {
        FlowRuleService service = get(FlowRuleService.class);
        ObjectNode root = mapper().createObjectNode();
        ArrayNode flowsNode = root.putArray(FLOWS);
        Iterable<FlowEntry> flowEntries =
                service.getFlowEntries(DeviceId.deviceId(deviceId));

        if (flowEntries == null || !flowEntries.iterator().hasNext()) {
            throw new ItemNotFoundException(DEVICE_NOT_FOUND);
        }
        for (FlowEntry entry : flowEntries) {
            if (entry.id().value() == flowId) {
                flowsNode.add(codec(FlowEntry.class).encode(entry, this));
            }
        }
        return ok(root).build();
    }

    /**
     * Gets flow rules generated by an application.
     * Returns the flow rule specified by the application id.
     *
     * @param appId application identifier
     * @return 200 OK with a collection of flows of given application id
     * @onos.rsModel FlowRules
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("application/{appId}")
    public Response getFlowByAppId(@PathParam("appId") String appId) {
        ObjectNode root = mapper().createObjectNode();
        ArrayNode flowsNode = root.putArray(FLOWS);
        ApplicationService appService = get(ApplicationService.class);
        ApplicationId idInstant = nullIsNotFound(appService.getId(appId), APP_ID_NOT_FOUND);
        Iterable<FlowEntry> flowEntries = get(FlowRuleService.class).getFlowEntriesById(idInstant);

        flowEntries.forEach(flow -> flowsNode.add(codec(FlowEntry.class).encode(flow, this)));
        return ok(root).build();
    }


    /**
     * Removes flow rules by application ID.
     * Removes a collection of flow rules generated by the given application.
     *
     * @param appId application identifier
     * @return 204 NO CONTENT
     */
    @DELETE
    @Produces(MediaType.APPLICATION_JSON)
    @Path("application/{appId}")
    public Response removeFlowByAppId(@PathParam("appId") String appId) {
        FlowRuleService service = get(FlowRuleService.class);
        ApplicationService appService = get(ApplicationService.class);
        ApplicationId idInstant = nullIsNotFound(appService.getId(appId), APP_ID_NOT_FOUND);
        service.removeFlowRulesById(idInstant);
        return Response.noContent().build();
    }

    /**
     * Creates new flow rule. Creates and installs a new flow rule for the
     * specified device. <br>
     * Flow rule criteria and instruction description:
     * https://wiki.onosproject.org/display/ONOS/Flow+Rules
     *
     * @param deviceId device identifier
     * @param appId    application identifier
     * @param stream   flow rule JSON
     * @return status of the request - CREATED if the JSON is correct,
     * BAD_REQUEST if the JSON is invalid
     * @onos.rsModel FlowsPost
     */
    @POST
    @Path("{deviceId}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response createFlow(@PathParam("deviceId") String deviceId,
                               @QueryParam("appId") String appId,
                               InputStream stream) {
        FlowRuleService service = get(FlowRuleService.class);
        try {
            ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
            JsonNode specifiedDeviceId = jsonTree.get("deviceId");
            if (specifiedDeviceId != null &&
                    !specifiedDeviceId.asText().equals(deviceId)) {
                throw new IllegalArgumentException(
                        "Invalid deviceId in flow creation request");
            }
            jsonTree.put("deviceId", deviceId);

            if (appId != null) {
                jsonTree.put("appId", appId);
            }

            FlowRule rule = codec(FlowRule.class).decode(jsonTree, this);
            service.applyFlowRules(rule);
            UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
                    .path("flows")
                    .path(deviceId)
                    .path(Long.toString(rule.id().value()));

            return Response
                    .created(locationBuilder.build())
                    .build();
        } catch (IOException ex) {
            throw new IllegalArgumentException(ex);
        }
    }

    /**
     * Removes flow rule. Removes the specified flow rule.
     *
     * @param deviceId device identifier
     * @param flowId   flow rule identifier
     * @return 204 NO CONTENT
     */
    @DELETE
    @Path("{deviceId}/{flowId}")
    public Response deleteFlowByDeviceIdAndFlowId(@PathParam("deviceId") String deviceId,
                                                  @PathParam("flowId") long flowId) {
        FlowRuleService service = get(FlowRuleService.class);
        Iterable<FlowEntry> flowEntries =
                service.getFlowEntries(DeviceId.deviceId(deviceId));

        if (!flowEntries.iterator().hasNext()) {
            throw new ItemNotFoundException(DEVICE_NOT_FOUND);
        }

        StreamSupport.stream(flowEntries.spliterator(), false)
                .filter(entry -> entry.id().value() == flowId)
                .forEach(service::removeFlowRules);
        return Response.noContent().build();
    }

    /**
     * Removes a batch of flow rules.
     *
     * @param stream stream for posted JSON
     * @return 204 NO CONTENT
     */
    @DELETE
    public Response deleteFlows(InputStream stream) {
        FlowRuleService service = get(FlowRuleService.class);
        ListMultimap<DeviceId, Long> deviceMap = ArrayListMultimap.create();
        List<FlowEntry> rulesToRemove = new ArrayList<>();

        try {
            ObjectNode jsonTree = readTreeFromStream(mapper(), stream);

            JsonNode jsonFlows = jsonTree.get("flows");

            jsonFlows.forEach(node -> {
                DeviceId deviceId =
                        DeviceId.deviceId(
                                nullIsNotFound(node.get(DEVICE_ID),
                                        DEVICE_NOT_FOUND).asText());
                long flowId = nullIsNotFound(node.get(FLOW_ID),
                        FLOW_NOT_FOUND).asLong();
                deviceMap.put(deviceId, flowId);

            });
        } catch (IOException ex) {
            throw new IllegalArgumentException(ex);
        }

        deviceMap.keySet().forEach(deviceId -> {
            List<Long> flowIds = deviceMap.get(deviceId);
            Iterable<FlowEntry> entries = service.getFlowEntries(deviceId);
            flowIds.forEach(flowId -> {
                StreamSupport.stream(entries.spliterator(), false)
                        .filter(entry -> flowId == entry.id().value())
                        .forEach(rulesToRemove::add);
            });
        });

        service.removeFlowRules(rulesToRemove.toArray(new FlowEntry[0]));
        return Response.noContent().build();
    }
}
