###################################################################################
# LAVA QA tool
# Copyright (C) 2015, 2016 Collabora Ltd.

# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  US
###################################################################################

import http.client
import xmlrpc.client
import urllib.parse as up
import requests
import lqa_tool.version as lqa_version


class RequestsTransport(xmlrpc.client.Transport):
    """ Custom transport factory that uses requests instead of httplib """
    def __init__(self, *, scheme='https', timeout=20.0, verify_ssl_cert=True, **kwargs):
        super().__init__(**kwargs)
        self.scheme = scheme
        self.user_agent = f'{self.user_agent} lqa/{lqa_version.__version__}'
        self.timeout = timeout
        self.verify_ssl_cert = verify_ssl_cert

    def request(self, host, handler, request_body, verbose=False):
        """ Make an xmlrpc request. """
        headers = {
            'User-Agent': self.user_agent,
            'Content-Type': 'text/xml',
            'Accept-Encoding': 'gzip',
        }
        url = f'{self.scheme}://{host}{handler}'
        response = requests.post(
            url,
            data=request_body,
            headers=headers,
            timeout=self.timeout,
            verify=self.verify_ssl_cert,
        )
        if response.status_code == 200:
            self.verbose = verbose
            return self.parse_response(response)
        raise xmlrpc.client.ProtocolError(url, response.status_code, response.text, response.headers)

    def parse_response(self, response):
        """ Parse the xmlrpc response. """
        p, u = self.getparser()
        p.feed(response.text)
        p.close()
        return u.close()


class Connection(object):
    """Class handling the connection to the LAVA server."""

    def __init__(self, api_url):
        self._api_url = api_url
        transport = RequestsTransport(scheme=up.urlparse(api_url).scheme, use_datetime=True)
        self._conn = xmlrpc.client.ServerProxy(
            self._api_url, use_datetime=True, allow_none=True, transport=transport
        )

    def submit_job(self, data):
        return self._conn.scheduler.submit_job(data)

    def cancel_job(self, job_id):
        return self._conn.scheduler.cancel_job(job_id)

    def resubmit_job(self, job_id):
        return self._conn.scheduler.resubmit_job(job_id)

    def streams(self):
        return self._conn.dashboard.streams()

    def make_stream(self, pathname, description):
        return self._conn.dashboard.make_stream(pathname, description)

    def job_details(self, job_id):
        return self._conn.scheduler.job_details(job_id)

    def job_output(self, job_id, offset=0):
        return self._conn.scheduler.job_output(job_id, offset).data

    def job_status(self, job_id):
        try:
            return self._conn.scheduler.job_state(job_id)
        except AttributeError:
            return self._conn.scheduler.job_status(job_id)

    def get_device_status(self, hostname):
        return self._conn.scheduler.get_device_status(hostname)

    def get_bundle(self, sha1):
        return self._conn.dashboard.get(sha1)

    def get_testjob_metadata(self, job_id):
        return self._conn.results.get_testjob_metadata(job_id)

    def get_testjob_results_csv(self, job_id):
        return self._conn.results.get_testjob_results_csv(job_id)

    def get_testjob_results_yaml(self, job_id):
        return self._conn.results.get_testjob_results_yaml(job_id)

    def get_testsuite_results_csv(self, job_id, suite_name):
        return self._conn.results.get_testsuite_results_csv(job_id, suite_name)

    def get_testsuite_results_yaml(self, job_id, suite_name):
        return self._conn.results.get_testsuite_results_yaml(job_id, suite_name)

    def get_testcase_results_csv(self, job_id, suite_name, case_name):
        return self._conn.results.get_testcase_results_csv(job_id, suite_name,
                                                           case_name)

    def get_testcase_results_yaml(self, job_id, suite_name, case_name):
        return self._conn.results.get_testcase_results_yaml(job_id, suite_name,
                                                            case_name)

    def get_filter_results(self, filter_name, count=10, offset=0):
        return self._conn.dashboard.get_filter_results(filter_name, count, offset)

    def get_filter_results_since(self, filter_name, since):
        return \
            self._conn.dashboard.get_filter_results_since(filter_name, since)

    def bundles(self, pathname):
        return self._conn.dashboard.bundles(pathname)

    def all_jobs(self):
        return self._conn.scheduler.all_jobs()

    def all_devices(self):
        return self._conn.scheduler.all_devices()

    def put_into_maintenance_mode(self, hostname, reason, notify):
        return self._conn.scheduler.put_into_maintenance_mode(hostname, reason,
                                                              notify)

    def put_into_online_mode(self, hostname, reason, skip_health_check):
        return self._conn.scheduler.put_into_online_mode(hostname, reason,
                                                         skip_health_check)

    def whoami(self):
        return self._conn.system.whoami()

    def version(self):
        return self._conn.dashboard.version()
