// 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.ovm.hypervisor;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.naming.ConfigurationException;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.xmlrpc.XmlRpcException;

import com.trilead.ssh2.SCPClient;

import org.apache.cloudstack.storage.to.TemplateObjectTO;
import org.apache.cloudstack.storage.to.VolumeObjectTO;

import com.cloud.agent.IAgentControl;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.AttachIsoCommand;
import com.cloud.agent.api.CheckNetworkAnswer;
import com.cloud.agent.api.CheckNetworkCommand;
import com.cloud.agent.api.CheckVirtualMachineAnswer;
import com.cloud.agent.api.CheckVirtualMachineCommand;
import com.cloud.agent.api.CleanupNetworkRulesCmd;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
import com.cloud.agent.api.CreateStoragePoolCommand;
import com.cloud.agent.api.DeleteStoragePoolCommand;
import com.cloud.agent.api.FenceAnswer;
import com.cloud.agent.api.FenceCommand;
import com.cloud.agent.api.GetHostStatsAnswer;
import com.cloud.agent.api.GetHostStatsCommand;
import com.cloud.agent.api.GetStorageStatsAnswer;
import com.cloud.agent.api.GetStorageStatsCommand;
import com.cloud.agent.api.GetVmStatsAnswer;
import com.cloud.agent.api.GetVmStatsCommand;
import com.cloud.agent.api.GetVncPortAnswer;
import com.cloud.agent.api.GetVncPortCommand;
import com.cloud.agent.api.HostStatsEntry;
import com.cloud.agent.api.HostVmStateReportEntry;
import com.cloud.agent.api.MaintainAnswer;
import com.cloud.agent.api.MaintainCommand;
import com.cloud.agent.api.MigrateAnswer;
import com.cloud.agent.api.MigrateCommand;
import com.cloud.agent.api.ModifyStoragePoolAnswer;
import com.cloud.agent.api.ModifyStoragePoolCommand;
import com.cloud.agent.api.PingCommand;
import com.cloud.agent.api.PingRoutingCommand;
import com.cloud.agent.api.PingTestCommand;
import com.cloud.agent.api.PrepareForMigrationAnswer;
import com.cloud.agent.api.PrepareForMigrationCommand;
import com.cloud.agent.api.PrepareOCFS2NodesCommand;
import com.cloud.agent.api.ReadyAnswer;
import com.cloud.agent.api.ReadyCommand;
import com.cloud.agent.api.RebootAnswer;
import com.cloud.agent.api.RebootCommand;
import com.cloud.agent.api.SecurityGroupRuleAnswer;
import com.cloud.agent.api.SecurityGroupRulesCmd;
import com.cloud.agent.api.StartAnswer;
import com.cloud.agent.api.StartCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand;
import com.cloud.agent.api.VmStatsEntry;
import com.cloud.agent.api.storage.CopyVolumeAnswer;
import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.CreateAnswer;
import com.cloud.agent.api.storage.CreateCommand;
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
import com.cloud.agent.api.storage.DestroyCommand;
import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.agent.api.to.DataTO;
import com.cloud.agent.api.to.DiskTO;
import com.cloud.agent.api.to.NfsTO;
import com.cloud.agent.api.to.NicTO;
import com.cloud.agent.api.to.StorageFilerTO;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.agent.api.to.VolumeTO;
import com.cloud.host.Host.Type;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.PhysicalNetworkSetupInfo;
import com.cloud.ovm.object.Connection;
import com.cloud.ovm.object.OvmBridge;
import com.cloud.ovm.object.OvmDisk;
import com.cloud.ovm.object.OvmHost;
import com.cloud.ovm.object.OvmSecurityGroup;
import com.cloud.ovm.object.OvmStoragePool;
import com.cloud.ovm.object.OvmVif;
import com.cloud.ovm.object.OvmVlan;
import com.cloud.ovm.object.OvmVm;
import com.cloud.ovm.object.OvmVolume;
import com.cloud.resource.ServerResource;
import com.cloud.resource.hypervisor.HypervisorResource;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.Volume;
import com.cloud.storage.template.TemplateProp;
import com.cloud.template.VirtualMachineTemplate.BootloaderType;
import com.cloud.utils.Pair;
import com.cloud.utils.Ternary;
import com.cloud.utils.UuidUtils;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
import com.cloud.utils.ssh.SSHCmdHelper;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.PowerState;

public class OvmResourceBase implements ServerResource, HypervisorResource {
    protected Logger logger = LogManager.getLogger(getClass());
    String _name;
    Long _zoneId;
    Long _podId;
    Long _clusterId;
    String _ip;
    String _username;
    String _password;
    String _guid;
    String _agentUserName = "oracle";
    String _agentPassword;
    Connection _conn;
    String _privateNetworkName;
    String _publicNetworkName;
    String _guestNetworkName;
    boolean _canBridgeFirewall;
    static boolean s_isHeartBeat = false;
    List<String> _bridges = null;
    private final Map<String, Pair<Long, Long>> _vmNetworkStats = new ConcurrentHashMap<String, Pair<Long, Long>>();
    private static String s_ovsAgentPath = "/opt/ovs-agent-latest";


    static HashMap<String, PowerState> s_powerStateMaps;
    static {
        s_powerStateMaps = new HashMap<String, PowerState>();
        s_powerStateMaps.put("RUNNING", PowerState.PowerOn);
        s_powerStateMaps.put("DOWN", PowerState.PowerOff);
        s_powerStateMaps.put("ERROR", PowerState.PowerUnknown);
        s_powerStateMaps.put("SUSPEND", PowerState.PowerOff);
    }

    @Override
    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
        _name = name;

        try {
            _zoneId = Long.parseLong((String)params.get("zone"));
            _podId = Long.parseLong((String)params.get("pod"));
            _clusterId = Long.parseLong((String)params.get("cluster"));
            _ip = (String)params.get("ip");
            _username = (String)params.get("username");
            _password = (String)params.get("password");
            _guid = (String)params.get("guid");
            _privateNetworkName = (String)params.get("private.network.device");
            _publicNetworkName = (String)params.get("public.network.device");
            _guestNetworkName = (String)params.get("guest.network.device");
            _agentUserName = (String)params.get("agentusername");
            _agentPassword = (String)params.get("agentpassword");
        } catch (Exception e) {
            logger.debug("Configure " + _name + " failed", e);
            throw new ConfigurationException("Configure " + _name + " failed, " + e.toString());
        }

