# Copyright 2011 Dorgival Guedes
# Copyright 2013 James McCauley
#
# Licensed 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.

"""
Tracks host location and configuration

Keep track of hosts in the network, where they are and how they are
configured (at least MAC/IP addresses).

For the time being, it keeps tables with the information; later, it should
transfer that information to Topology and handle just the actual
discovery/update of host information.

Timer configuration can be changed when needed (e.g., for debugging) using
the launch facility (check timeoutSec dict and PingCtrl.pingLim).

You can set various timeouts from the commandline.  Names and defaults:
  arpAware=60*2    Quiet ARP-responding entries are pinged after this
  arpSilent=60*20  This is for uiet entries not known to answer ARP
  arpReply=4       Time to wait for an ARP reply before retrial
  timerInterval=5  Seconds between timer routine activations
  entryMove=60     Minimum expected time to move a physical entry

Good values for testing:
  --arpAware=15 --arpSilent=45 --arpReply=1 --entryMove=4

You can also specify how many ARP pings we try before deciding it failed:
  --pingLim=2
"""

from pox.core import core

from pox.lib.addresses import EthAddr
from pox.lib.packet.ethernet import ethernet
from pox.lib.packet.ipv4 import ipv4
from pox.lib.packet.arp import arp

from pox.lib.recoco import Timer
from pox.lib.revent import Event, EventHalt

import pox.openflow.libopenflow_01 as of

import pox.openflow.discovery as discovery

from pox.lib.revent.revent import *

import time

import pox
log = core.getLogger()

# Times (in seconds) to use for differente timouts:
timeoutSec = dict(
  arpAware=60*2,   # Quiet ARP-responding entries are pinged after this
  arpSilent=60*20, # This is for uiet entries not known to answer ARP
  arpReply=4,      # Time to wait for an ARP reply before retrial
  timerInterval=5, # Seconds between timer routine activations
  entryMove=60     # Minimum expected time to move a physical entry
  )

# Address to send ARP pings from.
# The particular one here is just an arbitrary locally administered address.
DEFAULT_ARP_PING_SRC_MAC = '02:00:00:00:be:ef'


class HostEvent (Event):
  """
  Event when hosts join, leave, or move within the network
  """
  def __init__ (self, entry, new_dpid = None, new_port = None, join = False,
      leave = False, move = False):
    super(HostEvent,self).__init__()
    self.entry = entry
    self.join = join
    self.leave = leave
    self.move = move

    assert sum(1 for x in [join,leave,move] if x) == 1

    # You can alter these and they'll change where we think it goes...
    self._new_dpid = new_dpid
    self._new_port = new_port

    #TODO: Allow us to cancel add/removes

  @property
  def new_dpid (self):
    """
    New DPID for move events"
    """
    assert self.move
    return self._new_dpid

  @property
  def new_port (self):
    """
    New port for move events"
    """
    assert self.move
    return self._new_port


class Alive (object):
  """
  Holds liveliness information for MAC and IP entries