class ResponseFilter:
    @staticmethod
    def filter(responses: list):
        retained_responses = []
        filtered_responses = []
        for response in responses:
            if (response.question is not None and response.question_instance is not None and
                    response.classification is not None and response.classification_instance is not None):
                retained_responses.append(response)
            else:
                filtered_responses.append(response)
        return [retained_responses, filtered_responses]


class ResponseMapper:
    @staticmethod
    def map_classification(responses: list, classifications_dict: dict) -> bool:
        for response in responses:
            classification_text = response.classification_text.lower()
            classification_base_text = response.classification_base_text.lower()
            reply_text = response.classification_instance_text.lower()
            reply_corrected_text = response.classification_instance_corrected_text.lower()

            if classification_text in classifications_dict.keys():
                classification = classifications_dict[classification_text]
                response.classification = classification
                instance_found = False
                for instance in classification.individuals:
                    if reply_text == instance.label:
                        instance_found = True
                        response.classification_instance = instance
                        response.classification_note = ''
                        break
                if not instance_found:
                    # correct spelling and try to match it again
                    corrected_instance_found = False
                    for instance in classification.individuals:
                        if reply_corrected_text == instance.label:
                            corrected_instance_found = True
                            response.classification_instance = instance
                            response.classification_note = \
                                (f'Classification "{classification_text}" matched to '
                                 f'ontology classification "{classification.label}" with exact matching, '
                                 f'reply "{reply_text}" matched with instance with label "{instance.label}" '
                                 f'after spelling correction.')
                            break
                    if not corrected_instance_found:
                        response.classification_note = \
                            (f'Classification "{classification_text}" matched to '
                             f'ontology classification "{classification.label}" with exact matching, '
                             f'but reply "{reply_text}" not among classification instances.')
            else:
                # search the base classification name from the import file among the base ontology classification names
                found_classification = False
                for c in classifications_dict.values():
                    if classification_base_text == c.base_label:
                        found_classification = True
                        response.classification = c
                        instance_found = False
                        for instance in c.individuals:
                            if reply_text == instance.label:
                                instance_found = True
                                response.classification_instance = instance
                                response.classification_note = \
                                    (f'Classification "{classification_text}" matched to '
                                     f'ontology classification "{c.label}" with approximate matching.')
                                break
                        if not instance_found:
                            # correct spelling and try to match it again
                            corrected_instance_found = False
                            for instance in c.individuals:
                                if reply_corrected_text == instance.label:
                                    corrected_instance_found = True
                                    response.classification_instance = instance
                                    response.classification_note = \
                                        (f'Classification "{classification_text}" matched to '
                                         f'ontology classification "{c.label}" with approximate matching, '
                                         f'reply "{reply_text}" matched with instance with label "{instance.label}" '
                                         f'after spelling correction.')
                                    break
                            if not corrected_instance_found:
                                response.classification_note = \
                                    (f'Classification "{classification_text}" matched to '
                                     f'ontology classification "{c.label}" with approximate matching, '
                                     f'but reply "{reply_text}" not among classification instances.')
                        break

                if not found_classification:
                    response.classification_note = \
                        (f'Classification "{classification_text}" not found in the ontology '
                         f'with either exact or approximate matching.')

    @staticmethod
    def map_question(responses: list, questions_dict: dict) -> bool:
        for response in responses:
            if response.question_instance is not None:
                continue
            question_text = response.question_text.lower()
            for q in questions_dict.values():
                if question_text == q.label:
                    assert len(q.individuals) == 1
                    response.question = q
                    response.question_instance = q.individuals[0]
                    response.question_note = ''
                    break
                else:
                    response.question_note = \
                        f'Question "{question_text}" not found in the ontology.'

    @staticmethod
    def map_multiple_choice_question(responses: list, questions_dict: dict) -> bool:
        for response in responses:
            if response.question_instance is not None:
                continue
            question_text = response.question_base_text.lower()
            for q in questions_dict.values():
                if question_text == q.label:
                    assert len(q.individuals) == 1
                    response.question = q
                    response.question_instance = q.individuals[0]
                    response.question_note = ''
                    break
            else:
                response.question_note = \
                    f'Question "{question_text}" not found in the ontology.'

    @staticmethod
    def map_bipolar_question(responses: list, questions_dict: dict) -> bool:
        for response in responses:
            if response.question_instance is not None:
                continue
            question_text = response.question_base_text.lower()
            for q in questions_dict.values():
                if question_text == q.label:
                    assert len(q.individuals) == 1
                    response.question = q
                    response.question_instance = q.individuals[0]
                    response.question_note = ''
                    break
            else:
                response.question_note = \
                    f'Question "{question_text}" not found in the ontology.'
