package net.onrc.onos.apps.bgproute;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;

import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPort;
import org.openflow.util.HexString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FlowCache {
    private final static Logger log = LoggerFactory.getLogger(FlowCache.class);

    private IFloodlightProviderService floodlightProvider;

    private Map<Long, List<OFFlowMod>> flowCache;

    private Comparator<OFFlowMod> cookieComparator = new Comparator<OFFlowMod>() {
        @Override
        public int compare(OFFlowMod fm1, OFFlowMod fm2) {
            long difference = fm2.getCookie() - fm1.getCookie();

            if (difference > 0) {
                return 1;
            } else if (difference < 0) {
                return -1;
            } else {
                return 0;
            }
        }
    };

    public FlowCache(IFloodlightProviderService floodlightProvider) {
        this.floodlightProvider = floodlightProvider;

        flowCache = new HashMap<Long, List<OFFlowMod>>();
    }

    public synchronized void write(long dpid, OFFlowMod flowMod) {
        List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(1);
        flowModList.add(flowMod);
        write(dpid, flowModList);
    }

    public synchronized void write(long dpid, List<OFFlowMod> flowMods) {
        ensureCacheForSwitch(dpid);

        List<OFFlowMod> clones = new ArrayList<OFFlowMod>(flowMods.size());

        //Somehow the OFFlowMods we get passed in will change later on.
        //No idea how this happens, but we can just clone to prevent problems
        try {
            for (OFFlowMod fm : flowMods) {
                clones.add(fm.clone());
            }
        } catch (CloneNotSupportedException e) {
            log.debug("Clone exception", e);
        }

        flowCache.get(dpid).addAll(clones);

        IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);

        if (sw == null) {
            log.debug("Switch not found when writing flow mods");
            return;
        }

        List<OFMessage> msgList = new ArrayList<OFMessage>(clones.size());
        msgList.addAll(clones);

        try {
            sw.write(msgList, null);
        } catch (IOException e) {
            log.error("Error writing to switch", e);
        }


    }

    public synchronized void delete(long dpid, OFFlowMod flowMod) {
        List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(1);
        flowModList.add(flowMod);
        delete(dpid, flowModList);
    }

    public synchronized void delete(long dpid, List<OFFlowMod> flowMods) {
        ensureCacheForSwitch(dpid);

        //Remove the flow mods from the cache first before we alter them
        flowCache.get(dpid).removeAll(flowMods);

        //Alter the original flow mods to make them delete flow mods
        for (OFFlowMod fm : flowMods) {
            fm.setCommand(OFFlowMod.OFPFC_DELETE_STRICT)
                    .setOutPort(OFPort.OFPP_NONE)
                    .setLengthU(OFFlowMod.MINIMUM_LENGTH);

            fm.getActions().clear();
        }

        IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
        if (sw == null) {
            log.debug("Switch not found when writing flow mods");
            return;
        }

        List<OFMessage> msgList = new ArrayList<OFMessage>(flowMods.size());
        msgList.addAll(flowMods);

        try {
            sw.write(msgList, null);
        } catch (IOException e) {
            log.error("Error writing to switch", e);
        }
    }

    //TODO can the Prontos handle being sent all flow mods in one message?
    public synchronized void switchConnected(IOFSwitch sw) {
        log.debug("Switch connected: {}", sw);

        ensureCacheForSwitch(sw.getId());

        List<OFFlowMod> flowMods = flowCache.get(sw.getId());

        Collections.sort(flowMods, cookieComparator);

        sw.clearAllFlowMods();

        List<OFMessage> messages = new ArrayList<OFMessage>(flowMods.size());
        messages.addAll(flowMods);

        try {
            sw.write(messages, null);
        } catch (IOException e) {
            log.error("Failure writing flow mods to switch {}",
                    HexString.toHexString(sw.getId()));
        }
    }

    private void ensureCacheForSwitch(long dpid) {
        if (!flowCache.containsKey(dpid)) {
            flowCache.put(dpid, new ArrayList<OFFlowMod>());
        }
    }
}
