import re
import os

from bs4 import BeautifulSoup

from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.files import File

from pages.models import Page, Image

PEP_TEMPLATE = 'pages/pep-page.html'
pep_url = lambda num: 'dev/peps/pep-{}/'.format(num)


def check_paths():
    """ Checks to ensure our PEP_REPO_PATH is setup correctly """
    if not hasattr(settings, 'PEP_REPO_PATH'):
        raise ImproperlyConfigured("No PEP_REPO_PATH in settings")

    if not os.path.exists(settings.PEP_REPO_PATH):
        raise ImproperlyConfigured("PEP_REPO_PATH in settings does not exist")


def convert_pep0():
    """
    Take existing generated pep-0000.html and convert to something suitable
    for a Python.org Page returns the core body HTML necessary only
    """
    check_paths()

    pep0_path = os.path.join(settings.PEP_REPO_PATH, 'pep-0000.html')
    pep0_content = open(pep0_path).read()

    soup = BeautifulSoup(pep0_content)

    body_children = list(soup.body.children)

    # Grab header and PEP body
    header = body_children[3]
    pep_content = body_children[7]

    # Fix PEP links
    body_links = pep_content.find_all("a")

    pep_href_re = re.compile(r'pep-(\d+)\.html')

    for b in body_links:
        m = pep_href_re.search(b.attrs['href'])

        # Skip anything not matching 'pep-XXXX.html'
        if not m:
            continue

        b.attrs['href'] = '/dev/peps/pep-{}/'.format(m.group(1))

    # Remove Version from header
    header_rows = header.find_all('th')
    for t in header_rows:
        if 'Version:' in t.text and 'N/A' in t.next_sibling.text:
            t.parent.extract()

    return ''.join([header.prettify(), pep_content.prettify()])


def get_pep0_page(commit=True):
    """
    Using convert_pep0 above, create a CMS ready pep0 page and return it

    pep0 is used as the directory index, but it's also an actual pep, so we
    return both Page objects.
    """
    pep0_content = convert_pep0()
    pep0_page, _ = Page.objects.get_or_create(path='dev/peps/')
    pep0000_page, _ = Page.objects.get_or_create(path='dev/peps/pep-0000/')
    for page in [pep0_page, pep0000_page]:
        page.content = pep0_content
        page.content_markup_type = 'html'
        page.title = "PEP 0 -- Index of Python Enhancement Proposals (PEPs)"
        page.template_name = PEP_TEMPLATE

        if commit:
            page.save()

    return pep0_page, pep0000_page


def fix_headers(soup, data):
    """ Remove empty or unwanted headers and find our title """
    header_rows = soup.find_all('th')
    for t in header_rows:
        if 'Version:' in t.text:
            if t.next_sibling.text == '$Revision$':
                t.parent.extract()
            if t.next_sibling.text == '':
                t.parent.extract()
        if 'Last-Modified:' in t.text:
            if '$Date$'in t.next_sibling.text:
                t.parent.extract()
            if t.next_sibling.text == '':
                t.parent.extract()
        if t.text == 'Title:':
            data['title'] = t.next_sibling.text
        if t.text == 'Content-Type:':
            t.parent.extract()
        if 'Version:' in t.text and 'N/A' in t.next_sibling.text:
            t.parent.extract()

    return soup, data


def convert_pep_page(pep_number, content):
    """
    Handle different formats that pep2html.py outputs
    """
    check_paths()
    data = {
        'title': None,
    }

    if '<html>' in content:
        soup = BeautifulSoup(content)
        data['title'] = soup.title.text

        if not re.search(r'PEP \d+', data['title']):
            data['title'] = 'PEP {} -- {}'.format(
                pep_number,
                soup.title.text,
            )

        header = soup.body.find('div', class_="header")
        header, data = fix_headers(header, data)
        data['header'] = header.prettify()

        main_content = soup.body.find('div', class_="content")

        data['main_content'] = main_content.prettify()
        data['content'] = ''.join([
            data['header'],
            data['main_content']
        ])

    else:
        soup = BeautifulSoup(content)

        soup, data = fix_headers(soup, data)
        if not data['title']:
            data['title'] = "PEP {} -- ".format(pep_number)
        else:
            if not re.search(r'PEP \d+', data['title']):
                data['title'] = "PEP {} -- {}".format(
                    pep_number,
                    data['title'],
                )

        data['content'] = soup.prettify()

    # Fix PEP links
    pep_content = BeautifulSoup(data['content'])
    body_links = pep_content.find_all("a")

    pep_href_re = re.compile(r'pep-(\d+)\.html')

    for b in body_links:
        m = pep_href_re.search(b.attrs['href'])

        # Skip anything not matching 'pep-XXXX.html'
        if not m:
            continue

        b.attrs['href'] = '/dev/peps/pep-{}/'.format(m.group(1))

    data['content'] = pep_content.prettify()

    hg_link = "https://hg.python.org/peps/file/tip/pep-{0}.txt".format(pep_number)
    data['content'] += """Source: <a href="{0}">{0}</a>""".format(hg_link)
    return data


