def insert(self, app: Application):
        """Insert an Application in the store."""

        if app.pid == 0:
            raise ValueError("Applications must have a valid PID.")

        if not app.desktopid:
            raise ValueError("Applications must have a Desktop identifier.")

        tstart = app.getTimeOfStart()
        tend = app.getTimeOfEnd()
        if tstart > tend:
            raise ValueError("Applications must have valid times of start and "
                             "end.")

        # Get the list of instances for this PID, and find this app's place.
        pids = self.pidStore.get(app.pid, list())  # type: list

        neighbourCheckupIndex = -1
        for (index, bpp) in enumerate(pids):
            bstart = bpp.getTimeOfStart()
            bend = bpp.getTimeOfEnd()

            # other item before ours, keep moving
            if (bend < tstart):
                continue

            # other item after ours, we found our position
            if (bstart > tend):
                pids.insert(index, app)
                neighbourCheckupIndex = index
                break

            # time period conflict, merge apps if same id or alert of a problem
            if (bend >= tstart) or (bstart <= tend):
                if app.hasSameDesktopId(bpp, resolveInterpreter=True):
                    bpp.merge(app)
                    pids[index] = bpp
                    neighbourCheckupIndex = index
                else:
                    # Apps A (which we insert) and B (which we compare to) are
                    # overlapping. We now determine their respective orders to
                    # dispatch them to the appropriate app splitting algorithm.
                    print("Warning: Applications %s and %s overlap on PID %d" %
                          (app.desktopid, bpp.desktopid, app.pid),
                          file=sys.stderr)

                    pids = self.dispatchSplit(pids, index, app, bpp)

                    # Now, merge the inserted app with neighbours if applicable
                    # but note that we don't really know where it is, how many
                    # times it was split, and how much the list has grown. Even
                    # if we pulled that info from the split functions, doing
                    # merges on both edges of the newly inserted sequence would
                    # be more complicated (thus error-prone) than browsing the
                    # whole (short) list of pids. So let's keep it fool-proof.
                    pids = self._mergePidList(pids)

                    # raise ValueError("Applications %s and %s have the same "
                    #                  "PID (%d) and their runtimes overlap:\n"
                    #                  "\t%s \t %s\n\t%s \t %s\nbut they have "
                    #                  "different identities. This is a bug "
                    #                  "in the collected data." % (
                    #                    app.desktopid,
                    #                    bpp.desktopid,
                    #                    app.pid,
                    #                    time2Str(app.getTimeOfStart()),
                    #                    time2Str(app.getTimeOfEnd()),
                    #                    time2Str(bpp.getTimeOfStart()),
                    #                    time2Str(bpp.getTimeOfEnd())))
                break
        # app is the last item on the list!
        else:
            pids.append(app)

        # Now, we check if the neighbours to the newly inserted Application
        # have the same Desktop ID. If they do, and if they are within a given
        # proximity window, we merge the items. This is needed to help Events
        # from Zeitgeist and PreloadLogger to synchronise.
        if neighbourCheckupIndex >= 0:
            pids = self._mergePidItem(pids, neighbourCheckupIndex)

        self.pidStore[app.getPid()] = pids
        self.nameStoreClean = False