        if (_podId == null) {
            throw new ConfigurationException("Unable to get the pod");
        }

        if (_ip == null) {
            throw new ConfigurationException("Unable to get the host address");
        }

        if (_username == null) {
            throw new ConfigurationException("Unable to get the username");
        }

        if (_password == null) {
            throw new ConfigurationException("Unable to get the password");
        }

        if (_guid == null) {
            throw new ConfigurationException("Unable to get the guid");
        }

        if (_agentUserName == null) {
            throw new ConfigurationException("Unable to get agent user name");
        }

        if (_agentPassword == null) {
            throw new ConfigurationException("Unable to get agent password");
        }

        try {
            setupServer();
        } catch (Exception e) {
            logger.debug("Setup server failed, ip " + _ip, e);
            throw new ConfigurationException("Unable to setup server");
        }

        _conn = new Connection(_ip, _agentUserName, _agentPassword);
        try {
            OvmHost.registerAsPrimary(_conn);
            OvmHost.registerAsVmServer(_conn);
            _bridges = OvmBridge.getAllBridges(_conn);
        } catch (XmlRpcException e) {
            logger.debug("Get bridges failed", e);
            throw new ConfigurationException("Cannot get bridges on host " + _ip + "," + e.getMessage());
        }

        if (_privateNetworkName != null && !_bridges.contains(_privateNetworkName)) {
            throw new ConfigurationException("Cannot find bridge " + _privateNetworkName + " on host " + _ip + ", all bridges are:" + _bridges);
        }

        if (_publicNetworkName != null && !_bridges.contains(_publicNetworkName)) {
            throw new ConfigurationException("Cannot find bridge " + _publicNetworkName + " on host " + _ip + ", all bridges are:" + _bridges);
        }

        if (_guestNetworkName != null && !_bridges.contains(_guestNetworkName)) {
            throw new ConfigurationException("Cannot find bridge " + _guestNetworkName + " on host " + _ip + ", all bridges are:" + _bridges);
        }

        /* set to false so each time ModifyStoragePoolCommand will re-setup heartbeat*/
        s_isHeartBeat = false;

        /*
        try {
            _canBridgeFirewall = canBridgeFirewall();
        } catch (XmlRpcException e) {
            logger.error("Failed to detect whether the host supports security groups.", e);
            _canBridgeFirewall = false;
        }
        */

        _canBridgeFirewall = false;

        logger.debug("OVM host doesn't support security groups.");

