# Copyright (C) 2010, 2011, 2012, 2013, 2014 Intel, Inc.
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of the GNU General Public License
#    as published by the Free Software Foundation; version 2 of the License.
#
#    This program 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 General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
"""A build trigger"""

import os
import sys
import base64
import json
from time import sleep, strftime, gmtime
from jenkinsapi.jenkins import Jenkins
import urllib3

from common.utils import unicode_to_str
# remote jenkins build job
import requests
import ast
import zlib

# set default char-set endcoding to utf-8
reload(sys)
sys.setdefaultencoding('utf-8') # pylint: disable-msg=E1101


class LocalError(Exception):
    """Local error exception."""
    pass

class JenkinsError(Exception):
    """Local error exception."""
    pass

def trigger_next(job_name, data, show=True, extra_params={}, compress=False):
    """Trigger next job"""

    print "====LOG:TRIGGER_NEXT:%s =======================" % job_name.upper()
    if compress:
        _trigger_info = base64.b64encode(zlib.compress(json.dumps(data)))
    else:
        _trigger_info = base64.b64encode(json.dumps(data))

    with open("%s.env" % job_name, 'w') as info_file:
        info_file.write('TRIGGER_INFO=%s\n' % \
               _trigger_info)
        for k in extra_params:
            v = extra_params[k]
            info_file.write('%s=%s\n' % (k, v))
    if show == True:
        for key in data.keys():
            print "%s='%s'" % (key, data[key])
        for k in extra_params:
            v = extra_params[k]
            print "%s='%s'" % (k, v)
    else:
        print data.keys()
        print extra_params.keys()
    print "====LOG:TRIGGER_NEXT:======================end=="

def trigger_info(_trigger_info, show=True):
    "Return a trigger info dict"""

    print "====LOG:TRIGGER_INFO:==========================="

    try:
        data = zlib.decompress(base64.b64decode(_trigger_info))
    except Exception, error:
        data = base64.b64decode(_trigger_info)

    content_dict = unicode_to_str(json.loads(data))
    if show == True:
        print json.dumps(content_dict, indent=4)
    print "====LOG:TRIGGER_INFO:======================end=="
    return content_dict

def get_jenkins_instance(job, cred=None):

    if cred is None:
        cred = {'url': os.getenv('JENKINS_URL'), \
                'username': os.getenv('JENKINS_USER'), \
                'password': os.getenv('JENKINS_PASS')}

    try:
        jenkins = Jenkins(cred['url'], cred['username'], cred['password'])
    except Exception, error:
        raise JenkinsError("Can't connect to jenkins: %s" % str(error))

    if job not in jenkins:
        raise JenkinsError("Job %s doesn't exist" % job)

    return jenkins

def trigger_jenkins_build(job, parameters, cred=None, block=False):

    jenkins = get_jenkins_instance(job, cred)

    qitem = jenkins[job].invoke(block=block, build_params=parameters)

    if block:
        build = qitem.get_build()
        return build.get_number(), build.get_status(), build.get_console()
    else:
        return qitem.queue_id

def monitor_jenkins_build_with_queue_id(job, queue_id=None, cred=None):

    jenkins = get_jenkins_instance(job, cred)

    ret_val = {'queue_id': queue_id,
               'build_number': None,
               'building': True,
               'result': None,
               'returns': None}

    # Check queue first
    if queue_id:
        for pending_build in jenkins.get_queue().get_queue_items_for_job(job):
            if pending_build.queue_id == queue_id:
                return ret_val

    # Check build
    j = jenkins.get_job(job)
    builds = j.poll(tree='builds[number,building,queueId,result,actions[parameters[name,value]]]')
    for build in builds['builds']:
        if (queue_id and str(queue_id) == str(build['queueId'])):
            ret_val['build_number'] = build['number']
            if build['building']:
                return ret_val
            else:
                ret_val['building'] = False
                ret_val['result'] = build['result']
                # Get PBS_RETURN_VALUE
                for action in build['actions']:
                    if 'parameters' not in action:
                        continue
                    for parameter in action['parameters']:
                        if 'name' in parameter and parameter['name'] == 'PBS_RETURN_VALUE':
                            ret_val['returns'] = parameter['value']
                return ret_val

    return ret_val

