def update_or_create(cls, filter_key=None, with_status=False, **kwargs):
        """
        Update or create the element. If the element exists, update it using the
        kwargs provided if the provided kwargs after resolving differences from
        existing values. When comparing values, strings and ints are compared
        directly. If a list is provided and is a list of strings, it will be 
        compared and updated if different. If the list contains unhashable elements,
        it is skipped. To handle complex comparisons, override this method on
        the subclass and process the comparison seperately.
        If an element does not have a `create` classmethod, then it
        is considered read-only and the request will be redirected to
        :meth:`~get`. Provide a ``filter_key`` dict key/value if you want to
        match the element by a specific attribute and value. If no
        filter_key is provided, the name field will be used to find the
        element.
        ::

            >>> host = Host('kali')
            >>> print(host.address)
            12.12.12.12
            >>> host = Host.update_or_create(name='kali', address='10.10.10.10')
            >>> print(host, host.address)
            Host(name=kali) 10.10.10.10

        :param dict filter_key: filter key represents the data attribute and
            value to use to find the element. If none is provided, the name
            field will be used.
        :param kwargs: keyword arguments mapping to the elements ``create``
            method.
        :param bool with_status: if set to True, a 3-tuple is returned with
            (Element, modified, created), where the second and third tuple
            items are booleans indicating the status
        :raises CreateElementFailed: could not create element with reason
        :raises ElementNotFound: if read-only element does not exist
        :return: element instance by type
        :rtype: Element
        """
        updated = False
        # Providing this flag will return before updating and require the calling
        # class to call update if changes were made.
        defer_update = kwargs.pop('defer_update', False)
        if defer_update:
            with_status = True
        
        element, created = cls.get_or_create(filter_key=filter_key, with_status=True, **kwargs)
        if not created:
            for key, value in kwargs.items():
                # Callable, Element or string
                if callable(value):
                    value = value()
                elif isinstance(value, Element):
                    value = value.href
                # Retrieve the 'type' of instance attribute. This is used to
                # serialize attributes that resolve href's to elements. It
                # provides a common structure but also prevents the fetching
                # of the href to element when doing an equality comparison
                attr_type = getattr(type(element), key, None)
                if isinstance(attr_type, ElementRef):
                    attr_name = getattr(attr_type, 'attr', None)
                    if element.data.get(attr_name) != value:
                        element.data[attr_name] = value
                        updated = True
                    continue
                elif isinstance(attr_type, ElementList):
                    value_hrefs = element_resolver(value) # Resolve the elements to href
                    attr_name = getattr(attr_type, 'attr', None)
                    if set(element.data.get(attr_name, [])) != set(value_hrefs):
                        element.data[attr_name] = value_hrefs
                        updated = True
                    continue
                
                # Type is not 'special', therefore we are expecting only strings,
                # integer types or list of strings. Complex data structures
                # will be handled later through encapsulation and __eq__, __hash__
                # for comparison. The keys value type here is going to assume the
                # provided value is of the right type as the key may not necessarily
                # exist in the cached json.
                if isinstance(value, (string_types, int)): # also covers bool
                    val = getattr(element, key, None)
                    if val != value:
                        element.data[key] = value
                        updated = True
                elif isinstance(value, list) and all(isinstance(s, string_types) for s in value):
                    # List of simple strings (assuming the attribute is also!)
                    if set(value) ^ set(element.data.get(key, [])):
                        element.data[key] = value
                        updated = True
                # Complex lists, objects, etc will fall down here and be skipped.
                # To process these, provide defer_update=True, override update_or_create,
                # process the complex object deltas and call update()
            
            if updated and not defer_update:
                element.update()
        
        if with_status:
            return element, updated, created
        return element