Create an information object:

        - the unique identifier of the information object is specified
          by identifier_ns_uri and uid

        - the timestamp specifies the revision of the information object

        - iobject data must contain the DingoObjDict with the contents
          of the information object that is to be created

        - config_hooks specifies hooking functions for customizing the
          way the DingoObjDict is transformed into facts -- please
          look at the sample import modules for STIX and OpenIOC to
          get an idea of how this is used

        - A list of markings can be provided. Essentially, a marking is simply
          another information object, to which the created information object
          will receive a link. This can be used, e.g., to keep track of provenance
          information (e.g., which import step led to the creation of that information object.

        - Existing defaults for object family and type can be changed via function parameters.
          If nothing is changed, then a DINGO PLACEHOLDER object is created. This special
          object is used by the importer to create objects for forward references found
          during the import.

        Call the function as
    
        (iobject(s),exists) = create_iobject(...)
    
        The 'exists' flag contains information about whether there were already existing
        revisions.

def create_iobject(self,
                       identifier_ns_uri=None,
                       uid=None,
                       timestamp=None,
                       create_timestamp=None,
                       iobject_data=None,
                       config_hooks=None,
                       namespace_dict=None,
                       markings=None,
                       import_older_ts=True,
                       iobject_family_name=DINGOS_IOBJECT_FAMILY_NAME,
                       iobject_family_revision_name=DINGOS_REVISION_NAME,
                       iobject_type_name=DINGOS_PLACEHOLDER_TYPE_NAME,
                       iobject_type_namespace_uri=DINGOS_NAMESPACE_URI,
                       iobject_type_revision_name="",
                       ):
        """
        Create an information object:

        - the unique identifier of the information object is specified
          by identifier_ns_uri and uid

        - the timestamp specifies the revision of the information object

        - iobject data must contain the DingoObjDict with the contents
          of the information object that is to be created

        - config_hooks specifies hooking functions for customizing the
          way the DingoObjDict is transformed into facts -- please
          look at the sample import modules for STIX and OpenIOC to
          get an idea of how this is used

        - A list of markings can be provided. Essentially, a marking is simply
          another information object, to which the created information object
          will receive a link. This can be used, e.g., to keep track of provenance
          information (e.g., which import step led to the creation of that information object.

        - Existing defaults for object family and type can be changed via function parameters.
          If nothing is changed, then a DINGO PLACEHOLDER object is created. This special
          object is used by the importer to create objects for forward references found
          during the import.

        Call the function as
    
        (iobject(s),exists) = create_iobject(...)
    
        The 'exists' flag contains information about whether there were already existing
        revisions.

        """

        #if not timestamp:
        #    raise StandardError("You must supply a timestamp.")

        if not uid:
            raise StandardError("You must supply an identifier.")


        if not identifier_ns_uri:
            raise StandardError("You must supply an identifier namespace.")

        # Fill in parameter defaults that would be mutable.

        if not iobject_data:
            iobject_data = DingoObjDict()

        if not config_hooks:
            config_hooks = {}



        latest_existing_iobject = None
        latest_existing_timestamp = None
        existing_iobject = None

        exists = False
        overwrite = False

        # Check for existing objects of the given uid


        latest_existing_iobject = self.get_latest_revision_of_iobject_by_uid(identifier_ns_uri, uid)

        if latest_existing_iobject:
            latest_existing_timestamp = latest_existing_iobject.timestamp

            if ((not timestamp) and
                iobject_type_name==DINGOS_PLACEHOLDER_TYPE_NAME and
                iobject_type_namespace_uri==DINGOS_NAMESPACE_URI):
                return (latest_existing_iobject, EXIST_ID_AND_EXACT_TIMESTAMP)

        if not timestamp:
            timestamp = create_timestamp


        existing_iobjects = self._DCM['InfoObject'].objects.filter(identifier__uid=uid).filter(
            identifier__namespace__uri=identifier_ns_uri).filter(timestamp=timestamp)

        if existing_iobjects:
            existing_iobject = existing_iobjects[0]

        if existing_iobject:
            if existing_iobject.iobject_type.name == DINGOS_PLACEHOLDER_TYPE_NAME \
                and existing_iobject.iobject_family.name == DINGOS_IOBJECT_FAMILY_NAME:

                overwrite = existing_iobject

                exists = EXIST_PLACEHOLDER
            else:
                exists = EXIST_ID_AND_EXACT_TIMESTAMP
        elif latest_existing_iobject:
            if timestamp < latest_existing_timestamp:
                exists = EXIST_ID_AND_NEWER_TIMESTAMP
            else:
                exists = EXIST_ID_AND_OLDER_TIMESTAMP

        #
        # if uid:
        #     latest_existing_iobject = self.get_latest_revision_of_iobject_by_uid(identifier_ns_uri, uid)
        #
        # if latest_existing_iobject:
        #     latest_existing_timestamp = latest_existing_iobject.timestamp
        #     existing_timestamps = self._DCM['InfoObject'].objects.filter(identifier__uid=uid).filter(
        #         identifier__namespace__uri=identifier_ns_uri).values_list('timestamp', flat=True)
        #
        #     if latest_existing_iobject.iobject_type.name == DINGOS_PLACEHOLDER_TYPE_NAME \
        #         and latest_existing_iobject.iobject_family.name == DINGOS_IOBJECT_FAMILY_NAME:
        #
        #         overwrite = latest_existing_iobject
        #
        #         exists = EXIST_PLACEHOLDER
        #
        #
        #
        #     else:
        #         # We found a non-Placeholder object; let us see, what the timestamp says.


        # If we have found an object of the given id with the exact timestamp or
        # a newer object and the parameter 'import_older_ts' is set to False,
        # we return the latest revision (i.e., object with newest time stamp) of
        # for the given identifier.


        logger.debug("EXISTS flag for %s:%s is: %s" % (identifier_ns_uri, uid, exists))

        if exists==EXIST_ID_AND_EXACT_TIMESTAMP:
            if markings:
            # If markings were given, we create the marking.

                 for marking in markings:
                     Marking2X.objects.create(marked=existing_iobject,
                         marking=marking)

            return (existing_iobject, exists)
        elif  (not import_older_ts and exists == EXIST_ID_AND_NEWER_TIMESTAMP):
            return (latest_existing_iobject, exists)



        else:
            # Otherwise, we create or overwrite the object

            #if not uid:
            #    uid = uuid.uuid1()
            logger.info("Creating %s %s:%s with timestamp %s" % (iobject_type_name,
                                                                 identifier_ns_uri,
                                                                 uid,
                                                                 '{:%d-%m-%Y:%H:%M:%S}.{:03d}'.format(timestamp, timestamp.microsecond // 1000)))

            iobject, created = get_or_create_iobject(uid,
                                                     identifier_ns_uri,
                                                     iobject_type_name,
                                                     iobject_type_namespace_uri,
                                                     iobject_type_revision_name,
                                                     iobject_family_name,
                                                     iobject_family_revision_name,
                                                     identifier_namespace_name=None,
                                                     timestamp=timestamp,
                                                     create_timestamp=create_timestamp,
                                                     overwrite=overwrite,
                                                     dingos_class_map=self._DCM,
                                                    )

            # After creating the object, we write the facts to the object.
            # We overwrite in the special case that a PLACEHOLDER was found.

            if created or overwrite:
                iobject.from_dict(iobject_data, config_hooks=config_hooks, namespace_dict=namespace_dict)


            # We adjust the back pointer in the identifier table to the latest version
            # of the object
            if not exists or exists == EXIST_ID_AND_OLDER_TIMESTAMP or exists == EXIST_PLACEHOLDER:
                iobject.identifier.latest = iobject
                iobject.identifier.save()

            if markings:
                # If markings were given, we create the marking.

                for marking in markings:
                    Marking2X.objects.create(marked=iobject,
                                             marking=marking)

            return (iobject, exists)