# -*- coding: utf-8 -*-
#
# This file is part of Documentor
# (https://github.com/diegosarmentero/documentor).
#
# Documentor is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# any later version.
#
# Documentor is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Documentor; If not, see <http://www.gnu.org/licenses/>.
import os
import datetime

import templates

try:
    from nikola import utils
except:
    print """\nYou need to install Nikola in order to use Documentor, check out:

    http://nikola.ralsina.com.ar/\n\n"""
    raise Exception("Nikola is not installed.")


#FIXME: Improve the code for content creation


class DocDump(object):
    """Create a restructured text file with the representation obtained."""

    def __init__(self, projectname, output):
        self.projectname = projectname
        today = datetime.date.today()
        self.date = today.strftime('%Y/%m/%d %H:%M:%S')
        self.files_folder = os.path.join(output, 'files')
        self.posts_folder = os.path.join(output, 'posts')
        self.output = os.path.join(output, 'stories')

        self._create_post()

        self.__modules = []
        self.__classes = []
        self.__functions = []

    def process_symbols(self, symbols, filepath, relpath):
        """Process the symbols to create the documentation file."""
        basename = os.path.basename(filepath)
        name = os.path.splitext(basename)[0]
        path = os.path.join(self.output, relpath)
        htmlpath = os.path.join('/listings/', relpath, basename + '.html')
        docpath = os.path.join('stories/', relpath, name + '.html')
        content = templates.BASE_FILE % {
            'date': self.date,
            'projectname': self.projectname,
            'filename': name
        }
        # MODULE
        module_line = templates.MODULE % {
            'name': basename,
            'link': htmlpath
        }
        content += module_line + ('=' * len(module_line)) + '\n'

        docstring = symbols.get('docstring')
        if docstring:
            docstring = '| %s' % docstring.replace(
                '*', '\\*').replace('`', '\\`').replace('_', '\_')
            doc = '| '.join([line + '\n'
                             for line in docstring.split('\n')]) + '\n'
        else:
            doc = templates.NO_DESCRIPTION + '\n'
        content += doc

        content += self._add_imports(symbols, htmlpath) + '\n'
        content += self._add_global_attributes(symbols, htmlpath) + '\n'
        content += self._add_global_functions(symbols, htmlpath, docpath) + '\n'
        content += self._add_classes(symbols, htmlpath, docpath) + '\n'

        content = content.strip()
        if content[-4:] == '----':
            content = content[:-4]
        content += '\n\n'

        self.__modules.append((basename, docpath, 0))

        if not os.path.exists(path):
            os.makedirs(path)

        write_path = os.path.join(path, name + '.txt')
        with open(write_path, 'w') as f:
            f.write(content)

    def _create_post(self):
        """Create a post to show in the index page."""
        post = templates.POST % {
            'date': self.date,
            'projectname': self.projectname
        }

        path = os.path.join(self.posts_folder, 'index_post' + '.txt')
        with open(path, 'w') as f:
            f.write(post)

    def _add_imports(self, symbols, htmlpath):
        """Add the imports to the Module Documentation."""
        content = ''
        results = symbols['imports']
        imports = results['imports']
        fromImports = results['fromImports']

        if imports or fromImports:
            content += templates.IMPORTS + (
                        '-' * len(templates.IMPORTS)) + '\n'

        imports_key = sorted(imports.keys())
        for imp in imports_key:
            content += templates.LIST_LINK_ITEM % {
                'name': imp,
                'link': '%s#%s' % (htmlpath, imports[imp]['lineno'])
            } + '\n'

        fromImports_key = sorted(fromImports.keys())
        for imp in fromImports_key:
            content += templates.LIST_LINK_ITEM % {
                'name': fromImports[imp]['module'] + ".%s" % imp,
                'link': '%s#%s' % (htmlpath, fromImports[imp]['lineno'])
            } + '\n'

        return content

    def _add_global_attributes(self, symbols, htmlpath):
        """Add the global attributes to the Module Documentation."""
        content = ''
        attrs = symbols.get('attributes')
        if attrs:
            content += templates.GLOBAL_ATTRIBUTES + (
                        '-' * len(templates.GLOBAL_ATTRIBUTES)) + '\n'

            attrs_key = sorted(attrs.keys())
            for attr in attrs_key:
                content += templates.LIST_LINK_ITEM % {
                    'name': "%s [at ln:%d]" % (attr, attrs[attr]),
                    'link': '%s#%s' % (htmlpath, attrs[attr])
                } + '\n'

            content += '\n----\n'

        return content

    def _add_global_functions(self, symbols, htmlpath, docpath):
        """Add the global functions to the Module Documentation."""
        content = ''
        funcs = symbols.get('functions')
        if funcs:
            content += templates.GLOBAL_FUNCTIONS + (
                        '-' * len(templates.GLOBAL_FUNCTIONS)) + '\n'

            funcs_key = sorted(funcs.keys())
            for func in funcs_key:
                content += self._add_function(funcs[func], htmlpath, docpath)

        return content

    def _add_function(self, symbol, htmlpath, docpath):
        """Add the function with the function content and style."""
        content = ''
        name_to_slugy = os.path.splitext(htmlpath)[0]
        slugy = utils.slugify(name_to_slugy.decode('utf-8'))
        function_name = templates.FUNCTION % {
            'name': "%s [at ln:%d]" % (symbol['name'], symbol['lineno']),
            'link': '%s#%s-%s' % (htmlpath, slugy, symbol['lineno'])
        }
        content += function_name + ('~' * len(function_name)) + '\n'

        content += templates.CODE % {
            'code': "def %s:" % symbol['name']
        }

        docstring = symbol['docstring']
        if docstring:
            docstring = '| %s' % docstring.replace(
                '*', '\\*').replace('`', '\\`').replace('_', '\_')
            doc = '| '.join([line + '\n'
                             for line in docstring.split('\n')]) + '\n'
        else:
            doc = templates.NO_DESCRIPTION
        content += doc

        if symbol['decorators']:
            content += templates.DECORATORS
            for decorator in symbol['decorators']:
                content += '- *%s*\n' % decorator

        self.__functions.append((symbol['name'], docpath, symbol['lineno']))

        content += '\n----\n'

        return content

    def _add_classes(self, symbols, htmlpath, docpath):
        """Add the class with the class content and style."""
        content = ''
        clazzes = symbols.get('classes', [])
        name_to_slugy = os.path.splitext(htmlpath)[0]
        slugy = utils.slugify(name_to_slugy.decode('utf-8'))
        for clazz in clazzes:
            clazz_name = templates.CLASS % {
                'name': clazz,
                'link': '%s#%s-%s' % (htmlpath, slugy, clazzes[clazz]['lineno'])
            }
            content += clazz_name + ('-' * len(clazz_name)) + '\n'

            content += templates.CODE % {
                'code': "class %s:" % clazz
            }

            docstring = clazzes[clazz]['docstring']
            if docstring:
                docstring = '| %s' % docstring.replace(
                '*', '\\*').replace('`', '\\`').replace('_', '\_')
                doc = '| '.join([line + '\n'
                                 for line in docstring.split('\n')]) + '\n'
            else:
                doc = templates.NO_DESCRIPTION
            content += doc

            attrs = clazzes[clazz]['attributes']
            if attrs:
                content += templates.ATTRIBUTES + (
                            '~' * len(templates.ATTRIBUTES)) + '\n'

                attrs_key = sorted(attrs.keys())
                for attr in attrs_key:
                    content += templates.LIST_LINK_ITEM % {
                        'name': "%s [at ln:%d]" % (attr, attrs[attr]),
                        'link': '%s#%s' % (htmlpath, attrs[attr])
                    } + '\n'

            funcs = clazzes[clazz]['functions']
            if funcs:
                funcs_key = sorted(funcs.keys())
                for func in funcs_key:
                    content += self._add_function(funcs[func], htmlpath,
                        docpath)
            else:
                content += '\n----\n'

            self.__classes.append((clazz, docpath, clazzes[clazz]['lineno']))

        return content

    def create_html_sections(self):
        """Create the sections to access: Modules, Classes and Functions."""
        # Modules
        html = templates.HTML_FILES_HEADER % {
            'projectname': self.projectname,
            'type': 'Modules'
        }
        for mod in sorted(self.__modules, key=lambda x: x[0]):
            html += templates.HTML_FILES_BODY % {
                'link': mod[1],
                'name': mod[0]
            }
        html += templates.HTML_FILES_FOOTER % {
            'year': str(datetime.date.today().year),
            'projectname': self.projectname
        }

        path = os.path.join(self.files_folder, 'documentor_modules.html')
        with open(path, 'w') as f:
            f.write(html)

        # Classes
        html = templates.HTML_FILES_HEADER % {
            'projectname': self.projectname,
            'type': 'Classes'
        }
        for cla in sorted(self.__classes, key=lambda x: x[0]):
            name_to_slugy = os.path.splitext(cla[1])[0]
            slugy = utils.slugify(name_to_slugy.decode('utf-8'))
            html += templates.HTML_FILES_BODY % {
                'link': "%s#%s-%d" % (cla[1], slugy, cla[2]),
                'name': cla[0]
            }
        html += templates.HTML_FILES_FOOTER % {
            'year': str(datetime.date.today().year),
            'projectname': self.projectname
        }

        path = os.path.join(self.files_folder, 'documentor_classes.html')
        with open(path, 'w') as f:
            f.write(html)

        # Functions
        html = templates.HTML_FILES_HEADER % {
            'projectname': self.projectname,
            'type': 'Functions'
        }
        for fun in sorted(self.__functions, key=lambda x: x[0]):
            name_to_slugy = os.path.splitext(fun[1])[0]
            slugy = utils.slugify(name_to_slugy.decode('utf-8'))
            html += templates.HTML_FILES_BODY % {
                'link': "%s#%s-%d" % (fun[1], slugy, fun[2]),
                'name': fun[0]
            }
        html += templates.HTML_FILES_FOOTER % {
            'year': str(datetime.date.today().year),
            'projectname': self.projectname
        }

        path = os.path.join(self.files_folder, 'documentor_functions.html')
        with open(path, 'w') as f:
            f.write(html)
Contents © 2013 Documentor - Powered by Nikola and Documentor