# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# 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.

from .openconfig_network_instance import openconfig_network_instance
from pyangbind.lib.serialise     import pybindIETFXMLEncoder

def create_network_instance(parameters,vendor):                   #[L2/L3] Creates a Network Instance as described in: /network_instance[{:s}] 
    NetInstance_name        = parameters['name']           #Retrieves the Name parameter of the NetInstance
    DEL                     = parameters['DEL']            #If the parameter DEL is set to "TRUE" that will mean that is for making a DELETE, ELSE is for creating
    verify = str(parameters)                               #Verify transforms the received parameters into a string format for later making verifications and modifications

    #Create an instance of the YANG model
    Network_Instance = openconfig_network_instance()

    if DEL == True:                                         #DELETE OPERATION
        #Access the entry container
        NetInstance_set = Network_Instance.network_instances.network_instance.add(name = NetInstance_name)

        #Dump the entire instance as RFC 750 XML
        NetInstance_set = pybindIETFXMLEncoder.serialise(Network_Instance)
        #Generic Replaces
        NetInstance_set = NetInstance_set.replace('<openconfig-network-instance xmlns="http://openconfig.net/yang/network-instance">',"")
        NetInstance_set = NetInstance_set.replace('<network-instances>','<network-instances xmlns="http://openconfig.net/yang/network-instance">')
        NetInstance_set = NetInstance_set.replace('<network-instance>','<network-instance xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete">')   
        NetInstance_set = NetInstance_set.replace('</openconfig-network-instance>','') 

    else:                                                   #MERGE OPERATION
        NetInstance_type = parameters['type']                                                                    #Retrieves the Type parameter of the NetInstance
    
        #Access the entry container
        NetInstance_set = Network_Instance.network_instances.network_instance.add(name = NetInstance_name)      
        NetInstance_set.config.name = NetInstance_name                                                          
        if vendor == 'ADVA': NetInstance_set.config.type = NetInstance_type 
        NetInstance_encapsulation = NetInstance_set.encapsulation.config

        #If the description parameter is defined [OPTIONAL-PARAMETER]
        if verify.find('description')>0:
            NetInstance_description = parameters['description']    
            if  len(NetInstance_description) != 0: NetInstance_set.config.description = NetInstance_description   #If description parameter has a value

        #Configuration for L2VSI
        if   "L2VSI" in NetInstance_type:
            if verify.find('mtu')>0:                            #If the MTU parameter is defined with a value
                NetInstance_MTU = parameters['mtu']    
            else:
                NetInstance_MTU = 1500                  #Fixed value of MTU parameter  [Obligatory for L2VSI]
            #Encapsulation
            NetInstance_encapsulation.encapsulation_type = "MPLS"
            #fdb
            NetInstance_fdb = NetInstance_set.fdb.config
            NetInstance_fdb.mac_learning    = True
            NetInstance_fdb.maximum_entries = 1000
            NetInstance_fdb.mac_aging_time  = 300
            #Dump the entire instance as RFC 750 XML
            NetInstance_set = pybindIETFXMLEncoder.serialise(Network_Instance)
            #Specific Replace [Addition of the enabled and MTU variables]
            NetInstance_set = NetInstance_set.replace('</type>','</type>\n        <mtu>'+str(NetInstance_MTU)+'</mtu>\n        <enabled>true</enabled>')   

        #Configuration for L3VRF
        elif   "L3VRF" in NetInstance_type:
            NetInstance_Route_disting = parameters['route_distinguisher']                                       #Retrieves the Route-Distinguisher parameter [Obligatory for L2VSI]
            NetInstance_set.config.route_distinguisher                            = NetInstance_Route_disting
            
            #If the router-id parameter is defined [OPTIONAL-PARAMETER]
            #if verify.find('router_id')>0:
                #NetInstance_Router_ID = parameters['router_id']    
                #if  len(NetInstance_Router_ID) != 0: NetInstance_set.config.router_id = NetInstance_Router_ID     #If router-id parameter has a value

            #Encapsulation
            if vendor == 'ADVA':
                NetInstance_encapsulation.encapsulation_type = "MPLS"
                NetInstance_encapsulation.label_allocation_mode = "INSTANCE_LABEL"    
            #Dump the entire instance as RFC 750 XML
            NetInstance_set = pybindIETFXMLEncoder.serialise(Network_Instance)
            #Specific Replace [Addition of the enabled]
            NetInstance_set = NetInstance_set.replace('</route-distinguisher>','</route-distinguisher>\n        <enabled>true</enabled>')   
        
        #Generic Replaces
        NetInstance_set = NetInstance_set.replace('<openconfig-network-instance xmlns="http://openconfig.net/yang/network-instance">',"")
        NetInstance_set = NetInstance_set.replace('<network-instances>','<network-instances xmlns="http://openconfig.net/yang/network-instance">')
        NetInstance_set = NetInstance_set.replace('</openconfig-network-instance>','')  

    return (NetInstance_set)

