/*
 * Copyright 2015 Open Networking Laboratory
 *
 * 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.segmentrouting.grouphandler;

import static com.google.common.base.Preconditions.checkArgument;
import static org.slf4j.LoggerFactory.getLogger;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.onlab.packet.MplsLabel;
import org.onosproject.core.ApplicationId;
import org.onosproject.segmentrouting.grouphandler.GroupBucketIdentifier.BucketOutputType;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.link.LinkService;
import org.slf4j.Logger;

/**
 * A module to create group chains based on the specified device
 * ports and label stack to be applied on each port.
 */
public class PolicyGroupHandler extends DefaultGroupHandler {

    private final Logger log = getLogger(getClass());
    private HashMap<PolicyGroupIdentifier, PolicyGroupIdentifier> dependentGroups = new HashMap<>();

    /**
     * Policy group handler constructor.
     *
     * @param deviceId device identifier
     * @param appId application identifier
     * @param config interface to retrieve the device properties
     * @param linkService link service object
     * @param flowObjService flow objective service object
     * @param nsNextObjStore next objective store map
     */
    public PolicyGroupHandler(DeviceId deviceId,
                              ApplicationId appId,
                              DeviceProperties config,
                              LinkService linkService,
                              FlowObjectiveService flowObjService,
                              EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
                                      Integer> nsNextObjStore) {
        super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
    }

    public PolicyGroupIdentifier createPolicyGroupChain(String id,
                                                        List<PolicyGroupParams> params) {
        List<GroupBucketIdentifier> bucketIds = new ArrayList<>();
        for (PolicyGroupParams param: params) {
            List<PortNumber> ports = param.getPorts();
            if (ports == null) {
                log.warn("createPolicyGroupChain in sw {} with wrong "
                        + "input parameters", deviceId);
                return null;
            }

            int labelStackSize = (param.getLabelStack() != null) ?
                                      param.getLabelStack().size() : 0;

            if (labelStackSize > 1) {
                for (PortNumber sp : ports) {
                    PolicyGroupIdentifier previousGroupkey = null;
                    DeviceId neighbor = portDeviceMap.get(sp);
                    for (int idx = 0; idx < param.getLabelStack().size(); idx++) {
                        int label = param.getLabelStack().get(idx);
                        if (idx == (labelStackSize - 1)) {
                            // Innermost Group
                            GroupBucketIdentifier bucketId =
                                    new GroupBucketIdentifier(label,
                                                              previousGroupkey);
                            bucketIds.add(bucketId);
                        } else if (idx == 0) {
                            // Outermost Group
                            List<GroupBucket> outBuckets = new ArrayList<>();
                            GroupBucketIdentifier bucketId =
                                    new GroupBucketIdentifier(label, sp);
                            PolicyGroupIdentifier key = new
                                    PolicyGroupIdentifier(id,
                                                          Collections.singletonList(param),
                                                          Collections.singletonList(bucketId));
                            TrafficTreatment.Builder tBuilder =
                                    DefaultTrafficTreatment.builder();
                            tBuilder.setOutput(sp)
                                    .setEthDst(deviceConfig.
                                               getDeviceMac(neighbor))
                                    .setEthSrc(nodeMacAddr)
                                    .pushMpls()
                                    .setMpls(MplsLabel.mplsLabel(label));
                            /*outBuckets.add(DefaultGroupBucket.
                                           createSelectGroupBucket(tBuilder.build()));
                            GroupDescription desc = new
                                    DefaultGroupDescription(deviceId,
                                                            GroupDescription.Type.INDIRECT,
                                                            new GroupBuckets(outBuckets));
                            //TODO: BoS*/
                            previousGroupkey = key;
                            //groupService.addGroup(desc);
                            //TODO: Use nextObjective APIs here
                        } else {
                            // Intermediate Groups
                            GroupBucketIdentifier bucketId =
                                    new GroupBucketIdentifier(label,
                                                              previousGroupkey);
                            PolicyGroupIdentifier key = new
                                    PolicyGroupIdentifier(id,
                                                          Collections.singletonList(param),
                                                          Collections.singletonList(bucketId));
                            // Add to group dependency list
                            dependentGroups.put(previousGroupkey, key);
                            previousGroupkey = key;
                        }
                    }
                }
            } else {
                int label = -1;
                if (labelStackSize == 1) {
                    label = param.getLabelStack().get(0);
                }
                for (PortNumber sp : ports) {
                    GroupBucketIdentifier bucketId =
                            new GroupBucketIdentifier(label, sp);
                    bucketIds.add(bucketId);
                }
            }
        }
        PolicyGroupIdentifier innermostGroupkey = null;
        if (!bucketIds.isEmpty()) {
            innermostGroupkey = new
                    PolicyGroupIdentifier(id,
                                          params,
                                          bucketIds);
            // Add to group dependency list
            boolean fullyResolved = true;
            for (GroupBucketIdentifier bucketId:bucketIds) {
                if (bucketId.type() == BucketOutputType.GROUP) {
                    dependentGroups.put(bucketId.outGroup(),
                                        innermostGroupkey);
                    fullyResolved = false;
                }
            }

            if (fullyResolved) {
                List<GroupBucket> outBuckets = new ArrayList<>();
                for (GroupBucketIdentifier bucketId:bucketIds) {
                    DeviceId neighbor = portDeviceMap.
                            get(bucketId.outPort());
                    TrafficTreatment.Builder tBuilder =
                            DefaultTrafficTreatment.builder();
                    tBuilder.setOutput(bucketId.outPort())
                            .setEthDst(deviceConfig.
                                       getDeviceMac(neighbor))
                            .setEthSrc(nodeMacAddr);
                    if (bucketId.label() != NeighborSet.NO_EDGE_LABEL) {
                        tBuilder.pushMpls()
                            .setMpls(MplsLabel.mplsLabel(bucketId.label()));
                    }
                    //TODO: BoS
                    /*outBuckets.add(DefaultGroupBucket.
                                   createSelectGroupBucket(tBuilder.build()));*/
                }
                /*GroupDescription desc = new
                        DefaultGroupDescription(deviceId,
                                                GroupDescription.Type.SELECT,
                                                new GroupBuckets(outBuckets));
                groupService.addGroup(desc);*/
                //TODO: Use nextObjective APIs here
            }
        }
        return innermostGroupkey;
    }

