def validate_nesting(self):
        '''
        Reviews the story tree and validates associated arc
        elements are nested appropriately. Returns a dict of errors.
        '''
        error_dict = {}
        story_root = self.story_tree_root
        story_nodes = story_root.get_descendants().prefetch_related('arcelementnode_set').filter(depth=2)

        def parse_children(node_object, seq=0):
            '''
            Recursive method to check all generations of a node for arc
            elements.
            '''
            returnable_ae_dict = {}
            if node_object.get_children_count():
                for node in node_object.get_children().prefetch_related('arcelementnode_set'):
                    if node.get_children_count():
                        local_ae_dict, newseq = parse_children(node, seq)
                        for arc in local_ae_dict.keys():
                            if arc not in returnable_ae_dict.keys():
                                returnable_ae_dict[arc] = []
                            returnable_ae_dict[arc] = returnable_ae_dict[arc] + (local_ae_dict[arc])
                        seq = newseq
                    else:
                        local_arc_elements = node.arcelementnode_set.all()
                        for ae in local_arc_elements:
                            if ae.is_milestone:
                                logger.debug('Found a milestone to sequence.')
                                if ae.arc not in returnable_ae_dict.keys():
                                    returnable_ae_dict[ae.arc] = []
                                returnable_ae_dict[ae.arc].append({
                                    ae.arc_element_type: seq,
                                })
                                logger.debug('Appended an element of type %s  from arc %s at sequence %d' % (
                                    ae.arc_element_type,
                                    ae.arc.name,
                                    seq))
                        seq += 1
            return returnable_ae_dict, seq

        arcs_out_of_sequence = []
        arc_milestone_elements = {}
        x = 0
        arcs_with_nest_conflicts = []
        for node in story_nodes:
            arc_elements_found, x = parse_children(node, x)
            for arc in arc_elements_found.keys():
                if arc not in arc_milestone_elements.keys():
                    arc_milestone_elements[arc] = []
                arc_milestone_elements[arc] = arc_milestone_elements[arc] + arc_elements_found[arc]
        arc_entry_exit = {}
        for arc, elements in arc_milestone_elements.items():
            z = {}
            last_local_seq = 0
            logger.debug("There are %d elements to parse" % len(elements))
            for ae_elements in elements:
                logger.debug('Parsing %s' % ae_elements)
                for k, v in ae_elements.items():
                    z[k] = v
            logger.debug('%s' % OrderedDict(sorted(z.items(), key=lambda t: t[1])))
            for key, value in OrderedDict(sorted(z.items(), key=lambda t: t[1])).items():
                if last_local_seq > ARC_NODE_ELEMENT_DEFINITIONS[key]['milestone_seq']:
                    arcs_out_of_sequence.append(arc)
                    break
                last_local_seq = ARC_NODE_ELEMENT_DEFINITIONS[key]['milestone_seq']
                if 'mile_hook' in z.keys() and 'mile_reso' in z.keys():
                    arc_entry_exit[arc] = {
                        'entry': z['mile_hook'],
                        'exit': z['mile_reso'],
                    }
        if arc_entry_exit:
            temp_ent = {}
            temp_ex = {}
            for en_arc, enter in arc_entry_exit.items():
                temp_ent[en_arc] = enter['entry']
            for ex_arc, leave in arc_entry_exit.items():
                temp_ex[ex_arc] = leave['exit']
            arc_entries = OrderedDict(sorted(temp_ent.items(), key=lambda t: t[1]))
            arc_exits = OrderedDict(sorted(temp_ex.items(), key=lambda t: t[1], reverse=True))
            logger.debug("Evaluating entries vs exits: %s vs %s" % (arc_entries, arc_exits))
            index_num = 0
            for entrance in arc_entries.keys():
                test_exit = list(arc_exits.keys())[index_num]
                logger.debug('Checking %s vs %s arcs' % (entrance, test_exit))
                if entrance != test_exit:
                    logger.debug("Different arcs.. making sure they don't share an entry/exist point")
                    if (arc_entry_exit[entrance]['entry'] != arc_entry_exit[test_exit]['entry'] and
                        arc_entry_exit[entrance]['exit'] != arc_entry_exit[test_exit]['exit']):
                        if ((arc_entry_exit[entrance]['entry'] < arc_entry_exit[test_exit]['entry'] and
                                arc_entry_exit[entrance]['exit'] > arc_entry_exit[test_exit]['exit']) or
                            (arc_entry_exit[entrance]['entry'] > arc_entry_exit[test_exit]['entry'] and
                             arc_entry_exit[entrance]['exit'] < arc_entry_exit[test_exit]['exit'])):
                            logger.debug("No same entry point, but the nest is still valid.")
                        else:
                            logger.debug("nesting error found: %s should resole before %s" % (entrance, test_exit))
                            if entrance not in arcs_with_nest_conflicts:
                                arcs_with_nest_conflicts.append(entrance)
                            if test_exit not in arcs_with_nest_conflicts:
                                arcs_with_nest_conflicts.append(test_exit)
                    else:
                        logger.debug('Arcs share an entry/exit point so nesting error is ignored.')
                index_num += 1
        unique_nest_errors = list(set(arcs_with_nest_conflicts))
        logger.debug("%d arcs with nesting errors found" % len(unique_nest_errors))
        logger.debug('Arcs with nesting errors: %s' % unique_nest_errors)
        story_tree = story_root.get_descendants().prefetch_related('arcelementnode_set')
        if arcs_out_of_sequence:
            error_dict['nest_arc_seq'] = {
                'error_message': "Arc element milestones are out of sequence",
                'offending_arcs': []
            }
            logger.debug('There are %d arcs out of internal sequence' % len(arcs_out_of_sequence))
            arc_sequence_error_dict = {}
            story_root.refresh_from_db()
            for arc in arcs_out_of_sequence:
                arc_sequence_error_dict['offending_nodes'] = story_tree.filter(arcelementnode__arc=arc)
            error_dict['nest_arc_seq']['offending_arcs'].append(arc_sequence_error_dict)
        if unique_nest_errors:
            error_dict['nest_reso_error'] = {
                'error_message': "Arcs should resolve in the opposite order that they were introduced",
                'offending_nodes': story_tree.filter(
                    arcelementnode__arc__in=unique_nest_errors,
                    arcelementnode__arc_element_type='mile_reso'
                )
            }
        return error_dict
Reviews the story tree and validates associated arc
        elements are nested appropriately. Returns a dict of errors.