def associate_If_to_NI(parameters):                        #[L2/L3] Associates an Interface to a Network Instance as described in: /network_instance[{:s}]/interface[{:s}]
    NetInstance_name = parameters['name']
    NetInstance_ID = parameters['id']
    NetInstance_Interface = parameters['interface']
    NetInstance_SubInterface = parameters['subinterface']

    #Create an instance of the YANG model
    Network_Instance = openconfig_network_instance()

    #Access the entry container
    NetInstance_set = Network_Instance.network_instances.network_instance.add(name = NetInstance_name)
    NetInstance_interface = NetInstance_set.interfaces.interface.add(id = NetInstance_ID)
    NetInstance_interface.config.id = NetInstance_ID
    NetInstance_interface.config.interface = NetInstance_Interface
    NetInstance_interface.config.subinterface = NetInstance_SubInterface
        
    #Dump the entire instance as RFC 750 XML
    NetInstance_set = pybindIETFXMLEncoder.serialise(Network_Instance)
    #Generic Replaces
    NetInstance_set = NetInstance_set.replace('<openconfig-network-instance xmlns="http://openconfig.net/yang/network-instance">',"")
    NetInstance_set = NetInstance_set.replace('<network-instances>','<network-instances xmlns="http://openconfig.net/yang/network-instance">')
    NetInstance_set = NetInstance_set.replace('</openconfig-network-instance>','')   
    return (NetInstance_set)

def add_protocol_NI(parameters):                           #[L3]    Adds a Protocol to a Network Instance as described in: /network_instance[{:s}]/protocols
    NetInstance_name = parameters['name']                        
    Protocol_name    = parameters['protocol_name']         #Protocol can be [STATIC], [DIRECTLY_CONNECTED] or [BGP]
    Identifier       = parameters['identifier']            #Identifier can be [STATIC], [DIRECTLY_CONNECTED] or [BGP]
    DEL              = parameters['DEL']                   #If the parameter DEL is set to "TRUE" that will mean that is for making a DELETE, ELSE is for creating

    if DEL == True:                                        #DELETE OPERATION
        #Create an instance of the YANG model
        Network_Instance = openconfig_network_instance()

        #Access the entry container
        NetInstance_set = Network_Instance.network_instances.network_instance.add(name = NetInstance_name)      
        NetInstance_protocol = NetInstance_set.protocols.protocol.add(name = Protocol_name, identifier = Identifier)    

        #Dump the entire instance as RFC 750 XML
        NetInstance_set = pybindIETFXMLEncoder.serialise(Network_Instance)
        #Delete Replace
        NetInstance_set = NetInstance_set.replace('<protocol>','<protocol xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete">')
        #Generic Replaces
        NetInstance_set = NetInstance_set.replace('<openconfig-network-instance xmlns="http://openconfig.net/yang/network-instance">',"")
        NetInstance_set = NetInstance_set.replace('<network-instances>','<network-instances xmlns="http://openconfig.net/yang/network-instance">')
        NetInstance_set = NetInstance_set.replace('</openconfig-network-instance>','')
    
    else:                                                   #MERGE OPERATION
        #Create an instance of the YANG model
        Network_Instance = openconfig_network_instance()

        #Access the entry container
        NetInstance_set = Network_Instance.network_instances.network_instance.add(name = NetInstance_name)      
        NetInstance_protocol = NetInstance_set.protocols.protocol.add(name = Protocol_name, identifier = Identifier)    
        NetInstance_protocol.config.name = Protocol_name      
        NetInstance_protocol.config.identifier = Identifier
        if Identifier in 'BGP':
            AS          = parameters['as']  
            Router_ID   = parameters['router_id']                        

            NetInstance_protocol.bgp.global_.config.as_=AS 
            NetInstance_protocol.bgp.global_.config.router_id=Router_ID
                
        #Configuration of Table
        NetInstance_tables = NetInstance_set.tables.table.add(protocol = Protocol_name, address_family = "IPV4")       #What about IPV6?
        NetInstance_tables.config.protocol = Protocol_name
        NetInstance_tables.config.address_family = "IPV4"

        #Dump the entire instance as RFC 750 XML
        NetInstance_set = pybindIETFXMLEncoder.serialise(Network_Instance)
        # Specific Replaces
        NetInstance_set = NetInstance_set.replace('<table>\n          <protocol>'+Identifier+'</protocol>','<table> \n\t  <protocol xmlns:oc-pol-types="http://openconfig.net/yang/policy-types">oc-pol-types:'+Identifier+'</protocol>')
        NetInstance_set = NetInstance_set.replace('<config>\n            <protocol>'+Identifier+'</protocol>','<config> \n\t    <protocol xmlns:oc-pol-types="http://openconfig.net/yang/policy-types">oc-pol-types:'+Identifier+'</protocol>')
        NetInstance_set = NetInstance_set.replace('<address-family>IPV4</address-family>','<address-family xmlns:oc-types="http://openconfig.net/yang/openconfig-types">oc-types:'+"IPV4"+'</address-family>')
        NetInstance_set = NetInstance_set.replace('<identifier>'+Identifier+'</identifier>','<identifier xmlns:oc-pol-types="http://openconfig.net/yang/policy-types">oc-pol-types:'+Identifier+'</identifier>')
        #Generic Replaces
        NetInstance_set = NetInstance_set.replace('<openconfig-network-instance xmlns="http://openconfig.net/yang/network-instance">',"")
        NetInstance_set = NetInstance_set.replace('<network-instances>','<network-instances xmlns="http://openconfig.net/yang/network-instance">')
        NetInstance_set = NetInstance_set.replace('</openconfig-network-instance>','')  

    return (NetInstance_set)

