def _create_all_new_chains(self, converter) -> Tuple[List[Converter], List[Converter],
                                                         List[Converter], List[Converter]]:
        """
        Creates all specific and generic chains that may be built by adding this converter to the existing chains.

        :param converter:
        :return: generic_chains, generic_nonstrict_chains, specific_chains, specific_nonstrict_chains
        """

        specific_chains, specific_nonstrict_chains, generic_chains, generic_nonstrict_chains = [], [], [], []

        if converter.is_generic():
            # the smaller chain : the singleton :)
            generic_chains.append(ConversionChain(initial_converters=[converter], strict_chaining=True))
        else:
            specific_chains.append(ConversionChain(initial_converters=[converter], strict_chaining=True))


        # 1) create new specific chains by adding this converter at the beginning or end of all *non-generic* ones
        # -- non-strict
        new_c_at_end_ns = []
        new_c_at_beginning_ns = []
        if not self.strict:
            # then there are non-strict chains already. Try to connect to them
            for existing_specific_nonstrict in self._specific_non_strict_conversion_chains:
                if converter.can_be_appended_to(existing_specific_nonstrict, strict=False):
                    if ConversionChain.are_worth_chaining(existing_specific_nonstrict, converter):
                        new_c_at_end_ns.append(ConversionChain.chain(existing_specific_nonstrict, converter,
                                                                     strict=False))
                if existing_specific_nonstrict.can_be_appended_to(converter, strict=False):
                    if ConversionChain.are_worth_chaining(converter, existing_specific_nonstrict):
                        new_c_at_beginning_ns.append(ConversionChain.chain(converter, existing_specific_nonstrict,
                                                                           strict=False))

        # -- strict
        new_c_at_end = []
        new_c_at_beginning = []
        for existing_specific in self._specific_conversion_chains:
            # first try *strict* mode
            if converter.can_be_appended_to(existing_specific, strict=True):
                if ConversionChain.are_worth_chaining(existing_specific, converter):
                    new_c_at_end.append(ConversionChain.chain(existing_specific, converter, strict=True))
            elif (not self.strict) and converter.can_be_appended_to(existing_specific, strict=False):
                if ConversionChain.are_worth_chaining(existing_specific, converter):
                    new_c_at_end_ns.append(ConversionChain.chain(existing_specific, converter, strict=False))

            if existing_specific.can_be_appended_to(converter, strict=True):
                if ConversionChain.are_worth_chaining(converter, existing_specific):
                    # TODO this is where when chaining a generic to a specific, we would actually have to restrict it
                    # note: but maybe we dont care since now this is checked and prevented in the convert() method
                    new_c_at_beginning.append(ConversionChain.chain(converter, existing_specific, strict=True))
            elif (not self.strict) and existing_specific.can_be_appended_to(converter, strict=False):
                if ConversionChain.are_worth_chaining(converter, existing_specific):
                    # TODO this is where when chaining a generic to a specific, we would actually have to restrict it
                    # note: but maybe we dont care since now this is checked and prevented in the convert() method
                    new_c_at_beginning_ns.append(ConversionChain.chain(converter, existing_specific, strict=False))

        # append to the right list depending on the nature of this converter
        if converter.is_generic():
            generic_chains += new_c_at_end
            generic_nonstrict_chains += new_c_at_end_ns
        else:
            specific_chains += new_c_at_end
            specific_nonstrict_chains += new_c_at_end_ns
        # common for both types
        specific_chains += new_c_at_beginning
        specific_nonstrict_chains += new_c_at_beginning_ns

        # by combining all created chains into a big one
        for a in new_c_at_end:
            for b in new_c_at_beginning:
                b_ = b.remove_first()
                if b_.can_be_appended_to(a, strict=True):
                    if ConversionChain.are_worth_chaining(a, b_):
                        specific_chains.append(ConversionChain.chain(a, b_, strict=True))
            for b in new_c_at_beginning_ns:
                b_ = b.remove_first()
                if b_.can_be_appended_to(a, strict=False):
                    if ConversionChain.are_worth_chaining(a, b_):
                        specific_nonstrict_chains.append(ConversionChain.chain(a, b_, strict=False))
        for a in new_c_at_end_ns:
            for b in (new_c_at_beginning_ns + new_c_at_beginning):
                b_ = b.remove_first()
                if b_.can_be_appended_to(a, strict=False):
                    if ConversionChain.are_worth_chaining(a, b_):
                        specific_nonstrict_chains.append(ConversionChain.chain(a, b_, strict=False))

        # by inserting this converter at the beginning of an existing *generic*
        if converter.is_generic():
            # we want to avoid chaining generic converters together
            pass
        else:
            new_c_at_beginning_generic = []
            new_c_at_beginning_generic_ns = []
            for existing_specific in self._generic_conversion_chains:
                # start with strict
                if existing_specific.can_be_appended_to(converter, strict=True):
                    if ConversionChain.are_worth_chaining(converter, existing_specific):
                        new_c_at_beginning_generic.append(ConversionChain.chain(converter, existing_specific,
                                                                                strict=True))
                elif (not self.strict) and existing_specific.can_be_appended_to(converter, strict=False):
                    if ConversionChain.are_worth_chaining(converter, existing_specific):
                        new_c_at_beginning_generic_ns.append(ConversionChain.chain(converter, existing_specific,
                                                                                   strict=False))

            for existing_specific_ns in self._generic_nonstrict_conversion_chains:
                if existing_specific_ns.can_be_appended_to(converter, strict=False):
                    if ConversionChain.are_worth_chaining(converter, existing_specific_ns):
                        new_c_at_beginning_generic_ns.append(ConversionChain.chain(converter, existing_specific_ns,
                                                                               strict=False))
            generic_chains += new_c_at_beginning_generic
            generic_nonstrict_chains += new_c_at_beginning_generic_ns

            # by combining specific and generic created chains into a big one
            for a in new_c_at_end:
                for b in new_c_at_beginning_generic:
                    b_ = b.remove_first()
                    if b_.can_be_appended_to(a, strict=True):
                        if ConversionChain.are_worth_chaining(a, b_):
                            generic_chains.append(ConversionChain.chain(a, b_, strict=True))
                for b in new_c_at_beginning_generic_ns:
                    b_ = b.remove_first()
                    if b_.can_be_appended_to(a, strict=False):
                        if ConversionChain.are_worth_chaining(a, b_):
                            generic_nonstrict_chains.append(ConversionChain.chain(a, b_, strict=False))
            for a in new_c_at_end_ns:
                for b in (new_c_at_beginning_generic_ns + new_c_at_beginning_generic):
                    b_ = b.remove_first()
                    if b_.can_be_appended_to(a, strict=False):
                        if ConversionChain.are_worth_chaining(a, b_):
                            generic_nonstrict_chains.append(ConversionChain.chain(a, b_, strict=False))

        return generic_chains, generic_nonstrict_chains, specific_chains, specific_nonstrict_chains