def get_pep_page(pep_number, commit=True):
    """
    Given a pep_number retrieve original PEP source text, rst, or html.
    Get or create the associated Page and return it
    """
    pep_path = os.path.join(settings.PEP_REPO_PATH, 'pep-{}.html'.format(pep_number))
    if not os.path.exists(pep_path):
        print("PEP Path '{}' does not exist, skipping".format(pep_path))

    pep_content = convert_pep_page(pep_number, open(pep_path).read())

    pep_page, _ = Page.objects.get_or_create(path=pep_url(pep_number))

    # Remove leading zeros from PEP number for display purposes
    pep_number_string = str(pep_number)
    pep_number_string = re.sub(r'^0+', '', pep_number_string)

    pep_page.title = pep_content['title']

    pep_page.content = pep_content['content']
    pep_page.content_markup_type = 'html'
    pep_page.template_name = PEP_TEMPLATE

    if commit:
        pep_page.save()

    return pep_page


def add_pep_image(pep_number, path):
    image_path = os.path.join(settings.PEP_REPO_PATH, path)
    if not os.path.exists(image_path):
        print("Image Path '{}' does not exist, skipping".format(image_path))

    try:
        page = Page.objects.get(path=pep_url(pep_number))
    except Page.DoesNotExist:
        print("Could not find backing PEP {}".format(pep_number))
        return

    # Find existing images, we have to loop here as we can't use the ORM
    # to query against image__path
    existing_images = Image.objects.filter(page=page)
    MISSING = False
    FOUND = False

    for image in existing_images:
        image_root_path = os.path.join(settings.MEDIA_ROOT, page.path, path)

        if image.image.path.endswith(path):
            FOUND = True
            # File is missing on disk, recreate
            if not os.path.exists(image_root_path):
                MISSING = image

            break

    if not FOUND or MISSING:
        image = None
        if MISSING:
            image = MISSING
        else:
            image = Image(page=page)

        with open(image_path, 'rb') as image_obj:
            image.image.save(path, File(image_obj))
        image.save()

    # Old images used to live alongside html, but now they're in different
    # places, so update the page accordingly.
    soup = BeautifulSoup(page.content.raw)
    for img_tag in soup.findAll('img'):
        if img_tag['src'] == path:
            img_tag['src'] = os.path.join(settings.MEDIA_URL, page.path, path)

    page.content.raw = soup.prettify()
    page.save()

    return image


def get_peps_rss():
    rss_feed = os.path.join(settings.PEP_REPO_PATH, 'peps.rss')
    if not os.path.exists(rss_feed):
        return

    page, _ = Page.objects.get_or_create(
        path="dev/peps/peps.rss",
        template_name="pages/raw.html",
    )

    with open(rss_feed, "r") as rss_content:
        content = rss_content.read()

    page.content = content
    page.is_published = True
    page.content_type = "application/rss+xml"
    page.save()

    return page

