#   The class of the e2e slice resource context generation job unit


import os
from copy import deepcopy
from collections import OrderedDict

from common.util import get_class_func_name, cata_download, del_dir_or_file, \
                            SLICE_RES_STATUS_DEPLOYING, CONTEXT_NAMESPACE_SLICE_RES, \
                            VNF_RES_STATUS_DEPLOYING, \
                            PREFIX_VDU, PREFIX_CP, PREFIX_INTERNAL_VL, \
                            SUFFIX_PRIVATE_IP, SUFFIX_PUBLIC_IP, SUFFIX_SCALE_URL
from common.yaml_util import yaml_ordered_dump as yaml_dump
from event_framework.job_unit import JobUnit
from event_framework.event import META_EVENT_TYPE, META_EVENT_PRODUCER


__author__ = 'chenxin'    
__date__ = '2017-4-18'  
__version__ = 1.0



class E2ESliceResCtxGenerateJob(JobUnit):
    
    '''
    this job is used to generate the e2e slice resource context when slice resource deploy is requested.
    the works done by this job are:
        allocate a slice resource id and return
        insert output resources into vnfd
        generate and store the slice resource context, consists with:
            sliceResId:
            sliceResGlobalStatus:
            nsdContent:
            vnfResInfo:
                (vnfNodeId):
                    dcResId:
                    vimDriverId:
                    vnfResStatus:
                    vnfResId:
                    relatedVimInfo:
                        vimType:
                        vimMgrEndPoint:
                    vnfdContent:
                    vduInfo:
                        (vduId):
                            flavorInfo:
                                relatedVimType:
                                flavorType:
                            loginInfo:
                                username:
                                password:
                            vmList:
                    cpInfo:
                        (cpId):
                            privateIpInfo:
                                relatedOutputId:
                                ipList:
                            publicIpInfo:
                                relatedOutputId:
                                ipList:
                    spInfo:
                        (spId):
                            relatedOutputId:
                            triggerUrl:
                    
    Note the resource context only contains the datacenter related resource information.
    this job output:
        'slice_res_id': the id of the slice resource been processed
    '''
    
    
    def __init__(self, task_unit, job_n, **params):
        
        '''
        params:
            task_unit: the task unit instance this job unit belongs to
            job_n: the name of this job given in the job unit sequence
            params: other parameters may used for extension
        '''
        super(E2ESliceResCtxGenerateJob, self).__init__(task_unit, job_n, **params)

    def execute_job(self, **params):

        '''
        called by the task unit to start the execution of this job.
        derived job unit class should override this method to deploy own processing logic

        '''
        try:
            self.event = self.task_unit.get_triggered_event()
            self._alloc_slice_res_id()
            self._init_slice_res_ctx()
            r_data = {'status': 'request accepted'}
            r_data.update({'sliceResId': self.slice_res_id})
            print '#### GenE2ESliceResCtxJob: create a slice resource id: ' + self.slice_res_id 
            self.event.set_return_data_syn(r_data)

            self._enrich_slice_res_ctx()
            self._output_params(**{'slice_res_id': self.slice_res_id})
            self._execution_finish()
        except Exception, e:
            print Exception, ':', e, \
                      ' in %s:%s' % get_class_func_name(self)
            self.event.set_return_data_asyn({'status': 'request failed'})
            self._execution_exception(Exception, e)
    
    def _alloc_slice_res_id(self):

        '''
        allocate the slice resource id 

        '''
        id_gen = self.task_unit.task_scheduler.global_id_generator
        slice_id = self.event.get_event_data().get('sliceId', None)
        self.slice_res_id = slice_id
        #   self.slice_res_id = id_gen.get_context_item_id_without_env(slice_id)
    
    def _init_slice_res_ctx(self):

        '''
        init the slice resource context according to the data
        contained in the slice resource deploy request

        '''
        slice_res_ctx = OrderedDict()
        event_d = self.event.get_event_data()
        slice_res_ctx['sliceResId'] = self.slice_res_id
        slice_res_ctx['sliceResGlobalStatus'] = SLICE_RES_STATUS_DEPLOYING
        slice_res_ctx['nsdContent'] = event_d['nsdContent']
        ctx_loc = slice_res_ctx.setdefault('vnfResInfo', OrderedDict())

        for vnf_nid, vnf_res in event_d['vnfInfo'].items():
            loc = ctx_loc.setdefault(vnf_nid, OrderedDict())
            loc['dcResId'] = vnf_res['dcResId']
            loc['vimDriverId'] = self._get_vim_driver_id(dc_res_id=loc['dcResId'])
            loc['vnfResStatus'] = VNF_RES_STATUS_DEPLOYING
            loc['vnfResId'] = None
            loc['relatedVimInfo'] = OrderedDict()
            loc['relatedVimInfo']['vimType'], \
            loc['relatedVimInfo']['vimMgrEndPoint'] = None, None
            loc['vnfdContent'] = vnf_res['vnfdContent']
            loc['vduInfo'] = OrderedDict()
            loc['cpInfo'] = OrderedDict()
            loc['spInfo'] = OrderedDict()
            print '####debug: loc#######'
            print loc
        ctx_store = self.task_unit.task_scheduler.context_store
        ctx_store.add_context_item(slice_res_ctx, CONTEXT_NAMESPACE_SLICE_RES, 
                                   self.slice_res_id, item_id_n='sliceResId')
 
    
    def _get_vim_driver_id(self, **params):

        return self.task_unit.task_scheduler.get_vim_driver_by_dc_id(params['dc_res_id'])
    
    def _enrich_slice_res_ctx(self):

        '''
        enrich resource context, including:
            generate vdu and cp info by reading the vnfd
            add output resources into the vnfd
        '''
        ctx_store = self.task_unit.task_scheduler.context_store
        ctx_h = ctx_store.get_context_item_process_handler(CONTEXT_NAMESPACE_SLICE_RES, self.slice_res_id)
        slice_res_ctx = ctx_h.get_context_item()
        
        for vnf_nid, vnf_res_v in slice_res_ctx['vnfResInfo'].items():
            vnfd = vnf_res_v['vnfdContent']
            vdu_ctx_loc = vnf_res_v['vduInfo']
            cp_ctx_loc = vnf_res_v['cpInfo']
            sp_ctx_loc = vnf_res_v['spInfo']
            vnfd_output_loc = vnfd['topology_template'].setdefault('outputs', OrderedDict())
            vnfd_node_loc = vnfd['topology_template']['node_templates']
            vnfd_policy_loc = vnfd['topology_template'].get('policies', {})
            vnfd_sub_map_req_loc = vnfd['topology_template']['substitution_mappings']\
                                                            ['requirements']

            ############# add login info resource to the vnfd ###############
            vdu_type_pro_loc = vnfd['node_types']['tosca.nodes.nfv.VDU.Customized']['properties']
            vdu_type_pro_loc['username'] = OrderedDict()
            vdu_type_pro_loc['username']['type'] = 'string'
            vdu_type_pro_loc['username']['description'] = 'the username used to login the vdu instances'
            vdu_type_pro_loc['password'] = OrderedDict()
            vdu_type_pro_loc['password']['type'] = 'string'
            vdu_type_pro_loc['password']['description'] = 'the username used to login the vdu instances'
            for k, v in vnfd_node_loc.items():
                
                if PREFIX_VDU in k:
                    loc = vdu_ctx_loc.setdefault(k, OrderedDict())
                    loc['flavorInfo'] = OrderedDict()
                    loc['flavorInfo']['relatedVimType'] = \
                           v['properties']['vim_type']
                    loc['flavorInfo']['flavorType'] = \
                           v['properties']['flavor_type']
                    loc['loginInfo'] = OrderedDict()
                    usr, passwd = self._gen_vdu_login_info(vdu_id=k)
                    loc['loginInfo']['username'], \
                    loc['loginInfo']['password'] = usr, passwd
                    v['properties']['username'], \
                    v['properties']['password'] = usr, passwd
                    loc['vmList'] = []
                
                if PREFIX_CP in k:
                    loc = cp_ctx_loc.setdefault(k, OrderedDict())
                    pri_ip_loc = loc.setdefault('privateIpInfo', OrderedDict())
                    pub_ip_loc = loc.setdefault('publicIpInfo', OrderedDict())

            #########   add cp ip output resource to the vnfd ################
                    #vl_info = v['requirements'].get('virtualLink', [])
                    #if len(vl_info) > 0:
                    loc = vnfd_output_loc.setdefault(k + SUFFIX_PRIVATE_IP, OrderedDict())
                    pri_ip_loc['relatedOutputId'] = k + SUFFIX_PRIVATE_IP
                    pri_ip_loc['ipList'] = []
                    loc['node'] = k
                    loc['attr'] = 'private_ip'

            for v in vnfd_sub_map_req_loc.values():
                cp = v.strip('[]').split(',')[0]
                loc = vnfd_output_loc.setdefault(cp + SUFFIX_PUBLIC_IP, OrderedDict())
                pub_ip_loc = cp_ctx_loc[cp]['publicIpInfo']
                pub_ip_loc['relatedOutputId'] = cp + SUFFIX_PUBLIC_IP
                pub_ip_loc['ipList'] = []
                loc['node'] = cp
                loc['attr'] = 'public_ip'

            ########## add scaling policy output resource to the vnfd ########
            for sp_id, v in vnfd_policy_loc.items():
                loc = vnfd_output_loc.setdefault(sp_id + SUFFIX_SCALE_URL, OrderedDict())
                sp_url_loc = sp_ctx_loc.setdefault(sp_id, OrderedDict())
                sp_url_loc['relatedOutputId'] = sp_id + SUFFIX_SCALE_URL
                sp_url_loc['triggerUrl'] = None
                loc['node'] = sp_id
                loc['attr'] = 'alarm_url'
        
        #   print '#### GenE2ESliceResCtxJob: slice resource context created: '
        #   print yaml_dump(slice_res_ctx, default_flow_style=False)
        ctx_h.process_finish()
        
    
    def _gen_vdu_login_info(self, **params):

        '''
        generate the vdu login information
        return:
            (username, password)

        '''
        vdu_id = params['vdu_id']
        if 'MME' in vdu_id:
            return ('root', '123')
        if 'HSS' in vdu_id:
            return ('root', '123')
        if 'SPGW' in vdu_id:
            return ('root', '123')
        if 'mgmtAgent' in vdu_id:
            return ('root', '123')
        return ('5gslm', 'iaa')
    