def monitor_jenkins_build(job, queue_id=None, cred=None, retry_seconds=10, get_return=False):

    while True:
        sys.stdout.flush()
        sleep(retry_seconds)
        ret = monitor_jenkins_build_with_queue_id(job, queue_id=queue_id, cred=cred)
        if ret['building']:
            continue
        if get_return == True:
            return ret['result'], ret['returns']
        else:
            return ret['result']

def get_jenkins_build_data(job=None, build_num=None, cred=None, tree=None):

    jenkins = get_jenkins_instance(job, cred)

    j = jenkins.get_job(job)
    if tree is None:
        tree = ['number', 'building', 'queueId', 'result', 'timestamp', 'duration', 'actions[text,parameters[name,value]]']
    builds = j.poll(tree='builds[%s]' % ','.join(tree))

    for build in builds['builds']:
        if build_num and build_num == str(build['number']):
            return build
        elif build_num is None:
            return builds['builds']

def remote_jenkins_build_job( url, username, password, jobname, token=None, data=None, files=None):
    """ remote jenkins build job"""
    print 'remote jenkins job '
    if url and username and password and jobname:
        if token:
            url = '%s/job/%s/buildWithParameters?token=%s' \
                  %(url, jobname, token)
        else:
            url = '%s/job/%s/buildWithParameters?' \
                  %(url, jobname)
        try:

            if files:
                file_formdata_arr = []
                for (key, filename) in files:
                    file_formdata_arr.append((key, (filename, open(filename,'r').read())))

                filedata, content_type = urllib3.encode_multipart_formdata(file_formdata_arr)

                resp = requests.post(url, params=data, data=filedata,
                                    auth=(username, password),
                                    headers={"content-type":content_type}
                                    )
            else :
                resp = requests.post(url, params=data,
                                    auth=(username, password),
                                    )
            status_code = resp.status_code
            print status_code
        except requests.exceptions.Timeout as e:
            print(e)
        except requests.exceptions.ConnectionError as e:
            print(e)
        except Exception as e:
            raise Exception(e)

def get_pending_builds_with_parameter():

    cred = {'url': os.getenv('JENKINS_URL_INTERNAL'), \
            'username': os.getenv('JENKINS_USER'), \
            'password': os.getenv('JENKINS_PW')}

    path = '%s/queue/api/python' % (cred['url'])
    path = '%s?tree=items[id,task[name],actions[parameters[name,value]]]' % path
    resp = requests.post(path, auth=requests.auth.HTTPBasicAuth(cred['username'], cred['password']))
    ret_obj = ast.literal_eval(resp.text)
    return ret_obj.get("items")

def cancel_pending_build_with_id(queue_id):

    cred = {'url': os.getenv('JENKINS_URL_INTERNAL'), \
            'username': os.getenv('JENKINS_USER'), \
            'password': os.getenv('JENKINS_PW')}

    path = '%s/queue/cancelItem?id=%s' % (cred['url'], queue_id)
    resp = requests.post(path, auth=requests.auth.HTTPBasicAuth(cred['username'], cred['password']))

def get_running_builds_with_parameter(job_name):

    cred = {'url': os.getenv('JENKINS_URL_INTERNAL'), \
            'username': os.getenv('JENKINS_USER'), \
            'password': os.getenv('JENKINS_PW')}

    path = '%s/job/%s/api/python?tree=builds[number,building,queueId,actions[parameters[name,value]]]' % (cred['url'], job_name)
    #path = '%s?tree=items[id,task[name],actions[parameters[name,value]]]' % path
    resp = requests.post(path, auth=requests.auth.HTTPBasicAuth(cred['username'], cred['password']))
    conv_text = resp.text
    ret_obj = ast.literal_eval(conv_text)
    return ret_obj

def cancel_running_build_with_id(job_name, build_id):

    cred = {'url': os.getenv('JENKINS_URL_INTERNAL'), \
            'username': os.getenv('JENKINS_USER'), \
            'password': os.getenv('JENKINS_PW')}

    path = '%s/job/%s/%s/stop' % (cred['url'], job_name, build_id)
    resp = requests.post(path, auth=requests.auth.HTTPBasicAuth(cred['username'], cred['password']))