    //TODO: Use nextObjective APIs to handle the group chains
    /*@Override
    protected void handleGroupEvent(GroupEvent event) {
        if (event.type() == GroupEvent.Type.GROUP_ADDED) {
            if (dependentGroups.get(event.subject().appCookie()) != null) {
                PolicyGroupIdentifier dependentGroupKey = dependentGroups.get(event.subject().appCookie());
                dependentGroups.remove(event.subject().appCookie());
                boolean fullyResolved = true;
                for (GroupBucketIdentifier bucketId:
                            dependentGroupKey.bucketIds()) {
                    if (bucketId.type() != BucketOutputType.GROUP) {
                        continue;
                    }
                    if (dependentGroups.containsKey(bucketId.outGroup())) {
                        fullyResolved = false;
                        break;
                    }
                }

                if (fullyResolved) {
                    List<GroupBucket> outBuckets = new ArrayList<GroupBucket>();
                    for (GroupBucketIdentifier bucketId:
                                dependentGroupKey.bucketIds()) {
                        TrafficTreatment.Builder tBuilder =
                                DefaultTrafficTreatment.builder();
                        if (bucketId.label() != NeighborSet.NO_EDGE_LABEL) {
                            tBuilder.pushMpls()
                                    .setMpls(MplsLabel.
                                             mplsLabel(bucketId.label()));
                        }
                        //TODO: BoS
                        if (bucketId.type() == BucketOutputType.PORT) {
                            DeviceId neighbor = portDeviceMap.
                                        get(bucketId.outPort());
                            tBuilder.setOutput(bucketId.outPort())
                                    .setEthDst(deviceConfig.
                                               getDeviceMac(neighbor))
                                     .setEthSrc(nodeMacAddr);
                        } else {
                            if (groupService.
                                    getGroup(deviceId,
                                             getGroupKey(bucketId.
                                                       outGroup())) == null) {
                                throw new IllegalStateException();
                            }
                            GroupId indirectGroupId = groupService.
                                    getGroup(deviceId,
                                             getGroupKey(bucketId.
                                                         outGroup())).id();
                            tBuilder.group(indirectGroupId);
                        }
                        outBuckets.add(DefaultGroupBucket.
                                       createSelectGroupBucket(tBuilder.build()));
                    }
                    GroupDescription desc = new
                            DefaultGroupDescription(deviceId,
                                                    GroupDescription.Type.SELECT,
                                                    new GroupBuckets(outBuckets));
                    groupService.addGroup(desc);
                }
            }
        }
    }*/

