# -*- coding: ISO-8859-1 -*-
#
# Copyright (c) 2004-2005 DoCoMo Euro-Labs GmbH (Munich, Germany).
# Copyright (c) 2001-2005 LOGILAB S.A. (Paris, FRANCE).
#
# http://www.docomolab-euro.com/ -- mailto:tarlano@docomolab-euro.com
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
"""automatic documentation generation by introspection of memory elements

:version: $Revision:$  
:author: Logilab

:copyright:
  2001-2005 LOGILAB S.A. (Paris, FRANCE)
  
  2004-2005 DoCoMo Euro-Labs GmbH (Munich, Germany)
  
:contact:
  http://www.logilab.fr/ -- mailto:contact@logilab.fr
  
  http://www.docomolab-euro.com/ -- mailto:tarlano@docomolab-euro.com
"""

__revision__ = '$Id: Autodoc.py,v 1.10 2001/12/12 17:38:15 syt Exp $'

from narval.public import AL_NS
from narval.serialutils import yn_rev_value, context_rev_value
from narval.action import ActionElement
from narval.recipe import RecipeElement
from narval.elements.base import FileElement
from narval.elements.autodoc import AutodocConfigurationElement


TITLES = {
    'fr' : {'actions' : ('Description des actions du module %s',
                         'Prototype d\'entrée',
                         'Prototype de sortie'),
            'recipes' : ('Description des recettes du livre de recette %s')},
    'en' : {'actions' : ('Actions description for module %s',
                         'Input prototype',
                         'Output prototype'),
            'recipes' : ('Recipes descriptions for cookbook %s')},
    }


def document_input(node, lang, encoding):
    return document_proto_entry(node, lang, encoding,
                                (('list', yn_rev_value),
                                 ('optional', yn_rev_value),
                                 ('use', yn_rev_value),
                                 ('from_context', context_rev_value),
                                 ('to_context', context_rev_value)))

def document_output(node, lang, encoding):
    return document_proto_entry(node, lang, encoding,
                                (('list', yn_rev_value),
                                 ('optional', yn_rev_value),
                                 ('outdates', str)))

def document_proto_entry(node, lang, encoding, attrs):
    data = ['<section><title>%s</title>' % node.id]
    description = node.descriptions.get(lang)
    if description:
        data.append('<para>%s</para>' % description.encode(encoding))
    data.append('<para>')
    if node.matches:
        data.append('<emphasis>match&#160;:&#160;</emphasis><programlisting>%s</programlisting>' % '\n'.join(node.matches))
    data.append('''<informaltable>
   <tgroup cols="%s" colsep="0" rowsep="0" align="center">
   %s
   <thead>
   <row>''' % (len(attrs), '<colspec/>' * len(attrs)))
    for attr, tr_func in attrs:
        data.append('<entry>%s</entry>' % attr)
    data.append('''</row>
   </thead>
   <tbody>
   <row>''')
    for attr, tr_func in attrs:
        data.append('<entry align="center">%s</entry>' % tr_func(getattr(node, attr)))
    data.append('''</row>
</tbody>
</tgroup>
</informaltable>
</para>
</section>''')
    return '\n'.join(data)


def _docbook_document(inputs, etype):
    ctrl = inputs['ctrl'] or AutodocConfigurationElement()
    encoding, lang = ctrl.encoding, ctrl.lang
    bygroup = {'recipe': {}, 'action': {}}
    for elmt in inputs['elements']:
        if isinstance(elmt, RecipeElement):
            bygroup['recipe'].setdefault(elmt.group, []).append(elmt)
        elif isinstance(elmt, ActionElement):
            bygroup['action'].setdefault(elmt.group, []).append(elmt)
    result = []
    for etype, groups in bygroup.items():
        if etype == 'recipe':
            document_element = _recipe_docbook
        else: # etype == 'action'
            document_element = _action_docbook
        ctrl.etype = etype
        for group, elmts in groups.items():
            ctrl.group = group
            data = ['''<?xml version="1.0" encoding="%s"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
<article>
<articleinfo>''' % (encoding or 'utf-8')]
            title = TITLES[lang][etype][0] % ctrl.group
            data.append('<title>%s</title>' % title)
            data.append('</articleinfo>')
            for elmt in elmts:
                document_element(elmt, data, lang, encoding)
            data.append('</article>')
            data = '\n'.join(data)
            filee = FileElement(address=ctrl.raw_address(), mode='w', encoding=encoding)
            filee.data = data
            result.append(filee)
    return {'docfiles' : result}

def _recipe_docbook(elmt, data, lang, encoding):
    data.append('<section><title>%s</title>' % (elmt.name))
    description = elmt.descriptions.get(lang)
    if description:
        data.append('<para>%s</para>' % description.encode(encoding))
    data.append('</section>')
    
def _action_docbook(elmt, data, lang, encoding):
    data.append('<section><title>%s</title>' % (elmt.name))
    description = elmt.descriptions.get(lang)
    if description:
        data.append('<para>%s</para>' % description.encode(encoding))
    if hasattr(elmt, 'prototype'):
        data.append('<section><title>%s</title>' % TITLES[lang]['actions'][1])
        for proto in elmt.prototype._inputs:
            data.append(document_input(proto, lang, encoding))
        data.append('</section>')
        data.append('<section><title>%s</title>' % TITLES[lang]['actions'][2])
        for proto in elmt.prototype._outputs:
            data.append(document_output(proto, lang, encoding))
        data.append('</section>')
    data.append('</section>')

