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

[((854, 907), 'os.path.join', 'os.path.join', (['settings.PEP_REPO_PATH', '"""pep-0000.html"""'], {}), "(settings.PEP_REPO_PATH, 'pep-0000.html')\n", (866, 907), False, 'import os\n'), ((962, 989), 'bs4.BeautifulSoup', 'BeautifulSoup', (['pep0_content'], {}), '(pep0_content)\n', (975, 989), False, 'from bs4 import BeautifulSoup\n'), ((1216, 1247), 're.compile', 're.compile', (['"""pep-(\\\\d+)\\\\.html"""'], {}), "('pep-(\\\\d+)\\\\.html')\n", (1226, 1247), False, 'import re\n'), ((2025, 2069), 'pages.models.Page.objects.get_or_create', 'Page.objects.get_or_create', ([], {'path': '"""dev/peps/"""'}), "(path='dev/peps/')\n", (2051, 2069), False, 'from pages.models import Page, Image\n'), ((2092, 2145), 'pages.models.Page.objects.get_or_create', 'Page.objects.get_or_create', ([], {'path': '"""dev/peps/pep-0000/"""'}), "(path='dev/peps/pep-0000/')\n", (2118, 2145), False, 'from pages.models import Page, Image\n'), ((4605, 4635), 'bs4.BeautifulSoup', 'BeautifulSoup', (["data['content']"], {}), "(data['content'])\n", (4618, 4635), False, 'from bs4 import BeautifulSoup\n'), ((4698, 4729), 're.compile', 're.compile', (['"""pep-(\\\\d+)\\\\.html"""'], {}), "('pep-(\\\\d+)\\\\.html')\n", (4708, 4729), False, 'import re\n'), ((5836, 5872), 're.sub', 're.sub', (['"""^0+"""', '""""""', 'pep_number_string'], {}), "('^0+', '', pep_number_string)\n", (5842, 5872), False, 'import re\n'), ((6165, 6207), 'os.path.join', 'os.path.join', (['settings.PEP_REPO_PATH', 'path'], {}), '(settings.PEP_REPO_PATH, path)\n', (6177, 6207), False, 'import os\n'), ((6634, 6665), 'pages.models.Image.objects.filter', 'Image.objects.filter', ([], {'page': 'page'}), '(page=page)\n', (6654, 6665), False, 'from pages.models import Page, Image\n'), ((7444, 7475), 'bs4.BeautifulSoup', 'BeautifulSoup', (['page.content.raw'], {}), '(page.content.raw)\n', (7457, 7475), False, 'from bs4 import BeautifulSoup\n'), ((7741, 7789), 'os.path.join', 'os.path.join', (['settings.PEP_REPO_PATH', '"""peps.rss"""'], {}), "(settings.PEP_REPO_PATH, 'peps.rss')\n", (7753, 7789), False, 'import os\n'), ((7857, 7946), 'pages.models.Page.objects.get_or_create', 'Page.objects.get_or_create', ([], {'path': '"""dev/peps/peps.rss"""', 'template_name': '"""pages/raw.html"""'}), "(path='dev/peps/peps.rss', template_name=\n    'pages/raw.html')\n", (7883, 7946), False, 'from pages.models import Page, Image\n'), ((453, 505), 'django.core.exceptions.ImproperlyConfigured', 'ImproperlyConfigured', (['"""No PEP_REPO_PATH in settings"""'], {}), "('No PEP_REPO_PATH in settings')\n", (473, 505), False, 'from django.core.exceptions import ImproperlyConfigured\n'), ((518, 556), 'os.path.exists', 'os.path.exists', (['settings.PEP_REPO_PATH'], {}), '(settings.PEP_REPO_PATH)\n', (532, 556), False, 'import os\n'), ((572, 636), 'django.core.exceptions.ImproperlyConfigured', 'ImproperlyConfigured', (['"""PEP_REPO_PATH in settings does not exist"""'], {}), "('PEP_REPO_PATH in settings does not exist')\n", (592, 636), False, 'from django.core.exceptions import ImproperlyConfigured\n'), ((3507, 3529), 'bs4.BeautifulSoup', 'BeautifulSoup', (['content'], {}), '(content)\n', (3520, 3529), False, 'from bs4 import BeautifulSoup\n'), ((4153, 4175), 'bs4.BeautifulSoup', 'BeautifulSoup', (['content'], {}), '(content)\n', (4166, 4175), False, 'from bs4 import BeautifulSoup\n'), ((5465, 5489), 'os.path.exists', 'os.path.exists', (['pep_path'], {}), '(pep_path)\n', (5479, 5489), False, 'import os\n'), ((6219, 6245), 'os.path.exists', 'os.path.exists', (['image_path'], {}), '(image_path)\n', (6233, 6245), False, 'import os\n'), ((6765, 6815), 'os.path.join', 'os.path.join', (['settings.MEDIA_ROOT', 'page.path', 'path'], {}), '(settings.MEDIA_ROOT, page.path, path)\n', (6777, 6815), False, 'import os\n'), ((7801, 7825), 'os.path.exists', 'os.path.exists', (['rss_feed'], {}), '(rss_feed)\n', (7815, 7825), False, 'import os\n'), ((3586, 3622), 're.search', 're.search', (['"""PEP \\\\d+"""', "data['title']"], {}), "('PEP \\\\d+', data['title'])\n", (3595, 3622), False, 'import re\n'), ((7170, 7186), 'pages.models.Image', 'Image', ([], {'page': 'page'}), '(page=page)\n', (7175, 7186), False, 'from pages.models import Page, Image\n'), ((7580, 7629), 'os.path.join', 'os.path.join', (['settings.MEDIA_URL', 'page.path', 'path'], {}), '(settings.MEDIA_URL, page.path, path)\n', (7592, 7629), False, 'import os\n'), ((4345, 4381), 're.search', 're.search', (['"""PEP \\\\d+"""', "data['title']"], {}), "('PEP \\\\d+', data['title'])\n", (4354, 4381), False, 'import re\n'), ((6953, 6984), 'os.path.exists', 'os.path.exists', (['image_root_path'], {}), '(image_root_path)\n', (6967, 6984), False, 'import os\n'), ((7273, 7288), 'django.core.files.File', 'File', (['image_obj'], {}), '(image_obj)\n', (7277, 7288), False, 'from django.core.files import File\n')]