'Searches for common chapter headings throughout the document
attempts multiple patterns based on likelihood of a match
with minimum false positives.  Exits after finding a successful pattern'

def markup_chapters(self, html, wordcount, blanks_between_paragraphs):

    max_chapters = 150
    typical_chapters = 7000.0
    if (wordcount > 7000):
        if (wordcount > 200000):
            typical_chapters = 15000.0
        self.min_chapters = int(ceil((wordcount / typical_chapters)))
    self.log.debug(('minimum    chapters    required    are:    ' + unicode(self.min_chapters)))
    heading = re.compile('<h[1-3][^>]*>', re.IGNORECASE)
    self.html_preprocess_sections = len(heading.findall(html))
    self.log.debug((('found    ' + unicode(self.html_preprocess_sections)) + '    pre-existing    headings'))
    init_lookahead = '(?=<(p|div))'
    chapter_line_open = self.line_open
    title_line_open = '<(?P<outer2>p|div)[^>]*>\\s*(<(?P<inner4>font|span|[ibu])[^>]*>)?\\s*(<(?P<inner5>font|span|[ibu])[^>]*>)?\\s*(<(?P<inner6>font|span|[ibu])[^>]*>)?\\s*'
    chapter_header_open = '(?P<chap>'
    title_header_open = '(?P<title>'
    chapter_header_close = ')\\s*'
    title_header_close = ')'
    chapter_line_close = self.line_close
    title_line_close = '(</(?P=inner6)>)?\\s*(</(?P=inner5)>)?\\s*(</(?P=inner4)>)?\\s*</(?P=outer2)>'
    is_pdftohtml = self.is_pdftohtml(html)
    if is_pdftohtml:
        title_line_open = '<(?P<outer2>p)[^>]*>\\s*'
        title_line_close = '\\s*</(?P=outer2)>'
    if blanks_between_paragraphs:
        blank_lines = '(\\s*<p[^>]*>\\s*</p>){0,2}\\s*'
    else:
        blank_lines = ''
    opt_title_open = '('
    opt_title_close = ')?'
    n_lookahead_open = '(?!\\s*'
    n_lookahead_close = ')\\s*'
    default_title = '(<[ibu][^>]*>)?\\s{0,3}(?!Chapter)([\\w\\:\\\'\xe2\x80\x99\\"-]+\\s{0,3}){1,5}?(</[ibu][^>]*>)?(?=<)'
    simple_title = '(<[ibu][^>]*>)?\\s{0,3}(?!(Chapter|\\s+<)).{0,65}?(</[ibu][^>]*>)?(?=<)'
    analysis_result = []
    chapter_types = [['[^\'\\"]?(Introduction|Synopsis|Acknowledgements|Epilogue|CHAPTER|Kapitel|Volume\\b|Prologue|Book\\b|Part\\b|Dedication|Preface)\\s*([\\d\\w-]+\\:?\\\'?\\s*){0,5}', True, True, True, False, 'Searching    for    common    section    headings', 'common'], ['[^\'\\"]?(CHAPTER|Kapitel)\\s*([\\dA-Z\\-\\\'\\"\\?!#,]+\\s*){0,7}\\s*', True, True, True, False, 'Searching    for    most    common    chapter    headings', 'chapter'], ['<b[^>]*>\\s*(<span[^>]*>)?\\s*(?!([*#\xe2\x80\xa2=]+\\s*)+)(\\s*(?=[\\d.\\w#\\-*\\s]+<)([\\d.\\w#-*]+\\s*){1,5}\\s*)(?!\\.)(</span>)?\\s*</b>', True, True, True, False, 'Searching    for    emphasized    lines', 'emphasized'], ['[^\'\\"]?(\\d+(\\.|:))\\s*([\\w\\-\\\'\\"#,]+\\s*){0,7}\\s*', True, True, True, False, 'Searching    for    numeric    chapter    headings', 'numeric'], ['([A-Z]\\s+){3,}\\s*([\\d\\w-]+\\s*){0,3}\\s*', True, True, True, False, 'Searching    for    letter    spaced    headings', 'letter_spaced'], ['[^\'\\"]?(\\d+\\.?\\s+([\\d\\w-]+\\:?\\\'?-?\\s?){0,5})\\s*', True, True, True, False, 'Searching    for    numeric    chapters    with    titles', 'numeric_title'], ['[^\'\\"]?(\\d+)\\s*([\\dA-Z\\-\\\'\\"\\?!#,]+\\s*){0,7}\\s*', True, True, True, False, 'Searching    for    simple    numeric    headings', 'plain_number'], ['\\s*[^\'\\"]?([A-Z#]+(\\s|-){0,3}){1,5}\\s*', False, True, False, False, 'Searching    for    chapters    with    Uppercase    Characters', 'uppercase']]
    def recurse_patterns(html, analyze):
        for [chapter_type, n_lookahead_req, strict_title, ignorecase, title_req, log_message, type_name] in chapter_types:
            n_lookahead = ''
            hits = 0
            self.chapters_no_title = 0
            self.chapters_with_title = 0
            if n_lookahead_req:
                lp_n_lookahead_open = n_lookahead_open
                lp_n_lookahead_close = n_lookahead_close
            else:
                lp_n_lookahead_open = ''
                lp_n_lookahead_close = ''
            if strict_title:
                lp_title = default_title
            else:
                lp_title = simple_title
            if ignorecase:
                arg_ignorecase = '(?i)'
            else:
                arg_ignorecase = ''
            if title_req:
                lp_opt_title_open = ''
                lp_opt_title_close = ''
            else:
                lp_opt_title_open = opt_title_open
                lp_opt_title_close = opt_title_close
            if (self.html_preprocess_sections >= self.min_chapters):
                break
            full_chapter_line = ((((chapter_line_open + chapter_header_open) + chapter_type) + chapter_header_close) + chapter_line_close)
            if n_lookahead_req:
                n_lookahead = re.sub('(ou|in|cha)', 'lookahead_', full_chapter_line)
            if (not analyze):
                self.log.debug(((('Marked    ' + unicode(self.html_preprocess_sections)) + '    headings,    ') + log_message))
            chapter_marker = (((((((((((((arg_ignorecase + init_lookahead) + full_chapter_line) + blank_lines) + lp_n_lookahead_open) + n_lookahead) + lp_n_lookahead_close) + lp_opt_title_open) + title_line_open) + title_header_open) + lp_title) + title_header_close) + title_line_close) + lp_opt_title_close)
            chapdetect = re.compile(('%s' % chapter_marker))
            if analyze:
                hits = len(chapdetect.findall(html))
                if hits:
                    chapdetect.sub(self.analyze_title_matches, html)
                    if ((float(self.chapters_with_title) / float(hits)) > 0.5):
                        title_req = True
                        strict_title = False
                    self.log.debug((((((((((unicode(type_name) + '    had    ') + unicode(hits)) + '    hits    -    ') + unicode(self.chapters_no_title)) + '    chapters    with    no    title,    ') + unicode(self.chapters_with_title)) + '    chapters    with    titles,    ') + unicode((float(self.chapters_with_title) / float(hits)))) + '    percent.    '))
                    if (type_name == 'common'):
                        analysis_result.append([chapter_type, n_lookahead_req, strict_title, ignorecase, title_req, log_message, type_name])
                    elif ((self.min_chapters <= hits < max_chapters) or (self.min_chapters < 3 > hits)):
                        analysis_result.append([chapter_type, n_lookahead_req, strict_title, ignorecase, title_req, log_message, type_name])
                        break
            else:
                html = chapdetect.sub(self.chapter_head, html)
        return html
    recurse_patterns(html, True)
    chapter_types = analysis_result
    html = recurse_patterns(html, False)
    words_per_chptr = wordcount
    if ((words_per_chptr > 0) and (self.html_preprocess_sections > 0)):
        words_per_chptr = (wordcount / self.html_preprocess_sections)
    self.log.debug((((((('Total    wordcount    is:    ' + unicode(wordcount)) + ',    Average    words    per    section    is:    ') + unicode(words_per_chptr)) + ',    Marked    up    ') + unicode(self.html_preprocess_sections)) + '    chapters'))
    return html
