#
# Copyright (c) 2011, EPFL (Ecole Politechnique Federale de Lausanne)
# All rights reserved.
#
# Created by Marco Canini, Daniele Venzano, Dejan Kostic, Jennifer Rexford
# Contributed to this file: Peter Peresini
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#   -  Redistributions of source code must retain the above copyright notice,
#      this list of conditions and the following disclaimer.
#   -  Redistributions in binary form must reproduce the above copyright notice,
#      this list of conditions and the following disclaimer in the documentation
#      and/or other materials provided with the distribution.
#   -  Neither the names of the contributors, nor their associated universities or
#      organizations may be used to endorse or promote products derived from this
#      software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#

from lib.model import Model

from of_switch.of_switch import OpenflowSwitch
from clients.tcp_client import TcpClient
from clients.tcp_server import TcpServer
from of_controller.of_controller import EateController

from invariants.eate_route_invariant import EateRouteInvariant

class EateModel_5sw(Model):
	invariants = [EateRouteInvariant]
	generate_inputs = False
	generate_stats = True

	def initTopology(self, topo):
		self.controller = EateController(name="ctrl", ctxt=self.of_context, version=self.config.get("eate_model.app_version"))
		self.of_context.setController(self.controller)
		s_b = OpenflowSwitch(name="s_b", port_count=3+1, of_id=1, expire_entries=self.config.get("model.flow_entry_expiration"))
		s_c = OpenflowSwitch(name="s_c", port_count=4+1, of_id=2, expire_entries=self.config.get("model.flow_entry_expiration"))
		s_i = OpenflowSwitch(name="s_i", port_count=2+1, of_id=3, expire_entries=self.config.get("model.flow_entry_expiration"))
		# xiaoye
		s_al1 = OpenflowSwitch(name="s_al1", port_count=2+1, of_id=4, expire_entries=self.config.get("model.flow_entry_expiration"))
		s_on1 = OpenflowSwitch(name="s_on1", port_count=2+1, of_id=5, expire_entries=self.config.get("model.flow_entry_expiration"))

		h_b1_ip = (10, 0, 0, 11)
		h_x1_ip = (10, 0, 0, 13)
		h_y1_ip = (10, 0, 0, 14)
		h_b1_mac = (0, 0, 0, 0, 0, 0x0B)
		h_x1_mac = (0, 0, 0, 0, 0, 0x0D)
		h_y1_mac = (0, 0, 0, 0, 0, 0x0E)
		# Xiaoye: does not match with the eate application
		#h_x1_mac = (10, 0, 0, 0, 0, 0x0C)
		#h_y1_mac = (10, 0, 0, 0, 0, 0x0D)
		h_b1 = TcpClient(name="h_b1", mymac=h_b1_mac, myip=h_b1_ip, destip=[h_x1_ip, h_y1_ip], pkts=self.config.get("eate_model.connections")) #, h1ip = h_x1_ip, h2ip=h_y1_ip)
		h_x1 = TcpServer(name="h_x1", mymac=h_x1_mac, myip=h_x1_ip)
		h_y1 = TcpServer(name="h_y1", mymac=h_y1_mac, myip=h_y1_ip)
		h_b1.initTopology({0: (s_b, 3)})
		h_x1.initTopology({0: (s_c, 3)})
		h_y1.initTopology({0: (s_c, 4)})
		s_b.initTopology({1: (s_i, 1), 2: (s_al1, 1), 3: (h_b1, 0)})
		s_c.initTopology({1: (s_al1, 2), 2: (s_on1, 2), 3: (h_x1, 0), 4: (h_y1, 0)})
		s_i.initTopology({1: (s_b, 1), 2: (s_on1, 1)})
		# xiaoye
		s_al1.initTopology({1: (s_b, 2), 2: (s_c, 1)})
		s_on1.initTopology({1: (s_i, 2), 2: (s_c, 2)})

		s_b.setController(self.controller)
		s_c.setController(self.controller)
		s_i.setController(self.controller)
		# xiaoye
		s_al1.setController(self.controller)
		s_on1.setController(self.controller)

		self.clients.append(h_b1)
		self.clients.append(h_x1)
		self.clients.append(h_y1)
		self.switches.append(s_b)
		self.switches.append(s_c)
		self.switches.append(s_i)
		# xiaoye
		self.switches.append(s_al1)
		self.switches.append(s_on1)

		self.switches_idx[s_b.getOpenflowID()] = s_b
		self.switches_idx[s_c.getOpenflowID()] = s_c
		self.switches_idx[s_i.getOpenflowID()] = s_i
		# xiaoye
		self.switches_idx[s_al1.getOpenflowID()] = s_al1
		self.switches_idx[s_on1.getOpenflowID()] = s_on1

		h_x1.controller = self.controller
		#start callbacks
		self.controller.start_callbacks.append(lambda: self.controller.install())
		self.controller.start_callbacks.append(lambda: self.controller.addSwitch(s_b))
		self.controller.start_callbacks.append(lambda: self.controller.addSwitch(s_c))
		self.controller.start_callbacks.append(lambda: self.controller.addSwitch(s_i))
		self.controller.start_callbacks.append(lambda: self.controller.addSwitch(s_al1))
		self.controller.start_callbacks.append(lambda: self.controller.addSwitch(s_on1))

	def addNewStats(self, dp_id, stats):
		self.controller.enableAction("port_stats", (dp_id, stats))