def associate_virtual_circuit(parameters):                 #[L2]    Associates a Virtual Circuit as described in: /network_instance[{:s}]/connection_point[VC-1]
    NetInstance_name   = parameters['name']
    ConnectionPoint_ID = parameters['connection_point']
    VirtualCircuit_ID  = parameters['VC_ID']
    RemoteSystem       = parameters['remote_system']

    #Create an instance of the YANG model
    Network_Instance = openconfig_network_instance()

    #Access the entry container
    NetInstance_set = Network_Instance.network_instances.network_instance.add(name = NetInstance_name)
    ConnectionPoint_set = NetInstance_set.connection_points.connection_point.add(connection_point_id = ConnectionPoint_ID)
    ConnectionPoint_set.config.connection_point_id = ConnectionPoint_ID
    Endpoint_set = ConnectionPoint_set.endpoints.endpoint.add(endpoint_id = ConnectionPoint_ID)
    Endpoint_set.config.endpoint_id = ConnectionPoint_ID
    Endpoint_set.config.precedence = 1
    Endpoint_set.config.type = "REMOTE"
    Endpoint_set.remote.config.remote_system = RemoteSystem
    Endpoint_set.remote.config.virtual_circuit_identifier = VirtualCircuit_ID

    #Dump the entire instance as RFC 750 XML
    NetInstance_set = pybindIETFXMLEncoder.serialise(Network_Instance)
    NetInstance_set = NetInstance_set.replace('<openconfig-network-instance xmlns="http://openconfig.net/yang/network-instance">',"")
    NetInstance_set = NetInstance_set.replace('<network-instances>','<network-instances xmlns="http://openconfig.net/yang/network-instance">')
    NetInstance_set = NetInstance_set.replace('</openconfig-network-instance>','')   
    return (NetInstance_set)

def associate_RP_to_NI(parameters):                        #[L3]    Associates a Routing Policy to a Network Instance as described in: /network_instance[{:s}]/inter_instance_policies[{:s}] 
    NetInstance_name = parameters['name']
    verify = str(parameters)                               #Verify transforms the received parameters into a string format for later making verifications and modifications

    #Create an instance of the YANG model
    Network_Instance = openconfig_network_instance()

    #Access the entry container
    NetInstance_set = Network_Instance.network_instances.network_instance.add(name = NetInstance_name)
    Inter_instance = NetInstance_set.inter_instance_policies.apply_policy.config

    #If a Import policy is defined
    if verify.find('import_policy')>0:
        Import = parameters['import_policy']    
        if  len(Import) != 0: Inter_instance.import_policy = Import             #If the import_policy parameter has a value

    #If a Export Policy is defined
    if verify.find('export_policy')>0:
        Export = parameters['export_policy']    
        if  len(Export) != 0: Inter_instance.export_policy = Export             #If the export_policy parameter has a value
        
    #Dump the entire instance as RFC 750 XML
    NetInstance_set = pybindIETFXMLEncoder.serialise(Network_Instance)
    #Generic Replaces
    NetInstance_set = NetInstance_set.replace('<openconfig-network-instance xmlns="http://openconfig.net/yang/network-instance">',"")
    NetInstance_set = NetInstance_set.replace('<network-instances>','<network-instances xmlns="http://openconfig.net/yang/network-instance">')
    NetInstance_set = NetInstance_set.replace('</openconfig-network-instance>','')   
    return (NetInstance_set)