        return true;
    }

    @Override
    public boolean start() {
        return true;
    }

    @Override
    public boolean stop() {
        return true;
    }

    @Override
    public String getName() {
        return _name;
    }

    @Override
    public Type getType() {
        return Type.Routing;
    }

    protected void fillHostInfo(StartupRoutingCommand cmd) {
        try {
            OvmHost.Details hostDetails = OvmHost.getDetails(_conn);

            cmd.setName(hostDetails.name);
            cmd.setSpeed(hostDetails.cpuSpeed);
            cmd.setCpus(hostDetails.cpuNum);
            cmd.setMemory(hostDetails.freeMemory);
            cmd.setDom0MinMemory(hostDetails.dom0Memory);
            cmd.setGuid(_guid);
            cmd.setDataCenter(_zoneId.toString());
            cmd.setPod(_podId.toString());
            cmd.setCluster(_clusterId.toString());
            cmd.setVersion(OvmResourceBase.class.getPackage().getImplementationVersion());
            cmd.setHypervisorType(HypervisorType.Ovm);
            //TODO: introudce PIF
            cmd.setPrivateIpAddress(_ip);
            cmd.setStorageIpAddress(_ip);

            String defaultBridge = OvmBridge.getBridgeByIp(_conn, _ip);
            if (_publicNetworkName == null) {
                _publicNetworkName = defaultBridge;
            }
            if (_privateNetworkName == null) {
                _privateNetworkName = _publicNetworkName;
            }
            if (_guestNetworkName == null) {
                _guestNetworkName = _privateNetworkName;
            }
            Map<String, String> d = cmd.getHostDetails();
            d.put("public.network.device", _publicNetworkName);
            d.put("private.network.device", _privateNetworkName);
            d.put("guest.network.device", _guestNetworkName);
            cmd.setHostDetails(d);

            logger.debug(String.format("Add a OVM host(%s)", hostDetails.toJson()));
        } catch (XmlRpcException e) {
            logger.debug("XML RPC Exception" + e.getMessage(), e);
            throw new CloudRuntimeException("XML RPC Exception" + e.getMessage(), e);
        }
    }

    protected void setupServer() throws IOException {
        com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22);
        sshConnection.connect(null, 60000, 60000);
        if (!sshConnection.authenticateWithPassword(_username, _password)) {
            throw new CloudRuntimeException("Unable to authenticate");
        }
        SCPClient scp = new SCPClient(sshConnection);

        String configScriptName = "scripts/vm/hypervisor/ovm/configureOvm.sh";
        String configScriptPath = Script.findScript("", configScriptName);
        if (configScriptPath == null) {
            throw new CloudRuntimeException("Unable to find " + configScriptName);
        }
        scp.put(configScriptPath, "/usr/bin/", "0755");

        if (!SSHCmdHelper.sshExecuteCmd(sshConnection, "sh /usr/bin/configureOvm.sh preSetup")) {
            throw new CloudRuntimeException("Execute configureOvm.sh preSetup failed on " + _ip);
        }

        File tmp = new File(configScriptPath);
        File scriptDir = new File(tmp.getParent());
        File[] scripts = scriptDir.listFiles();
        for (int i = 0; i < scripts.length; i++) {
            File script = scripts[i];
            if (script.getName().equals("configureOvm.sh")) {
                continue;
            }

            if (logger.isDebugEnabled()) {
                logger.debug("Copying " + script.getPath() + " to " + s_ovsAgentPath + " on " + _ip + " with permission 0644");
            }
            scp.put(script.getPath(), s_ovsAgentPath, "0644");
        }

        sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password);
        if (sshConnection == null) {
            throw new CloudRuntimeException(String.format("Cannot connect to ovm host(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, _password));
        }

        if (!SSHCmdHelper.sshExecuteCmd(sshConnection, "sh /usr/bin/configureOvm.sh postSetup")) {
            throw new CloudRuntimeException("Execute configureOvm.sh postSetup failed on " + _ip);
        }

    }

    @Override
    public StartupCommand[] initialize() {
        try {
            StartupRoutingCommand cmd = new StartupRoutingCommand();
            fillHostInfo(cmd);
            cmd.setCaps("hvm");
            return new StartupCommand[] {cmd};
        } catch (Exception e) {
            logger.debug("Ovm resource initializes failed", e);
            return null;
        }
    }

    @Override
    public PingCommand getCurrentStatus(long id) {
        try {
            OvmHost.ping(_conn);
            return new PingRoutingCommand(getType(), id, getHostVmStateReport());
        } catch (XmlRpcException e) {
            logger.debug("Check agent status failed", e);
            return null;
        }
    }

    protected ReadyAnswer execute(ReadyCommand cmd) {
        try {
            OvmHost.Details d = OvmHost.getDetails(_conn);
            //TODO: cleanup halted vm
            if (d.primaryIp.equalsIgnoreCase(_ip)) {
                return new ReadyAnswer(cmd);
            } else {
                logger.debug("Primary IP changes to " + d.primaryIp + ", it should be " + _ip);
                return new ReadyAnswer(cmd, "I am not the primary server");
            }
        } catch (XmlRpcException e) {
            logger.debug("XML RPC Exception" + e.getMessage(), e);
            throw new CloudRuntimeException("XML RPC Exception" + e.getMessage(), e);
        }

    }

    protected void createNfsSr(StorageFilerTO pool) throws XmlRpcException {
        String mountPoint = String.format("%1$s:%2$s", pool.getHost(), pool.getPath());
        OvmStoragePool.Details d = new OvmStoragePool.Details();
        d.path = mountPoint;
        d.type = OvmStoragePool.NFS;
        d.uuid = pool.getUuid();
        OvmStoragePool.create(_conn, d);
        logger.debug(String.format("Created SR (mount point:%1$s)", mountPoint));
    }

    protected void createOCFS2Sr(StorageFilerTO pool) throws XmlRpcException {
        OvmStoragePool.Details d = new OvmStoragePool.Details();
        d.path = pool.getPath();
        d.type = OvmStoragePool.OCFS2;
        d.uuid = pool.getUuid();
        OvmStoragePool.create(_conn, d);
        logger.debug(String.format("Created SR (mount point:%1$s)", d.path));
    }

    private void setupHeartBeat(String poolUuid) {
        try {
            if (!s_isHeartBeat) {
                OvmHost.setupHeartBeat(_conn, poolUuid, _ip);
                s_isHeartBeat = true;
            }
        } catch (Exception e) {
            logger.debug("setup heart beat for " + _ip + " failed", e);
            s_isHeartBeat = false;
        }
    }

    protected Answer execute(ModifyStoragePoolCommand cmd) {
        StorageFilerTO pool = cmd.getPool();
        try {
            if (pool.getType() == StoragePoolType.NetworkFilesystem) {
                createNfsSr(pool);
            } else if (pool.getType() == StoragePoolType.OCFS2) {
                createOCFS2Sr(pool);
            } else {
                return new Answer(cmd, false, "The pool type: " + pool.getType().name() + " is not supported.");
            }

            setupHeartBeat(pool.getUuid());
            OvmStoragePool.Details d = OvmStoragePool.getDetailsByUuid(_conn, pool.getUuid());
            Map<String, TemplateProp> tInfo = new HashMap<String, TemplateProp>();
            ModifyStoragePoolAnswer answer = new ModifyStoragePoolAnswer(cmd, d.totalSpace, d.freeSpace, tInfo);
            return answer;
        } catch (Exception e) {
            logger.debug("ModifyStoragePoolCommand failed", e);
            return new Answer(cmd, false, e.getMessage());
        }
    }

    protected Answer execute(CreateStoragePoolCommand cmd) {
        return new Answer(cmd, true, "success");
    }

    protected PrimaryStorageDownloadAnswer execute(final PrimaryStorageDownloadCommand cmd) {
        try {
            URI uri = new URI(cmd.getUrl());
            String secondaryStoragePath = uri.getHost() + ":" + uri.getPath();
            Pair<String, Long> res = OvmStoragePool.downloadTemplate(_conn, cmd.getPoolUuid(), secondaryStoragePath);
            return new PrimaryStorageDownloadAnswer(res.first(), res.second());
        } catch (Exception e) {
            logger.debug("PrimaryStorageDownloadCommand failed", e);
            return new PrimaryStorageDownloadAnswer(e.getMessage());
        }
    }

    protected CreateAnswer execute(CreateCommand cmd) {
        StorageFilerTO primaryStorage = cmd.getPool();
        DiskProfile disk = cmd.getDiskCharacteristics();

        try {
            OvmVolume.Details vol = null;
            if (cmd.getTemplateUrl() != null) {
                vol = OvmVolume.createFromTemplate(_conn, primaryStorage.getUuid(), cmd.getTemplateUrl());
            } else {
                vol = OvmVolume.createDataDsik(_conn, primaryStorage.getUuid(), Long.toString(disk.getSize()), disk.getType() == Volume.Type.ROOT);
            }

            VolumeTO volume =
                new VolumeTO(cmd.getVolumeId(), disk.getType(), primaryStorage.getType(), primaryStorage.getUuid(), primaryStorage.getPath(), vol.name, vol.path,
                    vol.size, null);
            return new CreateAnswer(cmd, volume);
        } catch (Exception e) {
            logger.debug("CreateCommand failed", e);
            return new CreateAnswer(cmd, e.getMessage());
        }
    }

    protected void applySpecToVm(OvmVm.Details vm, VirtualMachineTO spec) {
        vm.name = spec.getName();
        vm.memory = spec.getMinRam();
        vm.cpuNum = spec.getCpus();
        vm.uuid = UuidUtils.nameUUIDFromBytes(spec.getName().getBytes()).toString();
        if (spec.getBootloader() == BootloaderType.CD) {
            vm.bootDev = OvmVm.CD;
            vm.type = OvmVm.HVM;
        } else {
            vm.bootDev = OvmVm.HDD;
            String osType = OvmHelper.getOvmGuestType(spec.getOs());
            if (OvmHelper.ORACLE_LINUX.equals(osType)) {
                vm.type = OvmVm.PV;
            } else if (OvmHelper.WINDOWS.equals(osType) || OvmHelper.ORACLE_SOLARIS.equals(osType)) {
                vm.type = OvmVm.HVM;
            } else {
                throw new CloudRuntimeException(spec.getOs() + " is not supported" + ",Oracle VM only supports Oracle Linux and Windows");
            }
        }
    }

    protected void createVbds(OvmVm.Details vm, VirtualMachineTO spec) throws URISyntaxException {
        for (DiskTO volume : spec.getDisks()) {
            if (volume.getType() == Volume.Type.ROOT) {
                VolumeObjectTO vol = (VolumeObjectTO)volume.getData();
                OvmDisk.Details root = new OvmDisk.Details();
                root.path = vol.getPath();
                root.type = OvmDisk.WRITE;
                root.isIso = false;
                vm.rootDisk = root;
            } else if (volume.getType() == Volume.Type.ISO) {
                DataTO isoTO = volume.getData();
                if (isoTO.getPath() != null) {
                    TemplateObjectTO template = (TemplateObjectTO)isoTO;
                    DataStoreTO store = template.getDataStore();
                    if (!(store instanceof NfsTO)) {
                        throw new CloudRuntimeException("unsupported protocol");
                    }
                    NfsTO nfsStore = (NfsTO)store;
                    String isoPath = nfsStore.getUrl() + File.separator + template.getPath();
                    OvmDisk.Details iso = new OvmDisk.Details();
                    URI path = new URI(isoPath);
                    iso.path = path.getHost() + ":" + path.getPath();
                    iso.type = OvmDisk.READ;
                    iso.isIso = true;
                    vm.disks.add(iso);
                }
            } else if (volume.getType() == Volume.Type.DATADISK) {

                OvmDisk.Details data = new OvmDisk.Details();
                data.path = volume.getData().getPath();
                data.type = OvmDisk.SHAREDWRITE;
                data.isIso = false;
                vm.disks.add(data);
            } else {
                throw new CloudRuntimeException("Unknown volume type: " + volume.getType());
            }
        }
    }

    private String createVlanBridge(String networkName, String vlanId) throws XmlRpcException {
        OvmBridge.Details brdetails = OvmBridge.getDetails(_conn, networkName);
        if (brdetails.attach.equalsIgnoreCase("null")) {
            throw new CloudRuntimeException("Bridge " + networkName + " has no PIF");
        }

        OvmVlan.Details vdetails = new OvmVlan.Details();
        vdetails.pif = brdetails.attach;
        vdetails.vid = Integer.parseInt(vlanId);
        brdetails.name = "vlan" + vlanId;
        brdetails.attach = "null";
        OvmBridge.createVlanBridge(_conn, brdetails, vdetails);
        return brdetails.name;
    }

    //TODO: complete all network support
    protected String getNetwork(NicTO nic) throws XmlRpcException {
        String vlanId = null;
        String bridgeName = null;
        if (nic.getBroadcastType() == BroadcastDomainType.Vlan) {
            vlanId = BroadcastDomainType.getValue(nic.getBroadcastUri());
        }

        if (nic.getType() == TrafficType.Guest) {
            if (nic.getBroadcastType() == BroadcastDomainType.Vlan && !vlanId.equalsIgnoreCase("untagged")) {
                bridgeName = createVlanBridge(_guestNetworkName, vlanId);
            } else {
                bridgeName = _guestNetworkName;
            }
        } else if (nic.getType() == TrafficType.Control) {
            throw new CloudRuntimeException("local link network is not supported");
        } else if (nic.getType() == TrafficType.Public) {
            throw new CloudRuntimeException("public network for system vm is not supported");
        } else if (nic.getType() == TrafficType.Management) {
            bridgeName = _privateNetworkName;
        } else {
            throw new CloudRuntimeException("Unkonw network traffic type:" + nic.getType());
        }

        return bridgeName;
    }

    protected OvmVif.Details createVif(NicTO nic) throws XmlRpcException {
        OvmVif.Details vif = new OvmVif.Details();
        vif.mac = nic.getMac();
        vif.bridge = getNetwork(nic);
        return vif;
    }

    protected void createVifs(OvmVm.Details vm, VirtualMachineTO spec) throws CloudRuntimeException, XmlRpcException {
        NicTO[] nics = spec.getNics();
        List<OvmVif.Details> vifs = new ArrayList<OvmVif.Details>(nics.length);
        for (NicTO nic : nics) {
            OvmVif.Details vif = createVif(nic);
            vifs.add(nic.getDeviceId(), vif);
        }
        vm.vifs.addAll(vifs);
    }

    protected void startVm(OvmVm.Details vm) throws XmlRpcException {
        OvmVm.create(_conn, vm);
    }

    private void cleanupNetwork(List<OvmVif.Details> vifs) throws XmlRpcException {
        for (OvmVif.Details vif : vifs) {
            if (vif.bridge.startsWith("vlan")) {
                OvmBridge.deleteVlanBridge(_conn, vif.bridge);
            }
        }
    }

    protected void cleanup(OvmVm.Details vm) {
        try {
            cleanupNetwork(vm.vifs);
        } catch (XmlRpcException e) {
            logger.debug("Clean up network for " + vm.name + " failed", e);
        }
        _vmNetworkStats.remove(vm.name);
    }

    @Override
    public synchronized StartAnswer execute(StartCommand cmd) {
        VirtualMachineTO vmSpec = cmd.getVirtualMachine();
        String vmName = vmSpec.getName();
        OvmVm.Details vmDetails = null;
        try {
            vmDetails = new OvmVm.Details();
            applySpecToVm(vmDetails, vmSpec);
            createVbds(vmDetails, vmSpec);
            createVifs(vmDetails, vmSpec);
            startVm(vmDetails);

            // Add security group rules
            NicTO[] nics = vmSpec.getNics();
            for (NicTO nic : nics) {
                if (nic.isSecurityGroupEnabled()) {
                    if (vmSpec.getType().equals(VirtualMachine.Type.User)) {
                        defaultNetworkRulesForUserVm(vmName, vmSpec.getId(), nic);
                    }
                }
            }

            return new StartAnswer(cmd);
        } catch (Exception e) {
            logger.debug("Start vm " + vmName + " failed", e);
            cleanup(vmDetails);
            return new StartAnswer(cmd, e.getMessage());
        }
    }

    protected Answer execute(GetHostStatsCommand cmd) {
        try {
            Map<String, String> res = OvmHost.getPerformanceStats(_conn, _publicNetworkName);
            Double cpuUtil = Double.parseDouble(res.get("cpuUtil"));
            Double rxBytes = Double.parseDouble(res.get("rxBytes"));
            Double txBytes = Double.parseDouble(res.get("txBytes"));
            Double totalMemory = Double.parseDouble(res.get("totalMemory"));
            Double freeMemory = Double.parseDouble(res.get("freeMemory"));
            HostStatsEntry hostStats = new HostStatsEntry(cmd.getHostId(), cpuUtil, rxBytes, txBytes, "host", totalMemory, freeMemory, 0, 0);
            return new GetHostStatsAnswer(cmd, hostStats);
        } catch (Exception e) {
            logger.debug("Get host stats of " + cmd.getHostName() + " failed", e);
            return new Answer(cmd, false, e.getMessage());
        }

    }

    @Override
    public StopAnswer execute(StopCommand cmd) {
        String vmName = cmd.getVmName();
        try {
            OvmVm.Details vm = null;
            try {
                vm = OvmVm.getDetails(_conn, vmName);
            } catch (XmlRpcException e) {
                logger.debug("Unable to get details of vm: " + vmName + ", treating it as stopped", e);
                return new StopAnswer(cmd, "success", true);
            }

            deleteAllNetworkRulesForVm(vmName);
            OvmVm.stop(_conn, vmName);
            cleanup(vm);
            return new StopAnswer(cmd, "success", true);
        } catch (Exception e) {
            logger.debug("Stop " + vmName + "failed", e);
            return new StopAnswer(cmd, e.getMessage(), false);
        }
    }

    @Override
    public RebootAnswer execute(RebootCommand cmd) {
        String vmName = cmd.getVmName();

        try {
            Map<String, String> res = OvmVm.reboot(_conn, vmName);
            Integer vncPort = Integer.parseInt(res.get("vncPort"));
            return new RebootAnswer(cmd, null, vncPort);
        } catch (Exception e) {
            logger.debug("Reboot " + vmName + " failed", e);
            return new RebootAnswer(cmd, e.getMessage(), false);
        }
    }

    private PowerState toPowerState(String vmName, String s) {
        PowerState state = s_powerStateMaps.get(s);
        if (state == null) {
            logger.debug("Unkown state " + s + " for " + vmName);
            state = PowerState.PowerUnknown;
        }
        return state;
    }

    protected HashMap<String, HostVmStateReportEntry> getHostVmStateReport() throws XmlRpcException {
        final HashMap<String, HostVmStateReportEntry> vmStates = new HashMap<String, HostVmStateReportEntry>();
        Map<String, String> vms = OvmHost.getAllVms(_conn);
        for (final Map.Entry<String, String> entry : vms.entrySet()) {
            PowerState state = toPowerState(entry.getKey(), entry.getValue());
            vmStates.put(entry.getKey(), new HostVmStateReportEntry(state, _conn.getIp()));
        }
        return vmStates;
    }

    protected HashMap<String, PowerState> getAllVms() throws XmlRpcException {
        final HashMap<String, PowerState> vmStates = new HashMap<String, PowerState>();
        Map<String, String> vms = OvmHost.getAllVms(_conn);
        for (final Map.Entry<String, String> entry : vms.entrySet()) {
            PowerState powerState = toPowerState(entry.getKey(), entry.getValue());
            vmStates.put(entry.getKey(), powerState);
        }
        return vmStates;
    }


    protected GetStorageStatsAnswer execute(final GetStorageStatsCommand cmd) {
        try {
            OvmStoragePool.Details d = OvmStoragePool.getDetailsByUuid(_conn, cmd.getStorageId());
            return new GetStorageStatsAnswer(cmd, d.totalSpace, d.usedSpace);
        } catch (Exception e) {
            logger.debug("GetStorageStatsCommand on pool " + cmd.getStorageId() + " failed", e);
            return new GetStorageStatsAnswer(cmd, e.getMessage());
        }
    }

    private VmStatsEntry getVmStat(String vmName) throws XmlRpcException {
        Map<String, String> vmStat = OvmVm.getVmStats(_conn, vmName);
        int nvcpus = Integer.parseInt(vmStat.get("cpuNum"));
        float cpuUtil = Float.parseFloat(vmStat.get("cpuUtil"));
        long rxBytes = Long.parseLong(vmStat.get("rxBytes"));
        long txBytes = Long.parseLong(vmStat.get("txBytes"));
        Pair<Long, Long> oldNetworkStat = _vmNetworkStats.get(vmName);

        long rx = rxBytes;
        long tx = txBytes;
        if (oldNetworkStat != null) {
            rx -= oldNetworkStat.first();
            tx -= oldNetworkStat.second();
            oldNetworkStat.set(rxBytes, txBytes);
        } else {
            oldNetworkStat = new Pair<Long, Long>(rx, tx);
        }
        _vmNetworkStats.put(vmName, oldNetworkStat);

        VmStatsEntry e = new VmStatsEntry();
        e.setCPUUtilization(cpuUtil);
        e.setNumCPUs(nvcpus);
        e.setNetworkReadKBs(rx);
        e.setNetworkWriteKBs(tx);
        e.setEntityType("vm");
        return e;
    }

    protected GetVmStatsAnswer execute(GetVmStatsCommand cmd) {
        List<String> vmNames = cmd.getVmNames();
        HashMap<String, VmStatsEntry> vmStatsNameMap = new HashMap<String, VmStatsEntry>();
        for (String vmName : vmNames) {
            try {
                VmStatsEntry e = getVmStat(vmName);
                vmStatsNameMap.put(vmName, e);
            } catch (XmlRpcException e) {
                logger.debug("Get vm stat for " + vmName + " failed", e);
                continue;
            }
        }
        return new GetVmStatsAnswer(cmd, vmStatsNameMap);
    }

    public Answer execute(DestroyCommand cmd) {
        try {
            OvmVolume.destroy(_conn, cmd.getVolume().getPoolUuid(), cmd.getVolume().getPath());
            return new Answer(cmd, true, "Success");
        } catch (Exception e) {
            logger.debug("Destroy volume " + cmd.getVolume().getName() + " failed", e);
            return new Answer(cmd, false, e.getMessage());
        }
    }

    protected PrepareForMigrationAnswer execute(PrepareForMigrationCommand cmd) {
        VirtualMachineTO vm = cmd.getVirtualMachine();
        if (logger.isDebugEnabled()) {
            logger.debug("Preparing host for migrating " + vm);
        }

        NicTO[] nics = vm.getNics();
        try {
            for (NicTO nic : nics) {
                getNetwork(nic);
            }

            return new PrepareForMigrationAnswer(cmd);
        } catch (Exception e) {
            logger.warn("Catch Exception " + e.getClass().getName() + " prepare for migration failed due to " + e.toString(), e);
            return new PrepareForMigrationAnswer(cmd, e);
        }
    }

    protected MigrateAnswer execute(final MigrateCommand cmd) {
        final String vmName = cmd.getVmName();
        try {
            OvmVm.Details vm = OvmVm.getDetails(_conn, vmName);
            String destIp = cmd.getDestinationIp();
            OvmVm.migrate(_conn, vmName, destIp);
            cleanup(vm);
            return new MigrateAnswer(cmd, true, "migration succeeded", null);
        } catch (Exception e) {
            String msg = "Catch Exception " + e.getClass().getName() + ": Migration failed due to " + e.toString();
            logger.debug(msg, e);
            return new MigrateAnswer(cmd, false, msg, null);
        }
    }

    protected CheckVirtualMachineAnswer execute(final CheckVirtualMachineCommand cmd) {
        final String vmName = cmd.getVmName();
        try {
            Map<String, String> res = OvmVm.register(_conn, vmName);
            Integer vncPort = Integer.parseInt(res.get("vncPort"));
            HashMap<String, PowerState> states = getAllVms();
            PowerState vmPowerState = states.get(vmName);
            if (vmPowerState == null) {
                logger.warn("Check state of " + vmName + " return null in CheckVirtualMachineCommand");
                vmPowerState = PowerState.PowerOff;
            }

            return new CheckVirtualMachineAnswer(cmd, vmPowerState, vncPort);
        } catch (Exception e) {
            logger.debug("Check migration for " + vmName + " failed", e);
            return new CheckVirtualMachineAnswer(cmd, PowerState.PowerOff, null);
        }
    }

    protected MaintainAnswer execute(MaintainCommand cmd) {
        return new MaintainAnswer(cmd);
    }

    protected GetVncPortAnswer execute(GetVncPortCommand cmd) {
        try {
            Integer vncPort = OvmVm.getVncPort(_conn, cmd.getName());
            return new GetVncPortAnswer(cmd, _ip, vncPort);
        } catch (Exception e) {
            logger.debug("get vnc port for " + cmd.getName() + " failed", e);
            return new GetVncPortAnswer(cmd, e.getMessage());
        }
    }

    protected Answer execute(PingTestCommand cmd) {
        try {
            if (cmd.getComputingHostIp() != null) {
                OvmHost.pingAnotherHost(_conn, cmd.getComputingHostIp());
            } else {
                return new Answer(cmd, false, "why asks me to ping router???");
            }

            return new Answer(cmd, true, "success");
        } catch (Exception e) {
            logger.debug("Ping " + cmd.getComputingHostIp() + " failed", e);
            return new Answer(cmd, false, e.getMessage());
        }
    }

    protected FenceAnswer execute(FenceCommand cmd) {
        try {
            Boolean res = OvmHost.fence(_conn, cmd.getHostIp());
            return new FenceAnswer(cmd, res, res.toString());
        } catch (Exception e) {
            logger.debug("fence " + cmd.getHostIp() + " failed", e);
            return new FenceAnswer(cmd, false, e.getMessage());
        }
    }

    protected Answer execute(AttachIsoCommand cmd) {
        try {
            URI iso = new URI(cmd.getIsoPath());
            String isoPath = iso.getHost() + ":" + iso.getPath();
            OvmVm.detachOrAttachIso(_conn, cmd.getVmName(), isoPath, cmd.isAttach());
            return new Answer(cmd);
        } catch (Exception e) {
            logger.debug("Attach or detach ISO " + cmd.getIsoPath() + " for " + cmd.getVmName() + " attach:" + cmd.isAttach() + " failed", e);
            return new Answer(cmd, false, e.getMessage());
        }
    }

    private Answer execute(SecurityGroupRulesCmd cmd) {
        boolean result = false;
        try {
            OvmVif.Details vif = getVifFromVm(cmd.getVmName(), null);
            String vifDeviceName = vif.name;
            String bridgeName = vif.bridge;
            result =
                addNetworkRules(cmd.getVmName(), Long.toString(cmd.getVmId()), cmd.getGuestIp(), cmd.getSignature(), String.valueOf(cmd.getSeqNum()), cmd.getGuestMac(),
                    cmd.stringifyRules(), vifDeviceName, bridgeName);
        } catch (XmlRpcException e) {
            logger.error(e);
            result = false;
        }

        if (!result) {
            logger.warn("Failed to program network rules for vm " + cmd.getVmName());
            return new SecurityGroupRuleAnswer(cmd, false, "programming network rules failed");
        } else {
            logger.info("Programmed network rules for vm " + cmd.getVmName() + " guestIp=" + cmd.getGuestIp() + ":ingress num rules=" + cmd.getIngressRuleSet().size() +
                ":egress num rules=" + cmd.getEgressRuleSet().size());
            return new SecurityGroupRuleAnswer(cmd);
        }
    }

    private Answer execute(CleanupNetworkRulesCmd cmd) {
        boolean result = false;
        try {
            result = cleanupNetworkRules();
        } catch (XmlRpcException e) {
            logger.error(e);
            result = false;
        }

        if (result) {
            return new Answer(cmd);
        } else {
            return new Answer(cmd, result, "Failed to cleanup network rules.");
        }
    }

    protected boolean defaultNetworkRulesForUserVm(String vmName, Long vmId, NicTO nic) throws XmlRpcException {
        if (!_canBridgeFirewall) {
            return false;
        }

        OvmVif.Details vif = getVifFromVm(vmName, nic.getDeviceId());
        String ipAddress = nic.getIp();
        String macAddress = vif.mac;
        String vifName = vif.name;
        String bridgeName = vif.bridge;

        return OvmSecurityGroup.defaultNetworkRulesForUserVm(_conn, vmName, String.valueOf(vmId), ipAddress, macAddress, vifName, bridgeName);
    }

    protected boolean deleteAllNetworkRulesForVm(String vmName) throws XmlRpcException {
        if (!_canBridgeFirewall) {
            return false;
        }

        String vif = getVifFromVm(vmName, null).name;
        return OvmSecurityGroup.deleteAllNetworkRulesForVm(_conn, vmName, vif);
    }

    protected boolean addNetworkRules(String vmName, String vmId, String guestIp, String signature, String seqno, String vifMacAddress, String rules,
        String vifDeviceName, String bridgeName) throws XmlRpcException {
        if (!_canBridgeFirewall) {
            return false;
        }

        String newRules = rules.replace(" ", ";");
        return OvmSecurityGroup.addNetworkRules(_conn, vmName, vmId, guestIp, signature, seqno, vifMacAddress, newRules, vifDeviceName, bridgeName);
    }

    protected boolean cleanupNetworkRules() throws XmlRpcException {
        if (!_canBridgeFirewall) {
            return false;
        }

        return OvmSecurityGroup.cleanupNetworkRules(_conn);
    }

    protected boolean canBridgeFirewall() throws XmlRpcException {
        return OvmSecurityGroup.canBridgeFirewall(_conn);
    }

    protected OvmVif.Details getVifFromVm(String vmName, Integer deviceId) throws XmlRpcException {
        List<OvmVif.Details> vifs = null;

        try {
            vifs = getInterfaces(vmName);
        } catch (XmlRpcException e) {
            logger.error("Failed to get VIFs for VM " + vmName, e);
            throw e;
        }

        if (deviceId != null && vifs.size() > deviceId) {
            return vifs.get(deviceId);
        } else if (deviceId == null && vifs.size() > 0) {
            return vifs.get(0);
        } else {
            return null;
        }
    }

    protected List<OvmVif.Details> getInterfaces(String vmName) throws XmlRpcException {
        OvmVm.Details vmDetails = OvmVm.getDetails(_conn, vmName);
        return vmDetails.vifs;
    }

    protected Answer execute(PrepareOCFS2NodesCommand cmd) {
        List<Ternary<Integer, String, String>> nodes = cmd.getNodes();
        StringBuffer params = new StringBuffer();
        for (Ternary<Integer, String, String> node : nodes) {
            String param = String.format("%1$s:%2$s:%3$s", node.first(), node.second(), node.third());
            params.append(param);
            params.append(";");
        }

        try {
            OvmStoragePool.prepareOCFS2Nodes(_conn, cmd.getClusterName(), params.toString());
            return new Answer(cmd, true, "Success");
        } catch (XmlRpcException e) {
            logger.debug("OCFS2 prepare nodes failed", e);
            return new Answer(cmd, false, e.getMessage());
        }
    }

    protected CreatePrivateTemplateAnswer execute(final CreatePrivateTemplateFromVolumeCommand cmd) {
        String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
        String volumePath = cmd.getVolumePath();
        Long accountId = cmd.getAccountId();
        Long templateId = cmd.getTemplateId();
        int wait = cmd.getWait();
        if (wait == 0) {
            /* Defaut timeout 2 hours */
            wait = 7200;
        }

        try {
            URI uri;
            uri = new URI(secondaryStorageUrl);
            String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
            String installPath = "template/tmpl/" + accountId + "/" + templateId;
            Map<String, String> res = OvmStoragePool.createTemplateFromVolume(_conn, secondaryStorageMountPath, installPath, volumePath, wait);
            return new CreatePrivateTemplateAnswer(cmd, true, null, res.get("installPath"), Long.parseLong(res.get("virtualSize")), Long.parseLong(res.get("physicalSize")),
                res.get("templateFileName"), ImageFormat.RAW);
        } catch (Exception e) {
            logger.debug("Create template failed", e);
            return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage());
        }
    }

    protected CopyVolumeAnswer execute(CopyVolumeCommand cmd) {
        String volumePath = cmd.getVolumePath();
        String secondaryStorageURL = cmd.getSecondaryStorageURL();
        int wait = cmd.getWait();
        if (wait == 0) {
            wait = 7200;
        }

        try {
            URI uri = new URI(secondaryStorageURL);
            String secStorageMountPath = uri.getHost() + ":" + uri.getPath();
            String volumeFolderOnSecStorage = "volumes/" + String.valueOf(cmd.getVolumeId());
            String storagePoolUuid = cmd.getPool().getUuid();
            Boolean toSec = cmd.toSecondaryStorage();
            String res = OvmStoragePool.copyVolume(_conn, secStorageMountPath, volumeFolderOnSecStorage, volumePath, storagePoolUuid, toSec, wait);
            return new CopyVolumeAnswer(cmd, true, null, null, res);
        } catch (Exception e) {
            logger.debug("Copy volume failed", e);
            return new CopyVolumeAnswer(cmd, false, e.getMessage(), null, null);
        }
    }

    protected Answer execute(DeleteStoragePoolCommand cmd) {
        try {
            OvmStoragePool.delete(_conn, cmd.getPool().getUuid());
        } catch (Exception e) {
            logger.debug("Delete storage pool on host " + _ip + " failed, however, we leave to user for cleanup and tell management server it succeeded", e);
        }

        return new Answer(cmd);
    }

    protected CheckNetworkAnswer execute(CheckNetworkCommand cmd) {
        if (logger.isDebugEnabled()) {
            logger.debug("Checking if network name setup is done on the resource");
        }

        List<PhysicalNetworkSetupInfo> infoList = cmd.getPhysicalNetworkInfoList();

        boolean errorout = false;
        String msg = "";
        for (PhysicalNetworkSetupInfo info : infoList) {
            if (!isNetworkSetupByName(info.getGuestNetworkName())) {
                msg = "For Physical Network id:" + info.getPhysicalNetworkId() + ", Guest Network is not configured on the backend by name " + info.getGuestNetworkName();
                errorout = true;
                break;
            }
            if (!isNetworkSetupByName(info.getPrivateNetworkName())) {
                msg =
                    "For Physical Network id:" + info.getPhysicalNetworkId() + ", Private Network is not configured on the backend by name " +
                        info.getPrivateNetworkName();
                errorout = true;
                break;
            }
            if (!isNetworkSetupByName(info.getPublicNetworkName())) {
                msg =
                    "For Physical Network id:" + info.getPhysicalNetworkId() + ", Public Network is not configured on the backend by name " + info.getPublicNetworkName();
                errorout = true;
                break;
            }
        }

        if (errorout) {
            logger.error(msg);
            return new CheckNetworkAnswer(cmd, false, msg);
        } else {
            return new CheckNetworkAnswer(cmd, true, "Network Setup check by names is done");
        }
    }

    private boolean isNetworkSetupByName(String nameTag) {
        if (nameTag != null) {
            if (logger.isDebugEnabled()) {
                logger.debug("Looking for network setup by name " + nameTag);
            }
            return _bridges.contains(nameTag);
        }
        return true;
    }

    @Override
    public Answer executeRequest(Command cmd) {
        Class<? extends Command> clazz = cmd.getClass();
        if (clazz == ReadyCommand.class) {
            return execute((ReadyCommand)cmd);
        } else if (clazz == CreateStoragePoolCommand.class) {
            return execute((CreateStoragePoolCommand)cmd);
        } else if (clazz == ModifyStoragePoolCommand.class) {
            return execute((ModifyStoragePoolCommand)cmd);
        } else if (clazz == PrimaryStorageDownloadCommand.class) {
            return execute((PrimaryStorageDownloadCommand)cmd);
        } else if (clazz == CreateCommand.class) {
            return execute((CreateCommand)cmd);
        } else if (clazz == GetHostStatsCommand.class) {
            return execute((GetHostStatsCommand)cmd);
        } else if (clazz == StopCommand.class) {
            return execute((StopCommand)cmd);
        } else if (clazz == RebootCommand.class) {
            return execute((RebootCommand)cmd);
        } else if (clazz == GetStorageStatsCommand.class) {
            return execute((GetStorageStatsCommand)cmd);
        } else if (clazz == GetVmStatsCommand.class) {
            return execute((GetVmStatsCommand)cmd);
        } else if (clazz == DestroyCommand.class) {
            return execute((DestroyCommand)cmd);
        } else if (clazz == PrepareForMigrationCommand.class) {
            return execute((PrepareForMigrationCommand)cmd);
        } else if (clazz == MigrateCommand.class) {
            return execute((MigrateCommand)cmd);
        } else if (clazz == CheckVirtualMachineCommand.class) {
            return execute((CheckVirtualMachineCommand)cmd);
        } else if (clazz == MaintainCommand.class) {
            return execute((MaintainCommand)cmd);
        } else if (clazz == StartCommand.class) {
            return execute((StartCommand)cmd);
        } else if (clazz == GetVncPortCommand.class) {
            return execute((GetVncPortCommand)cmd);
        } else if (clazz == PingTestCommand.class) {
            return execute((PingTestCommand)cmd);
        } else if (clazz == FenceCommand.class) {
            return execute((FenceCommand)cmd);
        } else if (clazz == AttachIsoCommand.class) {
            return execute((AttachIsoCommand)cmd);
        } else if (clazz == SecurityGroupRulesCmd.class) {
            return execute((SecurityGroupRulesCmd)cmd);
        } else if (clazz == CleanupNetworkRulesCmd.class) {
            return execute((CleanupNetworkRulesCmd)cmd);
        } else if (clazz == PrepareOCFS2NodesCommand.class) {
            return execute((PrepareOCFS2NodesCommand)cmd);
        } else if (clazz == CreatePrivateTemplateFromVolumeCommand.class) {
            return execute((CreatePrivateTemplateFromVolumeCommand)cmd);
        } else if (clazz == CopyVolumeCommand.class) {
            return execute((CopyVolumeCommand)cmd);
        } else if (clazz == DeleteStoragePoolCommand.class) {
            return execute((DeleteStoragePoolCommand)cmd);
        } else if (clazz == CheckNetworkCommand.class) {
            return execute((CheckNetworkCommand)cmd);
        } else {
            return Answer.createUnsupportedCommandAnswer(cmd);
        }
    }

    @Override
    public void disconnected() {
        // TODO Auto-generated method stub

    }

    @Override
    public IAgentControl getAgentControl() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void setAgentControl(IAgentControl agentControl) {
        // TODO Auto-generated method stub

    }

    @Override
    public void setName(String name) {
        // TODO Auto-generated method stub

    }

    @Override
    public void setConfigParams(Map<String, Object> params) {
        // TODO Auto-generated method stub

    }

    @Override
    public Map<String, Object> getConfigParams() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int getRunLevel() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void setRunLevel(int level) {
        // TODO Auto-generated method stub

    }

}