    public PolicyGroupIdentifier generatePolicyGroupKey(String id,
                                   List<PolicyGroupParams> params) {
        List<GroupBucketIdentifier> bucketIds = new ArrayList<>();
        for (PolicyGroupParams param: params) {
            List<PortNumber> ports = param.getPorts();
            if (ports == null) {
                log.warn("generateGroupKey in sw {} with wrong "
                        + "input parameters", deviceId);
                return null;
            }

            int labelStackSize = (param.getLabelStack() != null)
                    ? param.getLabelStack().size() : 0;

            if (labelStackSize > 1) {
                for (PortNumber sp : ports) {
                    PolicyGroupIdentifier previousGroupkey = null;
                    for (int idx = 0; idx < param.getLabelStack().size(); idx++) {
                        int label = param.getLabelStack().get(idx);
                        if (idx == (labelStackSize - 1)) {
                            // Innermost Group
                            GroupBucketIdentifier bucketId =
                                    new GroupBucketIdentifier(label,
                                                              previousGroupkey);
                            bucketIds.add(bucketId);
                        } else if (idx == 0) {
                            // Outermost Group
                            GroupBucketIdentifier bucketId =
                                    new GroupBucketIdentifier(label, sp);
                            PolicyGroupIdentifier key = new
                                    PolicyGroupIdentifier(id,
                                                          Collections.singletonList(param),
                                                          Collections.singletonList(bucketId));
                            previousGroupkey = key;
                        } else {
                            // Intermediate Groups
                            GroupBucketIdentifier bucketId =
                                    new GroupBucketIdentifier(label,
                                                              previousGroupkey);
                            PolicyGroupIdentifier key = new
                                    PolicyGroupIdentifier(id,
                                                          Collections.singletonList(param),
                                                          Collections.singletonList(bucketId));
                            previousGroupkey = key;
                        }
                    }
                }
            } else {
                int label = -1;
                if (labelStackSize == 1) {
                    label = param.getLabelStack().get(0);
                }
                for (PortNumber sp : ports) {
                    GroupBucketIdentifier bucketId =
                            new GroupBucketIdentifier(label, sp);
                    bucketIds.add(bucketId);
                }
            }
        }
        PolicyGroupIdentifier innermostGroupkey = null;
        if (!bucketIds.isEmpty()) {
            innermostGroupkey = new
                    PolicyGroupIdentifier(id,
                                          params,
                                          bucketIds);
        }
        return innermostGroupkey;
    }

    public void removeGroupChain(PolicyGroupIdentifier key) {
        checkArgument(key != null);
        List<PolicyGroupIdentifier> groupsToBeDeleted = new ArrayList<>();
        groupsToBeDeleted.add(key);

        Iterator<PolicyGroupIdentifier> it =
                groupsToBeDeleted.iterator();

        while (it.hasNext()) {
            PolicyGroupIdentifier innerMostGroupKey = it.next();
            for (GroupBucketIdentifier bucketId:
                        innerMostGroupKey.bucketIds()) {
                if (bucketId.type() != BucketOutputType.GROUP) {
                    groupsToBeDeleted.add(bucketId.outGroup());
                }
            }
            /*groupService.removeGroup(deviceId,
                                     getGroupKey(innerMostGroupKey),
                                     appId);*/
            //TODO: Use nextObjective APIs here
            it.remove();
        }
    }

}
