/**
 * *  Copyright (C) 2011 Citrix Systems, Inc.  All rights reserved
*
 *
 * This software is licensed under the GNU General Public License v3 or later.
 *
 * It is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package com.cloud.network.element;

import java.util.HashMap;
import java.util.Map;

import javax.ejb.Local;

import org.apache.log4j.Logger;

import com.cloud.baremetal.ExternalDhcpManager;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.dc.Pod;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.host.Host;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.Network;
import com.cloud.network.Network.Capability;
import com.cloud.network.Network.GuestType;
import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.PhysicalNetworkServiceProvider;
import com.cloud.offering.NetworkOffering;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.component.Inject;
import com.cloud.vm.NicProfile;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;

@Local(value=NetworkElement.class)
public class ExternalDhcpElement extends AdapterBase implements NetworkElement {
	private static final Logger s_logger = Logger.getLogger(ExternalDhcpElement.class);
	@Inject ExternalDhcpManager _dhcpMgr;
	private static final Map<Service, Map<Capability, String>> capabilities = setCapabilities();
	
	private boolean canHandle(DeployDestination dest, TrafficType trafficType, GuestType networkType) {
		DataCenter dc = dest.getDataCenter();
		Pod pod = dest.getPod();
		
		if ((pod != null && pod.getExternalDhcp()) && dc.getNetworkType() == NetworkType.Basic && trafficType == TrafficType.Guest
				&& networkType == Network.GuestType.Shared) {
			s_logger.debug("External DHCP can handle");
			return true;
		}

		return false;
	}

    private static Map<Service, Map<Capability, String>> setCapabilities() {
        Map<Service, Map<Capability, String>> capabilities = new HashMap<Service, Map<Capability, String>>();
        capabilities.put(Service.Dhcp, null);
        return capabilities;
    }
    
	@Override
	public Map<Service, Map<Capability, String>> getCapabilities() {
		return capabilities;
	}

	@Override
	public Provider getProvider() {
		return Provider.ExternalDhcpServer;
	}

	@Override
	public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context)
			throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
		if (!canHandle(dest, offering.getTrafficType(), network.getGuestType())) {
			return false;
		}
		return true;
	}

	@Override
	public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest,
			ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
		Host host = dest.getHost();
		if (host.getHypervisorType() == HypervisorType.BareMetal || !canHandle(dest, network.getTrafficType(), network.getGuestType())) {
			//BareMetalElement or DhcpElement handle this
			return false;
		}
		
		return _dhcpMgr.addVirtualMachineIntoNetwork(network, nic, vm, dest, context);
	}

	@Override
	public boolean release(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, ReservationContext context)
			throws ConcurrentOperationException, ResourceUnavailableException {
		return true;
	}

	@Override
	public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException {
		return true;
	}
	
	
	@Override
	public boolean destroy(Network network) throws ConcurrentOperationException, ResourceUnavailableException {
		return true;
	}

    @Override
    public boolean isReady(PhysicalNetworkServiceProvider provider) {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public boolean canEnableIndividualServices() {
        return false;
    }
}

@@ -2069,19 +2069,40 @@
 kElement
+, DhcpServiceProvider
  %7B%0A
-
 %09private
@@ -3840,321 +3840,23 @@
  %7B%0A%09
-%09Host host = dest.getHost();%0A%09%09if (host.getHypervisorType() == HypervisorType.BareMetal %7C%7C !canHandle(dest, network.getTrafficType(), network.getGuestType())) %7B%0A%09%09%09//BareMetalElement or DhcpElement handle this%0A%09%09%09return false;%0A%09%09%7D%0A%09%09%0A%09%09return _dhcpMgr.addVirtualMachineIntoNetwork(network, nic, vm, dest, context)
+    return true
 ;%0A%09%7D
@@ -4905,24 +4905,24 @@
 ervices() %7B%0A
-
         retu
@@ -4936,11 +4936,667 @@
 e;%0A    %7D
+%0A%0A    @Override%0A    public boolean addDhcpEntry(Network network, NicProfile nic, VirtualMachineProfile%3C? extends VirtualMachine%3E vm, DeployDestination dest, ReservationContext context)%0A            throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException %7B%0A        Host host = dest.getHost();%0A        if (host.getHypervisorType() == HypervisorType.BareMetal %7C%7C !canHandle(dest, network.getTrafficType(), network.getGuestType())) %7B%0A            //BareMetalElement or DhcpElement handle this%0A            return false;%0A        %7D%0A        return _dhcpMgr.addVirtualMachineIntoNetwork(network, nic, vm, dest, context);%0A    %7D
 %0A%7D%0A

Make ExternalDhcpElement implements DhcpServiceProvider