'''
Many aspects of the salt payload need to be managed, from the return of
encrypted keys to general payload dynamics and packaging, these happen
in here
'''

import sys
import salt.log
from salt._compat import pickle

log = salt.log.logging.getLogger(__name__)

try:
    # Attempt to import msgpack
    import msgpack
    # There is a serialization issue on ARM and potentially other platforms
    # for some msgpack bindings, check for it
    if msgpack.loads(msgpack.dumps([1,2,3])) is None:
        raise ImportError
except ImportError:
    # Fall back to msgpack_pure
    try:
        import msgpack_pure as msgpack
    except ImportError:
        # TODO: Come up with a sane way to get a configured logfile
        #       and write to the logfile when this error is hit also
        log_format = '[%(levelname)-8s] %(message)s'
        salt.log.setup_console_logger(log_format=log_format)
        log.fatal('Unable to import msgpack or msgpack_pure python modules')
        sys.exit(1)


def package(payload):
    '''
    This method for now just wraps msgpack.dumps, but it is here so that
    we can make the serialization a custom option in the future with ease.
    '''
    return msgpack.dumps(payload)


def unpackage(package_):
    '''
    Unpackages a payload
    '''
    return msgpack.loads(package_, use_list=True)


def format_payload(enc, **kwargs):
    '''
    Pass in the required arguments for a payload, the enc type and the cmd,
    then a list of keyword args to generate the body of the load dict.
    '''
    payload = {'enc': enc}
    load = {}
    for key in kwargs:
        load[key] = kwargs[key]
    payload['load'] = load
    return package(payload)


class Serial(object):
    '''
    Create a serialization object, this object manages all message
    serialization in Salt
    '''
    def __init__(self, opts):
        if isinstance(opts, dict):
            self.serial = self.opts.get('serial', 'msgpack')
        elif isinstance(opts, str):
            self.serial = opts
        else:
            self.serial = 'msgpack'

    def loads(self, msg):
        '''
        Run the correct loads serialization format
        '''
        if self.serial == 'msgpack':
            return msgpack.loads(msg, use_list=True)
        elif self.serial == 'pickle':
            try:
                return pickle.loads(msg)
            except Exception:
                return msgpack.loads(msg, use_list=True)

    def load(self, fn_):
        '''
        Run the correct serialization to load a file
        '''
        data = fn_.read()
        fn_.close()
        return self.loads(data)

    def dumps(self, msg):
        '''
        Run the correct dumps serialization format
        '''
        if self.serial == 'pickle':
            return pickle.dumps(msg)
        else:
            return msgpack.dumps(msg)

    def dump(self, msg, fn_):
        '''
        Serialize the correct data into the named file object
        '''
        fn_.write(self.dumps(msg))
        fn_.close()


class SREQ(object):
    '''
    Create a generic interface to wrap salt zeromq req calls. 
    '''
    def __init__(self, master, serial='msgpack', timeout=10, linger=0):
        self.master = master
        self.serial = Serial(serial)
        context = zmq.Context()
        self.socket = context.socket(zmq.REQ)
        self.socket.linger = linger
        self.socket.connect(master)

    def send(enc, load):
        '''
        Takes two arguments, the encryption type and the base payload
        '''
        payload = {'enc': enc}
        if enc == 'clear':
            eload = load
        elif enc == 'aes':
            eload = load
        elif enc == 'pub':
            eload = load
        payload['load'] = eload
        package = self.serial.dumps(payload)
        self.socket.send(package)
        poller = zmq.Poller()
        poller.register(self.socket, zmq.POLLIN)
        if not poller.poll(timeout):
            raise SaltReqTimeoutError
        ret = self.serial.loads(socket.recv())
        poller.unregister(self.socket)
        return ret

    def send_auto(payload):
        '''
        Detect the encryption type based on the payload
        '''
        enc = payload.get('enc', 'clear')
        load = payload.get('load', {})
        return self.send(enc, load)

@@ -157,34 +157,93 @@
 ''%0A%0A
-import sys%0Aimport salt.log
+# Import python libs%0Aimport sys%0A%0A# Import salt libs%0Aimport salt.log%0Aimport salt.crypt
 %0Afro
@@ -272,16 +272,17 @@
 pickle%0A%0A
+%0A
 log = sa
@@ -3222,20 +3222,8 @@
 ck',
- timeout=10,
  lin
@@ -3230,16 +3230,16 @@
 ger=0):%0A
+
         
@@ -3465,24 +3465,45 @@
 nd(enc, load
+, tries=1, timeout=10
 ):%0A        '
@@ -3622,164 +3622,8 @@
 nc%7D%0A
-        if enc == 'clear':%0A            eload = load%0A        elif enc == 'aes':%0A            eload = load%0A        elif enc == 'pub':%0A            eload = load%0A
     
@@ -3644,17 +3644,16 @@
 oad'%5D = 
-e
 load%0A   

fix timeout, add tries