# actions definition start here ###############################################

MOD_XML = '''<?xml version="1.0" encoding="ISO-8859-1"?>
<module xmlns:al="%s" name="Autodoc">''' % AL_NS

## def act_group_filter(inputs):
##     """filter elements necessary to generate documentation for
##     actions / recipes

##     FIXME: should not use this filter which is duplicating existing actions/recipes !
##     """
##     ctrl = inputs['ctrl'] or AutodocConfigurationElement()
##     group = ctrl.group
##     if group and group != 'all':
##         result = [n.clone() for n in inputs['elements'] if n.group == group]
##     else:
##         result = [n.clone() for n in inputs['elements']]
##     return {'elements': result}

## MOD_XML += '''<al:action name="filter-actions" func="act_group_filter">
##   <al:description lang="en">
## Select actions and control structure for doc generation
##   </al:description>
  
##   <al:input id='elements' list="yes">
##     <al:match>isinstance(elmt, ActionElement)</al:match>
##   </al:input>
##   <al:input id='ctrl' optional='yes'>
##     <al:match>isinstance(elmt, AutodocConfigurationElement)</al:match>
##   </al:input>
  
##   <al:output id='elements' list='yes'>
##    <al:match>isinstance(elmt, ActionElement)</al:match>
##    <al:description lang="en">filtered actions list</al:description>
##   </al:output>
## </al:action>'''

## MOD_XML += '''<al:action name="filter-recipes" func="act_group_filter">
##   <al:description lang="en">Select recipes and control structure for doc generation</al:description>
##   <al:input id='elements' list="yes"><al:match>isinstance(elmt, RecipeElement)</al:match></al:input>
##   <al:input id='ctrl' optional='yes'>
##     <al:match>isinstance(elmt, AutodocConfigurationElement)</al:match>
##   </al:input>
  
##   <al:output id='elements' list="yes">
##    <al:match>isinstance(elmt, RecipeElement)</al:match>
##    <al:description lang="en">filtered recipes list</al:description>
##   </al:output>
## </al:action>
## '''



## def act_document_actions(inputs):
##     return _docbook_document(inputs, 'actions')
## MOD_XML += '''<al:action name="document-actions" func="act_document_actions">
##   <al:description lang="en">Generate DOCBOOK documentation for actions elements</al:description>
##   <al:input id='ctrl' optional='yes'>
##     <al:match>isinstance(elmt, AutodocConfigurationElement)</al:match>
##   </al:input>
##   <al:input id='elements' list="yes"><al:match>isinstance(elmt, ActionElement)</al:match></al:input>
  
##   <al:output id='docfile'><al:match>IFile(elmt).mode == 'w'</al:match></al:output>
## </al:action>
## '''
    
## def act_document_recipes(inputs):
##     return _docbook_document(inputs, 'recipes')

## MOD_XML += '''<al:action name="document-recipes" func="act_document_recipes">
##   <al:description lang="en">Generate DOCBOOK documentation for recipes elements</al:description>
##   <al:input id='ctrl' optional='yes'>
##     <al:match>isinstance(elmt, AutodocConfigurationElement)</al:match>
##   </al:input>
##   <al:input id='elements' list="yes">
##     <al:match>isinstance(elmt, RecipeElement)</al:match>
##   </al:input>
  
##   <al:output id='docfile'><al:match>IFile(elmt).mode == 'w'</al:match></al:output>
## </al:action>
## '''
    
def act_document_elements(inputs):
    return _docbook_document(inputs, 'recipes')

MOD_XML += '''<al:action name="document-elements" func="act_document_recipes">
  <al:description lang="en">Generate DOCBOOK documentation for recipes elements</al:description>
  <al:input id="ctrl">
    <al:match>isinstance(elmt, AutodocConfigurationElement)</al:match>
  </al:input>
  <al:input id="elements" list="yes">
    <al:match>ctrl.match_element(elmt)</al:match>
  </al:input>
  
  <al:output id="docfiles" list="yes"><al:match>IFile(elmt).mode == 'w'</al:match></al:output>
</al:action>
'''
    
def act_command2autodocconfig(inputs):
    """generate the documentation generation control element according to the given command"""
    cmd = inputs['cmd']
    ctrl = AutodocConfigurationElement()
    possible_attrs = [descr.attrname for descr in ctrl.ns_attributes()]
    for arg in cmd.args:
        attr, val = arg.split('=')
        assert attr in possible_attrs
        setattr(ctrl, attr.strip(), val.strip())
    return {'ctrl' : ctrl}

MOD_XML += '''<al:action name="command2autodocconfig" func="act_command2autodocconfig">
  <al:description lang="en">%s</al:description>
  <al:input id='cmd'>
    <al:match>ICommand(elmt)</al:match>
  </al:input>
  
  <al:output id='ctrl'>
    <al:match>isinstance(elmt, AutodocConfigurationElement)</al:match>
  </al:output>
</al:action>
''' % act_command2autodocconfig.__doc__

MOD_XML += "</module>"
