# Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
#
# 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.
import logging

from ryu.base import app_manager
from time import sleep
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib import addrconv

LOG = logging.getLogger('ryu.app.pon_topology')

class PonTopology13(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

    def __init__(self, *args, **kwargs):
        super(PonTopology13, self).__init__(*args, **kwargs)
        self.mac_to_port = {}

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        datapath = ev.msg.datapath

        # Add/Del upstream/downstream flows (VID 100) in a loop to test for leaks in the OF agent
        #
        # (NOTE: The first del_all_flows does nothing if flows have not been previously 
        # configured in the OF agent)
        while 1:
            self.del_all_flows(datapath)

            self.add_vid_flow(datapath,10000, 1, 129, 100, 0)
            self.add_vid_flow(datapath,10001, 129, 1, 100, 0)

            sleep(1)
            self.send_barrier(datapath)
          
            sleep(5)
        
 
    @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
    def port_status_handler(self, ev):
        LOG.debug('port_status_handler port id: %d', ev.msg.desc.port_no)

    def add_meter(self, datapath, meter_id, rate):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        band = parser.OFPMeterBandDrop(burst_size=0, rate=rate)
        mod = parser.OFPMeterMod(datapath=datapath,
                                 command=ofproto.OFPMC_ADD, 
                                 flags=ofproto.OFPMF_KBPS, 
                                 meter_id=meter_id, 
                                 bands=[band])
        LOG.info("add_meter: meter_id=%d, rate=%d KBPS")
        datapath.send_msg(mod)

    def add_vid_flow(self, datapath, cookie, src_port, dst_port, vid, meter_id):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        actions = [parser.OFPActionOutput(dst_port)]
        if meter_id != 0:
            inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,actions), 
                    parser.OFPInstructionMeter(meter_id)]
        else:
            inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,actions)]

        # NOTE: 0x1000 is OR'd into the vid to set the OFPVID_PRESENT flag in the OpenFlow FLOW_MOD (OFPFC_ADD) 
        # message match field.
        match = parser.OFPMatch(in_port=src_port, vlan_vid=(vid | 0x1000))
        mod = parser.OFPFlowMod(datapath=datapath,
                                cookie=cookie, 
                                cookie_mask=32767, 
                                priority=0, 
                                match=match, 
                                instructions=inst)
        LOG.info("add_vid_flow: src_port=%d dst_port=%d vid=%d meter=%d cookie=%d", 
                 src_port, dst_port, vid, meter_id, cookie)
        datapath.send_msg(mod)

    def del_flow(self, datapath, cookie):
        LOG.info("del_flow: cookie=%d", cookie)
        self._del_flow(datapath, cookie, 32767)

    def del_all_flows(self, datapath):
        LOG.info("del_all_flows")
        # Cookie 0 (argument 2) tells the OF agent to delete all configured flows
        self._del_flow(datapath, 0, 0)

    def _del_flow(self, datapath, cookie, mask):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
 
        mod = parser.OFPFlowMod(
            datapath=datapath, match=None, cookie=cookie, cookie_mask=mask,
            command=ofproto.OFPFC_DELETE)
        datapath.send_msg(mod)
    
    def send_barrier(self, datapath):
        LOG.info("send_barrier")
        datapath.send_barrier()
                   



                   
