class PrebidTargetingKeyGen(TargetingKeyGen):
    def __init__(self):

        super().__init__()

        # Get DFP key IDs for line item targeting.
        self.hb_bidder_key_id = get_or_create_dfp_targeting_key('hb_bidder')
        self.hb_pb_key_id = get_or_create_dfp_targeting_key('hb_pb')

        # Instantiate DFP targeting value ID getters for the targeting keys.
        self.HBBidderValueGetter = DFPValueIdGetter('hb_bidder')
        self.HBPBValueGetter = DFPValueIdGetter('hb_pb')

        self.hb_bidder_value_id = None
        self.hb_pb_value_id = None

    def set_bidder_value(self, bidder_code):
        print("Setting bidder value to {0}".format(bidder_code))
        self.hb_bidder_value_id = self.HBBidderValueGetter.get_value_id(
            bidder_code)
        return self.hb_bidder_value_id

    def set_price_value(self, price_str):
        self.hb_pb_value_id = self.HBPBValueGetter.get_value_id(price_str)
        return self.hb_pb_value_id

    def get_dfp_targeting(self):
        # Create key/value targeting for Prebid.
        # https://github.com/googleads/googleads-python-lib/blob/master/examples/dfp/v201802/line_item_service/target_custom_criteria.py
        # create custom criterias

        hb_bidder_criteria = {
            'xsi_type': 'CustomCriteria',
            'keyId': self.hb_bidder_key_id,
            'valueIds': [self.hb_bidder_value_id],
            'operator': 'IS'
        }

        hb_pb_criteria = {
            'xsi_type': 'CustomCriteria',
            'keyId': self.hb_pb_key_id,
            'valueIds': [self.hb_pb_value_id],
            'operator': 'IS'
        }

        # The custom criteria will resemble:
        # (hb_bidder_criteria.key == hb_bidder_criteria.value AND
        #    hb_pb_criteria.key == hb_pb_criteria.value)
        top_set = {
            'xsi_type': 'CustomCriteriaSet',
            'logicalOperator': 'AND',
            'children': [hb_bidder_criteria, hb_pb_criteria]
        }

        return top_set
    def __init__(self):

        super().__init__()

        # Get DFP key IDs for line item targeting.
        self.hb_bidder_key_id = get_or_create_dfp_targeting_key('hb_bidder')
        self.hb_pb_key_id = get_or_create_dfp_targeting_key('hb_pb')

        # Instantiate DFP targeting value ID getters for the targeting keys.
        self.HBBidderValueGetter = DFPValueIdGetter('hb_bidder')
        self.HBPBValueGetter = DFPValueIdGetter('hb_pb')

        self.hb_bidder_value_id = None
        self.hb_pb_value_id = None
    def __init__(self):

        super().__init__()

        # Get DFP key IDs for line item targeting.
        self.pwtpid_key_id = get_or_create_dfp_targeting_key(
            'pwtpid', key_type='PREDEFINED')  # bidder
        self.pwtbst_key_id = get_or_create_dfp_targeting_key(
            'pwtbst', key_type='PREDEFINED')  # is pwt
        self.pwtecp_key_id = get_or_create_dfp_targeting_key(
            'pwtecp', key_type='FREEFORM')  # price
        self.pwtplt_key_id = get_or_create_dfp_targeting_key(
            'pwtplt', key_type='PREDEFINED')  # platform

        # Instantiate DFP targeting value ID getters for the targeting keys.
        self.BidderValueGetter = DFPValueIdGetter('pwtpid')
        self.BstValueGetter = DFPValueIdGetter('pwtbst')
        self.PriceValueGetter = DFPValueIdGetter('pwtecp', match_type='PREFIX')
        self.PltValueGetter = DFPValueIdGetter('pwtplt')

        self.pwtbst_value_id = self.BstValueGetter.get_value_id("1")
        self.bidder_criteria = None
        self.platform_criteria = None
        self.price_els = None
        self.jwPriceValueGetter = None
        self.jw_price_key_id = None
        self.creative_type = None
        self.get_custom_targeting = []
    def set_custom_targeting(self, custom_targeting):
        self.custom_targeting = []

        if custom_targeting == None:
            return

        for cc in custom_targeting:
            key_id = get_or_create_dfp_targeting_key(cc[0],
                                                     key_type='FREEFORM')
            value_getter = DFPValueIdGetter(cc[0])
            one_custom_criteria = None

            if isinstance(cc[2], (list, tuple)):
                value_criterias = []
                for val in cc[2]:
                    value_id = value_getter.get_value_id(val)
                    criteria = {
                        'xsi_type': 'CustomCriteria',
                        'keyId': key_id,
                        'valueIds': [value_id],
                        'operator': cc[1]
                    }
                    value_criterias.append(criteria)

                operator = 'OR'
                if cc[1] == 'IS_NOT':
                    operator = 'AND'

                one_custom_criteria = {
                    'xsi_type': 'CustomCriteriaSet',
                    'logicalOperator': operator,
                    'children': value_criterias
                }
            else:
                one_custom_criteria = {
                    'xsi_type': 'CustomCriteria',
                    'keyId': key_id,
                    'valueIds': [value_getter.get_value_id(cc[2])],
                    'operator': cc[1]
                }

            self.custom_targeting.append(one_custom_criteria)
