# Copyright 2010 New Relic, Inc.
#
# 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 newrelic.common.encoding_utils import (obfuscate, deobfuscate,
        json_encode, json_decode, base64_encode, base64_decode)


# CatHeaderMixin assumes the mixin class also inherits from TimeTrace
class CatHeaderMixin(object):
    cat_id_key = 'X-NewRelic-ID'
    cat_transaction_key = 'X-NewRelic-Transaction'
    cat_appdata_key = 'X-NewRelic-App-Data'
    cat_synthetics_key = 'X-NewRelic-Synthetics'
    cat_metadata_key = 'x-newrelic-trace'
    cat_distributed_trace_key = 'newrelic'
    settings = None

    def __enter__(self):
        result = super(CatHeaderMixin, self).__enter__()
        if result is self and self.transaction:
            self.settings = self.transaction.settings or None
        return result

    def process_response_headers(self, response_headers):
        """
        Decode the response headers and create appropriate metrics based on the
        header values. The response_headers are passed in as a list of tuples.
        [(HEADER_NAME0, HEADER_VALUE0), (HEADER_NAME1, HEADER_VALUE1)]

        """

        settings = self.settings
        if not settings:
            return

        if not settings.cross_application_tracer.enabled:
            return

        appdata = None
        try:
            for k, v in response_headers:
                if k.upper() == self.cat_appdata_key.upper():
                    appdata = json_decode(deobfuscate(v,
                            settings.encoding_key))
                    break

            if appdata:
                self.params['cross_process_id'] = appdata[0]
                self.params['external_txn_name'] = appdata[1]
                self.params['transaction_guid'] = appdata[5]

        except Exception:
            pass

    def process_response_metadata(self, cat_linking_value):
        payload = base64_decode(cat_linking_value)
        nr_headers = json_decode(payload)
        self.process_response_headers(nr_headers.items())

    @classmethod
    def generate_request_headers(cls, transaction):
        """
        Return a list of NewRelic specific headers as tuples
        [(HEADER_NAME0, HEADER_VALUE0), (HEADER_NAME1, HEADER_VALUE1)]

        """

        if transaction is None:
            return []

        settings = transaction.settings

        nr_headers = []

        if settings.distributed_tracing.enabled:
            transaction.insert_distributed_trace_headers(nr_headers)

        elif settings.cross_application_tracer.enabled:
            transaction.is_part_of_cat = True
            encoded_cross_process_id = obfuscate(settings.cross_process_id,
                    settings.encoding_key)
            nr_headers.append((cls.cat_id_key, encoded_cross_process_id))

            transaction_data = [transaction.guid, transaction.record_tt,
                    transaction.trip_id, transaction.path_hash]
            encoded_transaction = obfuscate(json_encode(transaction_data),
                    settings.encoding_key)
            nr_headers.append(
                    (cls.cat_transaction_key, encoded_transaction))

        if transaction.synthetics_header:
            nr_headers.append(
                    (cls.cat_synthetics_key, transaction.synthetics_header))

        return nr_headers

    @staticmethod
    def _convert_to_cat_metadata_value(nr_headers):
        payload = json_encode(nr_headers)
        cat_linking_value = base64_encode(payload)
        return cat_linking_value

    @classmethod
    def get_request_metadata(cls, transaction):
        nr_headers = dict(cls.generate_request_headers(transaction))

        if not nr_headers:
            return None

        return cls._convert_to_cat_metadata_value(nr_headers)
