/*
 * 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.grouphandler;

import static org.slf4j.LoggerFactory.getLogger;

import java.util.ArrayList;
import java.util.Arrays;
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.core.GroupId;
import org.onosproject.grouphandler.GroupBucketIdentifier.BucketOutputType;
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.group.DefaultGroupBucket;
import org.onosproject.net.group.DefaultGroupDescription;
import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.group.GroupBuckets;
import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.group.GroupEvent;
import org.onosproject.net.group.GroupKey;
import org.onosproject.net.group.GroupService;
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<GroupKey, GroupKey> dependentGroups =
            new HashMap<GroupKey, GroupKey>();

    /**
     * Creates policy group handler object.
     *
     * @param deviceId device identifier
     * @param appId application identifier
     * @param config interface to retrieve the device properties
     * @param linkService link service object
     * @param groupService group service object
     * @return policy group handler type
     */
    public PolicyGroupHandler(DeviceId deviceId,
                              ApplicationId appId,
                              DeviceProperties config,
                              LinkService linkService,
                              GroupService groupService) {
        super(deviceId, appId, config, linkService, groupService);
    }

    public PolicyGroupIdentifier createPolicyGroupChain(String id,
                                                        List<PolicyGroupParams> params) {
        List<GroupBucketIdentifier> bucketIds = new ArrayList<GroupBucketIdentifier>();
        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).intValue();
                        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<GroupBucket>();
                            GroupBucketIdentifier bucketId =
                                    new GroupBucketIdentifier(label, sp);
                            PolicyGroupIdentifier key = new
                                    PolicyGroupIdentifier(id,
                                                          Arrays.asList(param),
                                                          Arrays.asList(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);
                        } else {
                            // Intermediate Groups
                            GroupBucketIdentifier bucketId =
                                    new GroupBucketIdentifier(label,
                                                              previousGroupkey);
                            PolicyGroupIdentifier key = new
                                    PolicyGroupIdentifier(id,
                                                          Arrays.asList(param),
                                                          Arrays.asList(bucketId));
                            // Add to group dependency list
                            dependentGroups.put(previousGroupkey, key);
                            previousGroupkey = key;
                        }
                    }
                }
            } else {
                int label = -1;
                if (labelStackSize == 1) {
                    label = param.getLabelStack().get(0).intValue();
                }
                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<GroupBucket>();
                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)
                            .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);
            }
        }
        return innermostGroupkey;
    }

    @Override
    protected void handleGroupEvent(GroupEvent event) {
        if (event.type() == GroupEvent.Type.GROUP_ADDED) {
            if (dependentGroups.get(event.subject().appCookie()) != null) {
                PolicyGroupIdentifier dependentGroupKey = (PolicyGroupIdentifier)
                        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();
                        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,
                                             bucketId.outGroup()) == null) {
                                throw new IllegalStateException();
                            }
                            GroupId indirectGroupId = groupService.
                                    getGroup(deviceId,
                                             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 GroupKey generatePolicyGroupKey(String id,
                                   List<PolicyGroupParams> params) {
        List<GroupBucketIdentifier> bucketIds = new ArrayList<GroupBucketIdentifier>();
        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).intValue();
                        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,
                                                          Arrays.asList(param),
                                                          Arrays.asList(bucketId));
                            previousGroupkey = key;
                        } else {
                            // Intermediate Groups
                            GroupBucketIdentifier bucketId =
                                    new GroupBucketIdentifier(label,
                                                              previousGroupkey);
                            PolicyGroupIdentifier key = new
                                    PolicyGroupIdentifier(id,
                                                          Arrays.asList(param),
                                                          Arrays.asList(bucketId));
                            previousGroupkey = key;
                        }
                    }
                }
            } else {
                int label = -1;
                if (labelStackSize == 1) {
                    label = param.getLabelStack().get(0).intValue();
                }
                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(GroupKey key) {
        if (!(key instanceof PolicyGroupIdentifier)) {
            throw new IllegalArgumentException();
        }
        List<GroupKey> groupsToBeDeleted = new ArrayList<GroupKey>();
        groupsToBeDeleted.add(key);

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

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

}