.. versionadded:: 2017.7

    Compares Zabbix object definition against existing Zabbix object.

    :param defined: Zabbix object definition taken from sls file.
    :param existing: Existing Zabbix object taken from result of an API call.
    :param return_old_value: Default False. If True, returns dict("old"=old_val, "new"=new_val) for rollback purpose.
    :return: Params that are different from existing object. Result extended by
        object ID can be passed directly to Zabbix API update method.

def compare_params(defined, existing, return_old_value=False):
    '''
    .. versionadded:: 2017.7

    Compares Zabbix object definition against existing Zabbix object.

    :param defined: Zabbix object definition taken from sls file.
    :param existing: Existing Zabbix object taken from result of an API call.
    :param return_old_value: Default False. If True, returns dict("old"=old_val, "new"=new_val) for rollback purpose.
    :return: Params that are different from existing object. Result extended by
        object ID can be passed directly to Zabbix API update method.
    '''
    # Comparison of data types
    if not isinstance(defined, type(existing)):
        raise SaltException('Zabbix object comparison failed (data type mismatch). Expecting {0}, got {1}. '
                            'Existing value: "{2}", defined value: "{3}").'.format(type(existing),
                                                                                   type(defined),
                                                                                   existing,
                                                                                   defined))

    # Comparison of values
    if not salt.utils.data.is_iter(defined):
        if six.text_type(defined) != six.text_type(existing) and return_old_value:
            return {'new': six.text_type(defined), 'old': six.text_type(existing)}
        elif six.text_type(defined) != six.text_type(existing) and not return_old_value:
            return six.text_type(defined)

    # Comparison of lists of values or lists of dicts
    if isinstance(defined, list):
        if len(defined) != len(existing):
            log.info('Different list length!')
            return {'new': defined, 'old': existing} if return_old_value else defined
        else:
            difflist = []
            for ditem in defined:
                d_in_e = []
                for eitem in existing:
                    comp = compare_params(ditem, eitem, return_old_value)
                    if return_old_value:
                        d_in_e.append(comp['new'])
                    else:
                        d_in_e.append(comp)
                if all(d_in_e):
                    difflist.append(ditem)
            # If there is any difference in a list then whole defined list must be returned and provided for update
            if any(difflist) and return_old_value:
                return {'new': defined, 'old': existing}
            elif any(difflist) and not return_old_value:
                return defined

    # Comparison of dicts
    if isinstance(defined, dict):
        try:
            # defined must be a subset of existing to be compared
            if set(defined) <= set(existing):
                intersection = set(defined) & set(existing)
                diffdict = {'new': {}, 'old': {}} if return_old_value else {}
                for i in intersection:
                    comp = compare_params(defined[i], existing[i], return_old_value)
                    if return_old_value:
                        if comp or (not comp and isinstance(comp, list)):
                            diffdict['new'].update({i: defined[i]})
                            diffdict['old'].update({i: existing[i]})
                    else:
                        if comp or (not comp and isinstance(comp, list)):
                            diffdict.update({i: defined[i]})
                return diffdict

            return {'new': defined, 'old': existing} if return_old_value else defined

        except TypeError:
            raise SaltException('Zabbix object comparison failed (data type mismatch). Expecting {0}, got {1}. '
                                'Existing value: "{2}", defined value: "{3}").'.format(type(existing),
                                                                                       type(defined),
                                                                                       existing,
                                                                                       defined))