def create_table_conns(parameters):                        #[L3]    Creates Table Connections as described in: /network_instance[{:s}]/table_connections
    NetInstance_name = parameters['name']
    SourceProtocol   = parameters['src_protocol']
    DestProtocol     = parameters['dst_protocol']
    AddrFamily       = parameters['address_family']
    DEL              = parameters['DEL']                   #If the parameter DEL is set to "TRUE" that will mean that is for making a DELETE, ELSE is for creating
    
    #Create an instance of the YANG model
    Network_Instance = openconfig_network_instance()

    if DEL == True:                                         #DELETE OPERATION
        #Access the entry container
        NetInstance_set = Network_Instance.network_instances.network_instance.add(name = NetInstance_name) 

        #Configuration of Table-Connections
        Set_TableConns = NetInstance_set.table_connections.table_connection.add(src_protocol = SourceProtocol, dst_protocol = DestProtocol, address_family = AddrFamily)

        #Dump the entire instance as RFC 750 XML
        NetInstance_set = pybindIETFXMLEncoder.serialise(Network_Instance)

        #Specific Replaces
        NetInstance_set = NetInstance_set.replace('<src-protocol>'+SourceProtocol+'</src-protocol>','<src-protocol xmlns:oc-pol-types="http://openconfig.net/yang/policy-types">oc-pol-types:'+SourceProtocol+'</src-protocol>')
        NetInstance_set = NetInstance_set.replace('<dst-protocol>'+DestProtocol+'</dst-protocol>','<dst-protocol xmlns:oc-pol-types="http://openconfig.net/yang/policy-types">oc-pol-types:'+DestProtocol+'</dst-protocol>')
        NetInstance_set = NetInstance_set.replace('<address-family>'+AddrFamily+'</address-family>','<address-family xmlns:oc-types="http://openconfig.net/yang/openconfig-types">oc-types:'+AddrFamily+'</address-family>')
        #Generic Replaces
        NetInstance_set = NetInstance_set.replace('<openconfig-network-instance xmlns="http://openconfig.net/yang/network-instance">',"")
        NetInstance_set = NetInstance_set.replace('<network-instances>','<network-instances xmlns="http://openconfig.net/yang/network-instance">')
        NetInstance_set = NetInstance_set.replace('<table-connection>','<table-connection xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete">')
        NetInstance_set = NetInstance_set.replace('</openconfig-network-instance>','')

    else:                                                    #MERGE OPERATION
        verify = str(parameters)                             #Verify transforms the received parameters into a string format for later making verifications and modifications

        #Access the entry container
        NetInstance_set = Network_Instance.network_instances.network_instance.add(name = NetInstance_name) 

        #Configuration of Table-Connections
        Set_TableConns = NetInstance_set.table_connections.table_connection.add(src_protocol = "", dst_protocol = "", address_family = "")
        
        Set_TableConns.config.src_protocol   = ""
        Set_TableConns.config.dst_protocol   = ""
        Set_TableConns.config.address_family = ""

        # Default Import Policy (If is defined)
        if verify.find('default_import_policy')>0:
            Def_ImportPolicy = parameters['default_import_policy']    
            if  len(Def_ImportPolicy) != 0: Set_TableConns.config.default_import_policy = Def_ImportPolicy             #If the default_import_policy parameter has a value

        #Dump the entire instance as RFC 750 XML
        NetInstance_set = pybindIETFXMLEncoder.serialise(Network_Instance)

        #Specific Replaces
        NetInstance_set = NetInstance_set.replace('<src-protocol></src-protocol>','<src-protocol xmlns:oc-pol-types="http://openconfig.net/yang/policy-types">oc-pol-types:'+SourceProtocol+'</src-protocol>')
        NetInstance_set = NetInstance_set.replace('<dst-protocol></dst-protocol>','<dst-protocol xmlns:oc-pol-types="http://openconfig.net/yang/policy-types">oc-pol-types:'+DestProtocol+'</dst-protocol>')
        NetInstance_set = NetInstance_set.replace('<address-family></address-family>','<address-family xmlns:oc-types="http://openconfig.net/yang/openconfig-types">oc-types:'+AddrFamily+'</address-family>')
        #Generic Replaces
        NetInstance_set = NetInstance_set.replace('<openconfig-network-instance xmlns="http://openconfig.net/yang/network-instance">',"")
        NetInstance_set = NetInstance_set.replace('<network-instances>','<network-instances xmlns="http://openconfig.net/yang/network-instance">')
        NetInstance_set = NetInstance_set.replace('</openconfig-network-instance>','')   

    return (NetInstance_set)
