// 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 com.cloud.network.guru;

import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.InsufficientVirtualNetworkCapacityException;
import com.cloud.network.Network;
import com.cloud.network.NetworkProfile;
import com.cloud.network.Networks.TrafficType;
import com.cloud.offering.NetworkOffering;
import com.cloud.user.Account;
import com.cloud.utils.component.Adapter;
import com.cloud.vm.NicProfile;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.VirtualMachineProfile;

/**
 *   - Designs a virtual network depending on the network offering.
 *   - Implements the virtual network when a virtual machine requires the network to be started.
 *
 * There can be multiple NetworkGurus in a CloudStack system.  Each NetworkGuru
 * resources when VMs are gone.
 *
 * A Network goes through the following life cycles through the NetworkGuru.
 *   - When a guest network is created, NetworkGuru is asked to "design" the network.
 *     This means the NetworkGuru checks the parameters such as cidr, gateway,
 *     vlan, etc and returns a network that can work with those parameters.
 *     Note that at this point the network is only a virtual network.  It has
 *     not been substantiated with resources, such as vlan, to make the network
 *     functional in the physical environment.  At this stage, the network is in
 *     Allocated state.
 *
 *   - When the first virtual machine is about to be started and requires network
 *     services, the guest network needs to have resources to make it usable
 *     within the physical environment.  At this time, the NetworkGuru is
 *     called with the implement() method to acquire those resources.
 *
 *   - For every virtual machine starting in the network, the NetworkGuru is
 *     asked via the reserve() method to make sure everything the virtual
 *     machine needs to be functional in the network is reserved.
 *
 *   - For every virtual machine being stopped in the network, the NetworkGuru
 *     is informed via the release() method to make sure resources occupied
 *     by the virtual machine is released.
 *
 *   - If all virtual machines within the network have been stopped, the guest
 *     network is garbage collected.  When a guest network is garbage collected
 *     the NetworkGuru is informed via the shutdown() method to release any
 *     resources it allocated to that network.
 *
 *   - When a guest network is being deleted, the NetworkGuru is informed via
 *     the trash() method.
 *
 */
public interface NetworkGuru extends Adapter {
    /**
     * Cloud stack requires the NetworkGuru to design a guest network given
     * the software packages  Once a NetworkGuru returns the designed network,
     * that NetworkGuru is forever associated with the guest network.  It is
     * very important for the NetworkGuru implementation to be very specific
     * about the network it is responsible for designing.  Things that can
     * be used to make determination can be isolation methods, services
     * provided on the guest network and the service provider that's on the
     * guest network.
     * <p>
     * If a network is already fully substantiated with the necessary resources
     * during this design phase, then the state should be set to Setup.  If
     * the resources are not allocated at this point, the state should be set
     * to Allocated.
     *
     * @param offering      network offering that contains the package of services
     *                      the end user intends to use on that network.
     * @param plan          where is this network being deployed.
     * @param userSpecified user specified parameters for this network.
     * @param name
     * @param vpcId
     * @param owner         owner of this network.
     * @return Network
     */
    Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner);

    void setup(Network network, long networkId);

    /**
     * For guest networks that are in Allocated state after the design stage,
     * resources are allocated when the guest network is actually being used
     * by a virtual machine.  implement() is called to acquire those resources.
     *
     * @param network network to be implemented.
     * @param offering network offering that the network was created with.
     * @param destination where the network is being deployed in.
     * @return a fully implemented Network.
     * @throws InsufficientVirtualNetworkCapacityException  if there's not
     * enough resources to make the guest network usable in the physical
     * environment.  At this time, the admin generally must be involved to
     * allocate more resources before any more guest network can be implemented.
     */
    Network implement(Network network, NetworkOffering offering, DeployDestination destination, ReservationContext context)
        throws InsufficientVirtualNetworkCapacityException;

    /**
     * Once a guest network has been designed, virtual machines can be
     * created.  allocated() is called for the NetworkGuru to design a nic
     * that will make the virtual machine work within the guest network.
     *
     * @param network guest network that the virtual machine will be deployed in.
     * @param nic nic information that the end user wants to set.  The
     *            NetworkGuru should check this information with the guest
     *            network settings to make sure everything will work.
     * @param vm virtual machine that is about to be deployed.
     * @return NicProfile nic with all of the information
     * @throws InsufficientVirtualNetworkCapacityException if there's
     *         insufficient capacity within the guest network.
     * @throws InsufficientAddressCapacityException if there are not addresses
     *         to be assigned.
     */
    NicProfile allocate(Network network, NicProfile nic, VirtualMachineProfile vm) throws InsufficientVirtualNetworkCapacityException,
        InsufficientAddressCapacityException, ConcurrentOperationException;

    /**
     * Once a guest network is implemented, then the virtual machine must
     * be allocated its resources in order for it to participate within the
     * guest network.  reserve() is called for the NetworkGuru to make sure
     * that works.
     *
     * @param nic nic that the vm is using to access the guest network.
     * @param network guest network the vm is in.
     * @param vm vm
     * @param dest destination the vm is deployed to
     * @param context Reservation context from which to get the owner, caller, and reservation id
     * @throws InsufficientVirtualNetworkCapacityException if there's not enough
     *         resources.
     * @throws InsufficientAddressCapacityException if there's not enough ip
     *         addresses.
     * @throws ConcurrentOperationException if there are multiple operations
     *         happening on this guest network or vm.
     */
    void reserve(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context)
        throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException, ConcurrentOperationException;

    /**
     * When a virtual machine is stopped, the NetworkGuru is informed via the
     * release() method to release any resources.
     *
     * @param nic nic that the vm is using to access the guest network.
     * @param vm virtual machine
     * @param reservationId reservation id passed to it in the ReservationContext
     * @return true if release is successful or false if unsuccessful.
     */
    boolean release(NicProfile nic, VirtualMachineProfile vm, String reservationId);

    /**
     * When a virtual machine is destroyed, the NetworkGuru is informed via
     * the deallocate() method to make sure any resources that are allocated
     * are released.
     *
     * @param network guest network that the vm was running in.
     * @param nic nic that the vm was using to access the guest network.
     * @param vm virtual machine being destroyed.
     */
    void deallocate(Network network, NicProfile nic, VirtualMachineProfile vm);

    /**
     * @deprecated This method should not be here in the first place. What does this really mean? Is it always persisted
     *             in the nic? When is it persisted in the nic? When is it called? No Idea.
     * @param profile
     * @param network
     */
    @Deprecated
    void updateNicProfile(NicProfile profile, Network network);

    /**
     * When no virtual machines are running in the network, the network is
     * shutdown and all physical resources are released.  The NetworkGuru is
     * informed via the shutdown method().
     *
     * @param network guest network being shut down
     * @param offering network offering the guest network was created with.
     */
    void shutdown(NetworkProfile network, NetworkOffering offering);

    /**
     * When a guest network is destroyed, the NetworkGuru is informed via the
     * trash() method to recover any resources.
     *
     * @param network guest network being destroyed.
     * @param offering network offering the guest network was created with.
     * @return true if trash was successful; false if not.
     */
    boolean trash(Network network, NetworkOffering offering);

    void updateNetworkProfile(NetworkProfile networkProfile);

    TrafficType[] getSupportedTrafficType();

    boolean isMyTrafficType(TrafficType type);

    default boolean isSlaacV6Only() {
        return true;
    }

    default boolean update(Network network, String prevNetworkName) {
        return true;
    }
}