[((32, 16, 32, 69), 'os.path.join', 'os.path.join', ({(32, 29, 32, 51): 'settings.PEP_REPO_PATH', (32, 53, 32, 68): '"""pep-0000.html"""'}, {}), "(settings.PEP_REPO_PATH, 'pep-0000.html')", False, 'import os\n'), ((35, 11, 35, 38), 'bs4.BeautifulSoup', 'BeautifulSoup', ({(35, 25, 35, 37): 'pep0_content'}, {}), '(pep0_content)', False, 'from bs4 import BeautifulSoup\n'), ((46, 18, 46, 48), 're.compile', 're.compile', ({(46, 29, 46, 47): '"""pep-(\\\\d+)\\\\.html"""'}, {}), "('pep-(\\\\d+)\\\\.html')", False, 'import re\n'), ((74, 19, 74, 63), 'pages.models.Page.objects.get_or_create', 'Page.objects.get_or_create', (), '', False, 'from pages.models import Page, Image\n'), ((75, 22, 75, 75), 'pages.models.Page.objects.get_or_create', 'Page.objects.get_or_create', (), '', False, 'from pages.models import Page, Image\n'), ((159, 18, 159, 48), 'bs4.BeautifulSoup', 'BeautifulSoup', ({(159, 32, 159, 47): "data['content']"}, {}), "(data['content'])", False, 'from bs4 import BeautifulSoup\n'), ((162, 18, 162, 48), 're.compile', 're.compile', ({(162, 29, 162, 47): '"""pep-(\\\\d+)\\\\.html"""'}, {}), "('pep-(\\\\d+)\\\\.html')", False, 'import re\n'), ((195, 24, 195, 61), 're.sub', 're.sub', ({(195, 31, 195, 37): '"""^0+"""', (195, 39, 195, 41): '""""""', (195, 43, 195, 60): 'pep_number_string'}, {}), "('^0+', '', pep_number_string)", False, 'import re\n'), ((210, 17, 210, 59), 'os.path.join', 'os.path.join', ({(210, 30, 210, 52): 'settings.PEP_REPO_PATH', (210, 54, 210, 58): 'path'}, {}), '(settings.PEP_REPO_PATH, path)', False, 'import os\n'), ((222, 22, 222, 53), 'pages.models.Image.objects.filter', 'Image.objects.filter', (), '', False, 'from pages.models import Page, Image\n'), ((250, 11, 250, 42), 'bs4.BeautifulSoup', 'BeautifulSoup', ({(250, 25, 250, 41): 'page.content.raw'}, {}), '(page.content.raw)', False, 'from bs4 import BeautifulSoup\n'), ((262, 15, 262, 63), 'os.path.join', 'os.path.join', ({(262, 28, 262, 50): 'settings.PEP_REPO_PATH', (262, 52, 262, 62): '"""peps.rss"""'}, {}), "(settings.PEP_REPO_PATH, 'peps.rss')", False, 'import os\n'), ((266, 14, 269, 5), 'pages.models.Page.objects.get_or_create', 'Page.objects.get_or_create', (), '', False, 'from pages.models import Page, Image\n'), ((19, 14, 19, 66), 'django.core.exceptions.ImproperlyConfigured', 'ImproperlyConfigured', ({(19, 35, 19, 65): '"""No PEP_REPO_PATH in settings"""'}, {}), "('No PEP_REPO_PATH in settings')", False, 'from django.core.exceptions import ImproperlyConfigured\n'), ((21, 11, 21, 49), 'os.path.exists', 'os.path.exists', ({(21, 26, 21, 48): 'settings.PEP_REPO_PATH'}, {}), '(settings.PEP_REPO_PATH)', False, 'import os\n'), ((22, 14, 22, 78), 'django.core.exceptions.ImproperlyConfigured', 'ImproperlyConfigured', ({(22, 35, 22, 77): '"""PEP_REPO_PATH in settings does not exist"""'}, {}), "('PEP_REPO_PATH in settings does not exist')", False, 'from django.core.exceptions import ImproperlyConfigured\n'), ((122, 15, 122, 37), 'bs4.BeautifulSoup', 'BeautifulSoup', ({(122, 29, 122, 36): 'content'}, {}), '(content)', False, 'from bs4 import BeautifulSoup\n'), ((144, 15, 144, 37), 'bs4.BeautifulSoup', 'BeautifulSoup', ({(144, 29, 144, 36): 'content'}, {}), '(content)', False, 'from bs4 import BeautifulSoup\n'), ((186, 11, 186, 35), 'os.path.exists', 'os.path.exists', ({(186, 26, 186, 34): 'pep_path'}, {}), '(pep_path)', False, 'import os\n'), ((211, 11, 211, 37), 'os.path.exists', 'os.path.exists', ({(211, 26, 211, 36): 'image_path'}, {}), '(image_path)', False, 'import os\n'), ((227, 26, 227, 76), 'os.path.join', 'os.path.join', ({(227, 39, 227, 58): 'settings.MEDIA_ROOT', (227, 60, 227, 69): 'page.path', (227, 71, 227, 75): 'path'}, {}), '(settings.MEDIA_ROOT, page.path, path)', False, 'import os\n'), ((263, 11, 263, 35), 'os.path.exists', 'os.path.exists', ({(263, 26, 263, 34): 'rss_feed'}, {}), '(rss_feed)', False, 'import os\n'), ((125, 15, 125, 51), 're.search', 're.search', ({(125, 25, 125, 35): '"""PEP \\\\d+"""', (125, 37, 125, 50): "data['title']"}, {}), "('PEP \\\\d+', data['title'])", False, 'import re\n'), ((242, 20, 242, 36), 'pages.models.Image', 'Image', (), '', False, 'from pages.models import Page, Image\n'), ((253, 29, 253, 78), 'os.path.join', 'os.path.join', ({(253, 42, 253, 60): 'settings.MEDIA_URL', (253, 62, 253, 71): 'page.path', (253, 73, 253, 77): 'path'}, {}), '(settings.MEDIA_URL, page.path, path)', False, 'import os\n'), ((150, 19, 150, 55), 're.search', 're.search', ({(150, 29, 150, 39): '"""PEP \\\\d+"""', (150, 41, 150, 54): "data['title']"}, {}), "('PEP \\\\d+', data['title'])", False, 'import re\n'), ((232, 19, 232, 50), 'os.path.exists', 'os.path.exists', ({(232, 34, 232, 49): 'image_root_path'}, {}), '(image_root_path)', False, 'import os\n'), ((245, 35, 245, 50), 'django.core.files.File', 'File', ({(245, 40, 245, 49): 'image_obj'}, {}), '(image_obj)', False, 'from django.core.files import File\n')]