# -*- coding: utf-8 -*-
"""
MoinMoin - Macro for Attachment Administration

Discover unused (not linked) and missing (not yet uploaded) attachments

@copyright: 2015-2018, David Linke, MoinMoin:DavidLinke, https://github.com/dalito
@license: GNU GPL, see COPYING for details.
"""
import os
import sys

from MoinMoin import config
from MoinMoin import wikiutil
from MoinMoin.PageEditor import PageEditor
from MoinMoin.parser.text_moin_wiki import Parser
from MoinMoin.action import AttachFile

# Should only the superuser be allowed to use this macro ?
SUPERUSER_ONLY = False


def macro_StatusAttachments(macro):
    """
    Purpose: Discover unused (not linked) attachments and missing attachment

    This macro finds and reports
    (i)  attachments that are stored on pages put linked from nowhere
    (ii) attachment-links for which the attachment is not yet uploaded.

    The underlay directory is excluded.
    """
    _ = macro.request.getText
    request = macro.request

    # do not show to users not in superuser list
    if SUPERUSER_ONLY and not request.user.isSuperUser():
        error = _(u'Only superusers can use StatusAttachments macro.')
        # Send page with an error message
        request.theme.add_msg(error, 'info')
        return ''

    # do import from plugin "extensions" dir
    LinkParser = wikiutil.importWikiPlugin(
        request.cfg, 'parser', 'text_moin_wiki_links', 'LinkParser'
    )

    # create instance of parser for link extraction
    lparser = LinkParser()

    # collect info per page in lists
    stored_attachments = {}
    attachments_no_ext = {}
    links_to_existing_atts = {}
    links_to_missing_atts = {}
    stored_non_linked_atts = {}

    # get list of all pagenames excluding underlay
    pages = request.rootpage.getPageDict(user=request.user,
                                         include_underlay=False)

    for pagename in pages:
        page = PageEditor(request, pagename)

        # (i) get linked attachments by parsing raw text
        raw = page.get_raw_body()
        atts = lparser.find_links(raw, link_filter=lparser.is_attachment)
        for att in atts:
            link = att.split(':', 1)[1]
            if '/' in link:
                storage_page, filename = link.rsplit('/', 1)
            else:
                storage_page, filename = pagename, link
            filename = wikiutil.taintfilename(filename)
            if AttachFile.exists(request, storage_page, filename):
                if storage_page in links_to_existing_atts:
                    links_to_existing_atts[storage_page].append(filename)
                else:
                    links_to_existing_atts[storage_page] = [filename]
            else:
                if storage_page in links_to_missing_atts:
                   if filename not in links_to_missing_atts[storage_page]:
                        links_to_missing_atts[storage_page].append(filename)
                else:
                    links_to_missing_atts[storage_page] = [filename]

        # (ii) get stored attachments by looking at file system
        # & (iii) get stored attachments without any extension
        page_att_dir = AttachFile.getAttachDir(request, pagename)
        if os.path.isdir(page_att_dir):
            atts, atts_no_ext = [], []
            for fname in os.listdir(page_att_dir):
                atts.append(fname.decode(config.charset))
                if not os.path.splitext(fname)[1]:
                    atts_no_ext.append(fname.decode(config.charset))
            if atts:
                stored_attachments[pagename] = atts
            if atts_no_ext:
                attachments_no_ext[pagename] = atts_no_ext

    # when checking for availability of attachments we need to consider that
    # filenames are case insensitive on some platforms
    if sys.platform == 'win32':
        links_to_existing_atts_fs = {}
        for p in links_to_existing_atts:
            links_to_existing_atts_fs[p] = [os.path.normcase(att) for att in
                                            links_to_existing_atts[p]]
    else:
        links_to_existing_atts_fs = links_to_existing_atts

    # Find stored attachments that are not linked from anywhere
    for pagename in stored_attachments:
        for att in stored_attachments[pagename]:
            # look up in links_to_existing_atts if linked
            if (os.path.normcase(att)
                    in links_to_existing_atts_fs.get(pagename, [])):
                continue

            # keep name of non-linked attachment
            if pagename in stored_non_linked_atts:
                stored_non_linked_atts[pagename].append(att)
            else:
                stored_non_linked_atts[pagename] = [att]

    # Created formatted output. We create wiki raw code that is then rendered.
    # Compare to using formatters this is much less verbose (but slower).

    # (i)  attachments that are stored on pages put linked from nowhere
    ret = []
    ret.append('<<TableOfContents>>')
    ret.append(u'== %s ==' %
               _(u'Attachments that are not linked from anywhere'))

    if not stored_non_linked_atts:
        ret.append(u" * None!")
    else:
        ret.append(u" * Found '''%i''' attachments that are not linked." %
                   len(reduce(list.__add__, stored_non_linked_atts.values())))
    for pagename in sorted(stored_non_linked_atts):
        ret.append(u" * '''[[%s||&action=AttachFile]]'''" % pagename)
        for att in sorted(stored_non_linked_atts[pagename]):
            ret.append(u"  * `%s`" % att)

    # (ii) attachment-links for which the attachment is not yet uploaded.
    ret.append(u'== %s ==' %
               _(u'Attachments that are linked but missing'))
    if not links_to_missing_atts:
        ret.append(u" * None!")
    else:
        ret.append(u" * Found '''%i''' links to missing attachments." %
                   len(reduce(list.__add__, links_to_missing_atts.values())))
    for pagename in sorted(links_to_missing_atts):
        ret.append(u" * '''[[%s]]'''" % pagename)
        for att in sorted(links_to_missing_atts[pagename]):
            ret.append(u"  * `%s`" % att)

    # (iii) List all stored attachments without any extension
    ret.append(u'== %s ==' %
               _(u'Attachments lacking a file extension'))
    if not attachments_no_ext:
        ret.append(u" * None!")
    else:
        ret.append(u" * Found '''%i''' attachments without extension." %
                   len(reduce(list.__add__, attachments_no_ext.values())))
    for pagename in sorted(attachments_no_ext):
        ret.append(u" * '''[[%s||&action=AttachFile]]'''" % pagename)
        for att in sorted(attachments_no_ext[pagename]):
            ret.append(u"  * `%s`" % att)

    return wikiutil.renderText(request, Parser, '\n'.join(ret))