class OpenWrapTargetingKeyGen(TargetingKeyGen):
    def __init__(self):

        super().__init__()

        # Get DFP key IDs for line item targeting.
        self.pwtpid_key_id = get_or_create_dfp_targeting_key(
            'pwtpid', key_type='PREDEFINED')  # bidder
        self.pwtbst_key_id = get_or_create_dfp_targeting_key(
            'pwtbst', key_type='PREDEFINED')  # is pwt
        self.pwtecp_key_id = get_or_create_dfp_targeting_key(
            'pwtecp', key_type='FREEFORM')  # price
        self.pwtplt_key_id = get_or_create_dfp_targeting_key(
            'pwtplt', key_type='PREDEFINED')  # platform

        # Instantiate DFP targeting value ID getters for the targeting keys.
        self.BidderValueGetter = DFPValueIdGetter('pwtpid')
        self.BstValueGetter = DFPValueIdGetter('pwtbst')
        self.PriceValueGetter = DFPValueIdGetter('pwtecp', match_type='PREFIX')
        self.PltValueGetter = DFPValueIdGetter('pwtplt')

        self.pwtbst_value_id = self.BstValueGetter.get_value_id("1")
        self.bidder_criteria = None
        self.platform_criteria = None
        self.price_els = None
        self.jwPriceValueGetter = None
        self.jw_price_key_id = None
        self.creative_type = None
        self.get_custom_targeting = []

    def set_bidder_value(self, bidder_code):
        logger.info("Setting bidder value to {0}".format(bidder_code))

        if bidder_code == None:
            self.bidder_criteria = None
            return

        if isinstance(bidder_code, (list, tuple)):
            # Multiple biders for us to OR to other
            bidder_criteria = []
            for bc in bidder_code:
                value_id = self.BidderValueGetter.get_value_id(bc)
                custom_criteria = {
                    'xsi_type': 'CustomCriteria',
                    'keyId': self.pwtpid_key_id,
                    'valueIds': [value_id],
                    'operator': 'IS'
                }
                bidder_criteria.append(custom_criteria)

            self.bidder_criteria = {
                'xsi_type': 'CustomCriteriaSet',
                'logicalOperator': 'OR',
                'children': bidder_criteria
            }
        else:
            self.bidder_criteria = {
                'xsi_type': 'CustomCriteria',
                'keyId': self.pwtpid_key_id,
                'valueIds': [self.BidderValueGetter.get_value_id(bidder_code)],
                'operator': 'IS'
            }

    def set_creative_type(self, ct):
        self.creative_type = ct

    def set_jwplayer_key(self):
        self.jw_price_key_id = get_or_create_dfp_targeting_key(
            'vpb_pubmatic_bid', key_type='FREEFORM')
        self.jwPriceValueGetter = DFPValueIdGetter('vpb_pubmatic_bid',
                                                   match_type='PREFIX')

    def set_custom_targeting(self, custom_targeting):
        self.custom_targeting = []

        if custom_targeting == None:
            return

        for cc in custom_targeting:
            key_id = get_or_create_dfp_targeting_key(cc[0],
                                                     key_type='FREEFORM')
            value_getter = DFPValueIdGetter(cc[0])
            one_custom_criteria = None

            if isinstance(cc[2], (list, tuple)):
                value_criterias = []
                for val in cc[2]:
                    value_id = value_getter.get_value_id(val)
                    criteria = {
                        'xsi_type': 'CustomCriteria',
                        'keyId': key_id,
                        'valueIds': [value_id],
                        'operator': cc[1]
                    }
                    value_criterias.append(criteria)

                operator = 'OR'
                if cc[1] == 'IS_NOT':
                    operator = 'AND'

                one_custom_criteria = {
                    'xsi_type': 'CustomCriteriaSet',
                    'logicalOperator': operator,
                    'children': value_criterias
                }
            else:
                one_custom_criteria = {
                    'xsi_type': 'CustomCriteria',
                    'keyId': key_id,
                    'valueIds': [value_getter.get_value_id(cc[2])],
                    'operator': cc[1]
                }

            self.custom_targeting.append(one_custom_criteria)

    def set_price_value(self, price_obj):
        self.price_els = self.process_price_bucket(price_obj['start'],
                                                   price_obj['end'],
                                                   price_obj['granularity'])

    def set_platform_targetting(self):

        #get platform value from the creative type
        platform = creativetype_platform_map[self.creative_type]
        platform_value_id = self.PltValueGetter.get_value_id(platform)
        self.platform_criteria = {
            'xsi_type': 'CustomCriteria',
            'keyId': self.pwtplt_key_id,
            'valueIds': [platform_value_id],
            'operator': 'IS'
        }

    def get_dfp_targeting(self):

        # is PWT
        pwt_bst_criteria = {
            'xsi_type': 'CustomCriteria',
            'keyId': self.pwtbst_key_id,
            'valueIds': [self.pwtbst_value_id],
            'operator': 'IS'
        }

        # Generate Ids for all the price elements
        price_value_ids = []
        price_key_id = self.pwtecp_key_id
        price_value_getter = self.PriceValueGetter

        #for JW player set key to 'vpb_pubmatic_bid' for price targetting
        if self.creative_type == constant.JW_PLAYER:
            price_key_id = self.jw_price_key_id
            price_value_getter = self.jwPriceValueGetter

        for p in self.price_els:
            value_id = price_value_getter.get_value_id(p)
            custom_criteria = {
                'xsi_type': 'CustomCriteria',
                'keyId': price_key_id,
                'valueIds': [value_id],
                'operator': 'IS'
            }
            price_value_ids.append(custom_criteria)

        price_set = {
            'xsi_type': 'CustomCriteriaSet',
            'logicalOperator': 'OR',
            'children': price_value_ids
        }

        top_set = {
            'xsi_type': 'CustomCriteriaSet',
            'logicalOperator': 'AND',
            'children': [price_set]
        }

        #pwtpid
        if self.bidder_criteria:
            top_set['children'].append(self.bidder_criteria)

        # dont set other targetting for JW Player
        if self.creative_type is not constant.JW_PLAYER:

            # 2021-03 Randeep and Lloyd confirmed with Mike C that this is not optimal
            # disabling pwtbst for inapp
            #pwtbst
            if self.creative_type is not constant.IN_APP:
                top_set['children'].append(pwt_bst_criteria)

            #pwtplt
            if self.platform_criteria:
                top_set['children'].append(self.platform_criteria)

            #custom targetting
            if len(self.custom_targeting) > 0:
                top_set['children'].extend(self.custom_targeting)

        return top_set

    def process_price_bucket(self, start_index, end_index, granu):

        subCustomValueArray = []
        sub_granu = None

        if granu < 0.10:
            sub_granu = 0.01
        elif granu < 1:
            sub_granu = 0.10
        else:
            sub_granu = 1.00

        # if granu is .20 then $r=0 if .25 then $r=5
        r = (granu * 100) % 10
        k = start_index

        while round(k, 2) < round(end_index, 2):

            #logger.debug("k: {}  end_index: {}".format(k, end_index))
            # if k=1.25 then reminder is 5>0 and for .20 its 0
            if round(k * 100) % 10 > 0 or sub_granu == 0.01:
                if r >= 0:
                    #suppose start_index=0.33 and $end=0.40
                    end = None
                    if sub_granu < 0.10:
                        end = k + (granu * 100) % 10 / 100
                    else:
                        end = k + (10 - (round(k * 100) % 10)) / 100

                    if end >= end_index:
                        end = end_index

                    #TODO
                    if k == 0 and sub_granu == 0.01:
                        k = 0.01

                    v = k
                    while round(v, 2) < round(end, 2):
                        v_str = "{0:.2f}".format(v)
                        #logger.debug("----First---- Custom criteria for Line Item is =  %s", v_str)
                        subCustomValueArray.append(v_str)
                        v = v + 0.01

                    if end + 0.10 <= end_index:
                        k = k + (10 - (round(k * 100) % 10)) / 100
                    else:
                        k = end

                else:  # if r >= 0:
                    #logger.debug("----Second---- Custom criteria for Line Item is =  %f", k)
                    subCustomValueArray.append(k)
                    k = k + sub_granu
            else:  # if round(k*100)%10) > 0 or sub_granu == 0.01
                if r > 0 and round(k + sub_granu, 2) > round(end_index, 2):
                    # To create the custom value from 10 to granularity which can .5, so 10-14
                    g = None
                    if granu > 1:
                        g = 0.10
                    else:
                        g = 0.01

                    v = k
                    while round(v, 2) < round(end_index, 2):
                        temp = v
                        if granu > 1:
                            temp = round(temp, 1)
                        else:
                            temp = round(temp, 2)

                        if v + g > end_index and round(v + g, 2) != round(
                                end_index, 2):
                            subCustomValueArray.append("{0:.2f}".format(temp))
                            #logger.debug("----Third---- Custom criteria for Line Item is =  %.2f", subCustomValueArray[-1])
                            g = 0.01
                            v = v + g
                            continue

                        if g == 0.10:
                            subCustomValueArray.append("{0:.1f}".format(v))
                        else:
                            subCustomValueArray.append("{0:.2f}".format(v))

                        #logger.debug("----Third---- Custom criteria for Line Item is =  %s", subCustomValueArray[-1])
                        v = v + g

                    k = k + sub_granu
                elif k == 0:  # if r > 0 and round(k+sub_granu,2) > round(end_index,2)
                    vEnd = None
                    if sub_granu < 0.10:
                        vEnd = granu
                    else:
                        vEnd = 0.10

                    v = 0.01
                    while v <= vEnd - 0.01:
                        subCustomValueArray.append(str(round(v, 2)))
                        #logger.debug("----Fourth---- Custom criteria for Line Item is =  %s", subCustomValueArray[-1])
                        v = v + 0.01

                    k = k + vEnd
                else:
                    if sub_granu != 1:
                        k = round(k, 1)

                    if ((round(k * 10)) % 10 != 0 or sub_granu == 0.10) and (
                            round(k + sub_granu, 2) <= round(end_index, 2)):
                        subCustomValueArray.append(str(round(k, 2)))
                        #logger.debug("----fifth----1 Custom criteria for Line Item is =  %s", subCustomValueArray[-1])
                    elif (k + sub_granu > end_index
                          and granu == 1) or (granu > 1
                                              and k + sub_granu > end_index):
                        subCustomValueArray.append("{0:.1f}".format(k))
                        #logger.debug("----fifth----2 Custom criteria for Line Item is =  %s", subCustomValueArray[-1])
                    elif sub_granu == 0.10 and round(k + sub_granu, 2) > round(
                            end_index, 2) and end_index * 100 % 10 > 0:
                        subCustomValueArray.append("{0:.2f}".format(k))
                        #logger.debug("----fifth----2.5 Custom criteria for Line Item is =  %s", subCustomValueArray[-1])
                    else:
                        subCustomValueArray.append("{0}.".format(int(k)))
                        #logger.debug("----fifth----3 Custom criteria for Line Item is =  %s", subCustomValueArray[-1])

                    if k >= 1 and round(
                            k * 10
                    ) % 10 == 0 and k + sub_granu <= end_index:  #if $k=2 and end range is 2.57 then it should not increment to 3 while granu is 1
                        k = k + sub_granu
                    elif sub_granu == 0.10 and (
                            round(k + sub_granu, 2) > round(end_index, 2)
                            and end_index * 100 % 10 > 0
                    ):  #$end_index*100%10>0 and $sub_granu==0.10 and $k+$sub_granu>$end_index)
                        k = k + 0.01
                    else:
                        k = round(k, 2) + 0.10

                    if (round(k, 2) != round(end_index, 2)) and (round(
                            k + 0.10, 2) != round(end_index, 2)) and (
                                (k + 0.10 > end_index and granu == 1) or
                                (k + 0.10 > end_index and granu > 1)):
                        subCustomValueArray.append("{0:.2f}".format(k))
                        #logger.debug("----fifth----4 Custom criteria for Line Item is =  %s", subCustomValueArray[-1])
                        k = k + 0.01
        logger.debug("Custom price targetting for each lineitem: {}".format(
            subCustomValueArray))
        return subCustomValueArray
 def set_jwplayer_key(self):
     self.jw_price_key_id = get_or_create_dfp_targeting_key(
         'vpb_pubmatic_bid', key_type='FREEFORM')
     self.jwPriceValueGetter = DFPValueIdGetter('vpb_pubmatic_bid',
                                                match_type='PREFIX')