# stdlib
import logging
import socket
import urllib2
import urlparse

# project
import monasca_agent.common.util as util
import monasca_agent.collector.checks as checks
import monasca_agent.collector.checks.utils as utils

log = logging.getLogger(__name__)

class Apache(checks.AgentCheck):
    """Tracks basic connection/requests/workers metrics
    See http://httpd.apache.org/docs/2.2/mod/mod_status.html for more details
    """
    GAUGES = {'IdleWorkers': 'apache.performance.idle_worker_count',
              'BusyWorkers': 'apache.performance.busy_worker_count',
              'CPULoad': 'apache.performance.cpu_load_perc',
              'Total kBytes': 'apache.net.total_kbytes',
              'Total Accesses': 'apache.net.hits',
              }
    RATES = {'Total kBytes': 'apache.net.kbytes_sec',
             'Total Accesses': 'apache.net.requests_sec'
             }

    def __init__(self, name, init_config, agent_config, instances=None):
        super(Apache, self).__init__(name, init_config, agent_config, instances)
        self.url = None

    def check(self, instance):
        self.url = instance.get('apache_status_url', None)
        if not self.url:
            raise Exception("Missing 'apache_status_url' in Apache config")

        req = urllib2.Request(self.url, None, util.headers(self.agent_config))
        apache_user = instance.get('apache_user', None)
        apache_password = instance.get('apache_password', None)
        if apache_user and apache_password:
            utils.add_basic_auth(req, apache_user, apache_password)
        else:
            log.debug("Not using authentication for Apache Web Server")

        # Submit a service check for status page availability.
        parsed_url = urlparse.urlparse(self.url)
        apache_host = parsed_url.hostname
        apache_port = parsed_url.port or 80
        service_check_name = 'apache.status'

        # Add additional dimensions
        if apache_host == 'localhost':
            # Localhost is not very useful, so get the actual hostname
            apache_host = socket.gethostname()

        dimensions = self._set_dimensions({'apache_host': apache_host,
                                            'apache_port': apache_port,
                                            'service': 'apache',
                                            'component': 'apache'},
                                          instance)

        try:
            request = urllib2.urlopen(req)
        except Exception as e:
            self.log.info(
                "%s is DOWN, error: %s. Connection failed." % (service_check_name, str(e)))
            self.gauge(service_check_name, 1, dimensions=dimensions)
            return services_checks.Status.DOWN, "%s is DOWN, error: %s. Connection failed." % (
                service_check_name, str(e))
        else:
            self.log.debug("%s is UP" % service_check_name)
            self.gauge(service_check_name, 0, dimensions=dimensions)

        response = request.read()
        metric_count = 0

        # Loop through and extract the numerical values
        for line in response.split('\n'):
            values = line.split(': ')
            if len(values) == 2: # match
                metric, value = values
                try:
                    value = float(value)
                except ValueError:
                    continue

                # Send metric as a gauge, if applicable
                if metric in self.GAUGES:
                    metric_count += 1
                    metric_name = self.GAUGES[metric]
                    log.debug('Collecting gauge data for: {0}'.format(metric_name))
                    self.gauge(metric_name, value, dimensions=dimensions)

                # Send metric as a rate, if applicable
                if metric in self.RATES:
                    metric_count += 1
                    metric_name = self.RATES[metric]
                    log.debug('Collecting rate data for: {0}'.format(metric_name))
                    self.rate(metric_name, value, dimensions=dimensions)

        if metric_count == 0:
            if self.url[-5:] != '?auto':
                self.url = '%s?auto' % self.url
                self.warning("Assuming url was not correct. Trying to add ?auto suffix to the url")
                self.check(instance)
            else:
                return services_checks.Status.DOWN, "%s is DOWN, error: No metrics available.".format(service_check_name)
        else:
            log.debug("Collected {0} metrics for {1} Apache Web Server".format(apache_host, metric_count))
