# -*- coding: utf-8 -*-
import os
import difflib
import logging
import subprocess

import xml.etree.ElementTree as ET

import salt.exceptions as exc


log = logging.getLogger(__name__)


def runcli(*args, **kwargs):
    args = ('/usr/local/sbin/jenkins-cli',) + args

    if not os.path.exists(args[0]):
        raise exc.CommandExecutionError('jenkins-cli is not installed')

    input_ = kwargs.get('input_')
    if input_:
        try:
            input_ = input_.encode('utf-8')
        except Exception, e:
            log.debug("%r", input_)
            log.error("%s", e)

    p = subprocess.Popen(
        args,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        stdin=subprocess.PIPE)

    if input_:
        p.stdin.write(input_)

    p.stdin.close()
    p.wait()

    stdout = p.stdout.read()
    log.debug("runcli stdout:\n%s", stdout)

    stderr = p.stderr.read()
    log.debug("runcli stderr:\n%s", stderr)

    if p.returncode != 0:
        message = stdout + "\n" + stderr
        raise exc.CommandExecutionError(message)

    return stdout


def formatdiff(old, new):
    diff = difflib.unified_diff(old.splitlines(True), new.splitlines(True),
                                fromfile='old', tofile='new')
    diff = list(diff)
    if not diff:
        return

    last_line = diff[-1]
    if not last_line.endswith(u'\n'):
        last_line += u'\n\ No newline at end of file\n'
    diff[-1] = last_line
    return u''.join(diff)


def restart(wait_online=True):
    """Restarts jenkins and returns stderr or None.

    wait_online
        Boolean flag if we want to wait online after install (default: True).
    """

    runcli('safe-restart')

    if wait_online:
        runcli('wait-master-online')


def update_or_create_xml(name, xml, old=None,
                         object_=None, get=None, create=None, update=None):
    runcli = __salt__['jenkins.runcli']  # noqa
    test = __opts__['test']  # noqa

    ret = {
        'name': name,
        'changes': {},
        'result': False,
        'comment': ''
    }

    get = get or 'get-%s' % object_

    if type(xml) is unicode:
        # Wish the xml declared as UTF-8.
        xml = xml.encode('utf-8')

    if type(xml) is str:
        try:
            xml = ET.fromstring(xml)
        except Exception as e:
            ret['comment'] = str(e.message)
            ret['comment'] += '\n'
            ret['comment'] += xml.decode('utf-8')
            return ret

    new = """<?xml version="1.0" encoding="UTF-8"?>\n"""
    new += ET.tostring(xml.find('.'), encoding='utf-8')
    # Follow jenkins-cli convention
    new = new.replace(" />", "/>")
    new = new.decode('utf-8')

    try:
        if old is None:
            old = runcli(get, name)
        # Jenkins sometimes returns \n after <?xml
        old = old.replace("?><", "?>\n<")
        old = old.decode('utf-8')
    except Exception:
        old = u''
        command = create or 'create-%s' % object_
    else:
        command = update or 'update-%s' % object_

    if new == old:
        ret['comment'] = 'Not changed.'
        ret['result'] = True
        return ret

    # Compat with salt.states.format_log
    ret['changes']['xmldiff'] = formatdiff(old, new).encode('utf-8')

    log.debug(u"Sending %s %s:\n%s", command, name, new)

    if test:
        ret['result'] = None
        return ret

    # update if not testing
    try:
        runcli(command, name, input_=new)
    except exc.CommandExecutionError as e:
        ret['comment'] = e.message
        return ret

    ret['result'] = True
    return ret

@@ -366,24 +366,57 @@
 nstalled')%0A%0A
+    log.info(%22Calling %25r%22, args)%0A
     input_ =
@@ -846,24 +846,40 @@
 tdout.read()
+.decode('utf-8')
 %0A    log.deb
@@ -873,32 +873,33 @@
 )%0A    log.debug(
+u
 %22runcli stdout:%5C
@@ -941,16 +941,32 @@
 r.read()
+.decode('utf-8')
 %0A    log
@@ -972,16 +972,17 @@
 g.debug(
+u
 %22runcli 
@@ -1057,16 +1057,17 @@
 tdout + 
+u
 %22%5Cn%22 + s
@@ -2912,59 +2912,88 @@
     
-    old = old.decode('utf-8')%0A    except Exception:
+except Exception, e:%0A        log.info(%22Job %25r not found, creation: %25r%22, name, e)
 %0A   

Decode jenkins output