#
# Copyright 2013 IBM Corp
#
# 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 json
import logging
import logging.handlers

from oslo_log import log
from urllib import parse as urlparse

from ceilometer import publisher

LOG = log.getLogger(__name__)


class FilePublisher(publisher.ConfigPublisherBase):
    """Publisher metering data to file.

    The file publisher pushes metering data into a file. The file name and
    location should be configured in ceilometer pipeline configuration file.
    If a file name and location is not specified, this File Publisher will not
    log any meters other than log a warning in Ceilometer log file.

    To enable this publisher, add the following section to the
    /etc/ceilometer/pipeline.yaml file or simply add it to an existing
    pipeline::

        -
            name: meter_file
            meters:
                - "*"
            publishers:
                - file:///var/test?max_bytes=10000000&backup_count=5&json

    File path is required for this publisher to work properly. If max_bytes
    or backup_count is missing, FileHandler will be used to save the metering
    data. If max_bytes and backup_count are present, RotatingFileHandler will
    be used to save the metering data. The json argument is used to explicitly
    ask ceilometer to write json into the file.
    """

    def __init__(self, conf, parsed_url):
        super().__init__(conf, parsed_url)

        self.publisher_logger = None
        path = parsed_url.path
        if not path:
            LOG.error('The path for the file publisher is required')
            return

        rfh = None
        max_bytes = 0
        backup_count = 0
        self.output_json = None
        # Handling other configuration options in the query string
        if parsed_url.query:
            params = urlparse.parse_qs(parsed_url.query,
                                       keep_blank_values=True)
            if "json" in params:
                self.output_json = True
            if params.get('max_bytes') and params.get('backup_count'):
                try:
                    max_bytes = int(params.get('max_bytes')[0])
                    backup_count = int(params.get('backup_count')[0])
                except ValueError:
                    LOG.error('max_bytes and backup_count should be '
                              'numbers.')
                    return
        # create rotating file handler
        rfh = logging.handlers.RotatingFileHandler(
            path, encoding='utf8', maxBytes=max_bytes,
            backupCount=backup_count)

        self.publisher_logger = logging.Logger('publisher.file')
        self.publisher_logger.propagate = False
        self.publisher_logger.setLevel(logging.INFO)
        rfh.setLevel(logging.INFO)
        self.publisher_logger.addHandler(rfh)

    def publish_samples(self, samples):
        """Send a metering message for publishing

        :param samples: Samples from pipeline after transformation
        """
        if self.publisher_logger:
            for sample in samples:
                if self.output_json:
                    self.publisher_logger.info(json.dumps(sample.as_dict()))
                else:
                    self.publisher_logger.info(sample.as_dict())

    def publish_events(self, events):
        """Send an event message for publishing

        :param events: events from pipeline after transformation
        """
        if self.publisher_logger:
            for event in events:
                if self.output_json:
                    self.publisher_logger.info(json.dumps(event.as_dict(),
                                                          default=str))
                else:
                    self.publisher_logger.info(event.as_dict())
