package net.onrc.onos.core.hostmanager;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.IUpdate;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.util.MACAddress;
import net.onrc.onos.core.packet.ARP;
import net.onrc.onos.core.packet.Ethernet;
import net.onrc.onos.core.packet.IPv4;
import net.onrc.onos.core.topology.ITopologyService;
import net.onrc.onos.core.topology.MutableTopology;
import net.onrc.onos.core.topology.Port;
import net.onrc.onos.core.util.Dpid;
import net.onrc.onos.core.util.PortNumber;
import net.onrc.onos.core.util.PortNumberUtils;

import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFType;
import org.projectfloodlight.openflow.types.IPv4Address;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HostManager implements IFloodlightModule,
IOFMessageListener,
IHostService {

    private static final Logger log = LoggerFactory.getLogger(HostManager.class);
    private static final long HOST_CLEANING_INITIAL_DELAY = 30;
    private int cleanupSecondConfig = 60 * 60;
    private int agingMillisecConfig = 60 * 60 * 1000;

    private CopyOnWriteArrayList<IHostListener> hostListeners;
    private IFloodlightProviderService floodlightProvider;
    private static final ScheduledExecutorService EXECUTOR_SERVICE =
            Executors.newSingleThreadScheduledExecutor();

    private ITopologyService topologyService;
    private MutableTopology mutableTopology;

    public enum HostUpdateType {
        ADD, DELETE, UPDATE;
    }

    private class HostUpdate implements IUpdate {
        private final Host host;
        private final HostUpdateType type;

        public HostUpdate(Host host, HostUpdateType type) {
            this.host = host;
            this.type = type;
        }

        @Override
        public void dispatch() {
            if (type == HostUpdateType.ADD) {
                for (IHostListener listener : hostListeners) {
                    listener.hostAdded(host);
                }
            } else if (type == HostUpdateType.DELETE) {
                for (IHostListener listener : hostListeners) {
                    listener.hostRemoved(host);
                }
            }
        }
    }

    @Override
    public String getName() {
        return "hostmanager";
    }

    @Override
    public boolean isCallbackOrderingPrereq(OFType type, String name) {
        // We want link discovery to consume LLDP first otherwise we'll
        // end up reading bad host info from LLDP packets
        return type == OFType.PACKET_IN && "linkdiscovery".equals(name);
    }

    @Override
    public boolean isCallbackOrderingPostreq(OFType type, String name) {
        return type == OFType.PACKET_IN &&
                ("proxyarpmanager".equals(name) || "onosforwarding".equals(name));
    }

    @Override
    public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
        if (msg.getType().equals(OFType.PACKET_IN) &&
                (msg instanceof OFPacketIn)) {
            OFPacketIn pi = (OFPacketIn) msg;

            Ethernet eth = IFloodlightProviderService.bcStore.
                    get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
            short inport = (short) cntx.getStorage()
                    .get(IFloodlightProviderService.CONTEXT_PI_INPORT);

            return processPacketIn(sw, pi, eth, inport);
        }

        return Command.CONTINUE;
    }

    // This "protected" modifier is for unit test.
    // The above "receive" method couldn't be tested
    // because of IFloodlightProviderService static final field.
    protected Command processPacketIn(IOFSwitch sw, OFPacketIn pi, Ethernet eth,
            short inport) {
        if (log.isTraceEnabled()) {
            log.trace("Receive PACKET_IN swId {}, portId {}", sw.getId(), inport);
        }

        final Dpid dpid = new Dpid(sw.getId());
        // FIXME method signature needs to be fixed. losing port number precision
        final PortNumber portNum = PortNumberUtils
                            .openFlow(sw.getOFVersion(), inport);

        Host srcHost =
                getSourceHostFromPacket(eth, dpid.value(), portNum.value());

        if (srcHost == null) {
            return Command.STOP;
        }

        // If the switch port we try to attach a new host already has a link,
        // then don't add the host
        // TODO We probably don't need to check this here, it should be done in
        // the Topology module.
        mutableTopology.acquireReadLock();
        try {
            if (mutableTopology.getOutgoingLink(dpid, portNum) != null ||
                    mutableTopology.getIncomingLink(dpid, portNum) != null) {
                log.debug("Not adding host {} as " +
                        "there is a link on the port: dpid {} port {}",
                        srcHost.getMacAddress(), dpid, portNum);
                return Command.CONTINUE;
            }
        } finally {
            mutableTopology.releaseReadLock();
        }

        Long mac = eth.getSourceMAC().toLong();
        addHost(mac, srcHost);

        if (log.isTraceEnabled()) {
            log.trace("Add host info: {}", srcHost);
        }
        return Command.CONTINUE;
    }

    // Thread to delete hosts periodically.
    // Remove all hosts from the map first and then finally delete hosts
    // from the DB.

    // TODO This should be sharded based on host 'owner' (i.e. the instance
    // that owns the switch it is attached to). Currently any instance can
    // issue deletes for any host, which permits race conditions and could
    // cause the Topology replicas to diverge.
    private class HostCleaner implements Runnable {
        @Override
        public void run() {
            log.debug("called HostCleaner");
            mutableTopology.acquireReadLock();
            try {
                Set<net.onrc.onos.core.topology.Host> deleteSet = new HashSet<>();
                for (net.onrc.onos.core.topology.Host host : mutableTopology.getHosts()) {
                    long now = System.currentTimeMillis();
                    if ((now - host.getLastSeenTime() > agingMillisecConfig)) {
                        if (log.isTraceEnabled()) {
                            log.trace("Removing host info: mac {}, now {}, lastSeenTime {}, diff {}",
                                    host.getMacAddress(), now, host.getLastSeenTime(), now - host.getLastSeenTime());
                        }
                        deleteSet.add(host);
                    }
                }

                for (net.onrc.onos.core.topology.Host host : deleteSet) {
                    deleteHostByMac(host.getMacAddress());
                }
            } catch (Exception e) {
                // Any exception thrown by the task will prevent the Executor
                // from running the next iteration, so we need to catch and log
                // all exceptions here.
                log.error("Exception in host cleanup thread:", e);
            } finally {
                mutableTopology.releaseReadLock();
            }
        }
    }

    /**
     * Parse a host from an {@link Ethernet} packet.
     *
     * @param eth the packet to parse
     * @param swdpid the switch on which the packet arrived
     * @param port the port on which the packet arrived
     * @return the host from the packet
     */
    protected Host getSourceHostFromPacket(Ethernet eth,
            long swdpid, long port) {
        MACAddress sourceMac = eth.getSourceMAC();
        int sourceIp = 0;


        if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
            IPv4 ipv4 = (IPv4)eth.getPayload();
            sourceIp = ipv4.getSourceAddress();
        }
        else if (eth.getEtherType() == Ethernet.TYPE_ARP) {
            ARP arp = (ARP)eth.getPayload();
            sourceIp = IPv4Address.of(arp.getSenderProtocolAddress()).getInt();
        }

        // Ignore broadcast/multicast source
        if (sourceMac.isBroadcast() || sourceMac.isMulticast()) {
            return null;
        }

        short vlan = eth.getVlanID();
        return new Host(sourceMac,
                sourceIp,
                ((vlan >= 0) ? vlan : null),
                swdpid,
                port,
                new Date());
    }

    @Override
    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
        List<Class<? extends IFloodlightService>> services =
                new ArrayList<Class<? extends IFloodlightService>>();
        services.add(IHostService.class);
        return services;
    }

    @Override
    public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
        Map<Class<? extends IFloodlightService>, IFloodlightService> impls =
                new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
        impls.put(IHostService.class, this);
        return impls;
    }

    @Override
    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
        List<Class<? extends IFloodlightService>> dependencies =
                new ArrayList<Class<? extends IFloodlightService>>();
        dependencies.add(IFloodlightProviderService.class);
        dependencies.add(ITopologyService.class);
        return dependencies;
    }

    @Override
    public void init(FloodlightModuleContext context)
            throws FloodlightModuleException {
        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
        hostListeners = new CopyOnWriteArrayList<IHostListener>();
        topologyService = context.getServiceImpl(ITopologyService.class);
        mutableTopology = topologyService.getTopology();

        setHostManagerProperties(context);
    }

    @Override
    public void startUp(FloodlightModuleContext context) {
        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
        EXECUTOR_SERVICE.scheduleAtFixedRate(new HostCleaner(),
                HOST_CLEANING_INITIAL_DELAY, cleanupSecondConfig, TimeUnit.SECONDS);
    }

    @Override
    public void deleteHost(Host host) {
        floodlightProvider.publishUpdate(
                new HostUpdate(host, HostUpdateType.DELETE));
    }

    @Override
    public void deleteHostByMac(MACAddress mac) {
        Host deleteHost = null;
        mutableTopology.acquireReadLock();
        try {
            net.onrc.onos.core.topology.Host host = mutableTopology.getHostByMac(mac);

            for (Port switchPort : host.getAttachmentPoints()) {
                // We don't handle vlan now and multiple attachment points.
                deleteHost = new Host(host.getMacAddress(),
                        host.getIpAddress(),
                        null,
                        switchPort.getDpid().value(),
                        switchPort.getNumber().value(),
                        new Date(host.getLastSeenTime()));
                // FIXME: remove NOPMD flag after multiple attachment points are implemented
                break; // NOPMD
            }
        } finally {
            mutableTopology.releaseReadLock();
        }

        if (deleteHost != null) {
            deleteHost(deleteHost);
        }
    }

    @Override
    public void addHost(Long mac, Host host) {
        floodlightProvider.publishUpdate(
                new HostUpdate(host, HostUpdateType.ADD));
    }

    @Override
    public void addHostListener(IHostListener listener) {
        hostListeners.add(listener);
    }

    @Override
    public void removeHostListener(IHostListener listener) {
        hostListeners.remove(listener);
    }

    private void setHostManagerProperties(FloodlightModuleContext context) {
        Map<String, String> configOptions = context.getConfigParams(this);
        String cleanupsec = configOptions.get("cleanupsec");
        String agingmsec = configOptions.get("agingmsec");
        if (cleanupsec != null) {
            cleanupSecondConfig = Integer.parseInt(cleanupsec);
            log.debug("CLEANUP_SECOND is set to {}", cleanupSecondConfig);
        }

        if (agingmsec != null) {
            agingMillisecConfig = Integer.parseInt(agingmsec);
            log.debug("AGEING_MILLSEC is set to {}", agingMillisecConfig);
        }
    }
}
