u'''
Update Table Linkbase is an example of a plug-in to both GUI menu and command line/web service
that updates a table linkbase from Eurofiling 2010 syntax to XII 2011 PWD syntax and saves it.

(c) Copyright 2012 Mark V Systems Limited, All rights reserved.
'''
from io import open

def generateUpdatedTableLB(dts, updatedTableLinkbaseFile):
    import os, io
    from arelle import XmlUtil, XbrlConst
    from arelle.ViewUtil import viewReferences, referenceURI
    from arelle.ModelRenderingObject import ModelEuAxisCoord
    
    if dts.fileSource.isArchive:
        dts.error(u"genTblLB:outFileIsArchive",
                 _(u"Updated Table Linkbase file cannot be an archive: %(tableLBOutputFile)s."),
                 modelObject=dts, tableLBOutputFile=updatedTableLinkbaseFile)
        return
    tblAxisRelSet = dts.relationshipSet(XbrlConst.euTableAxis)
    axisMbrRelSet = dts.relationshipSet(XbrlConst.euAxisMember)
    if len(tblAxisRelSet.modelRelationships) == 0:
        dts.error(u"genTblLB:noInputTables",
                 _(u"DTS does not contain Eurofiling 2010 tables and axes: %(entryFile)s."),
                 modelObject=dts, entryFile=dts.uri)
        return

    file = io.StringIO(u'''
<nsmap>
<link:linkbase 
xmlns:label="http://xbrl.org/2008/label"
xmlns:gen="http://xbrl.org/2008/generic"
xmlns:df="http://xbrl.org/2008/filter/dimension"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:reference="http://xbrl.org/2008/reference"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:link="http://www.xbrl.org/2003/linkbase"
xmlns:table="http://xbrl.org/2011/table"
xmlns:formula="http://xbrl.org/2008/formula"
xsi:schemaLocation="             
http://www.xbrl.org/2003/linkbase http://www.xbrl.org/2003/xbrl-linkbase-2003-12-31.xsd
http://xbrl.org/2008/generic http://www.xbrl.org/2008/generic-link.xsd
http://xbrl.org/2008/reference http://www.xbrl.org/2008/generic-reference.xsd
http://xbrl.org/2008/label http://www.xbrl.org/2008/generic-label.xsd
http://xbrl.org/2011/table http://www.xbrl.org/2011/table.xsd
http://xbrl.org/2008/filter/dimension http://www.xbrl.org/2008/dimension-filter.xsd">
  <link:arcroleRef arcroleURI="http://xbrl.org/arcrole/2011/table-filter" xlink:type="simple" 
   xlink:href="http://www.xbrl.org/2011/table.xsd#table-filter"/>
  <link:arcroleRef arcroleURI="http://xbrl.org/arcrole/2011/table-axis" xlink:type="simple"
   xlink:href="http://www.xbrl.org/2011/table.xsd#table-axis"/>
  <link:arcroleRef arcroleURI="http://xbrl.org/arcrole/2011/axis-subtree" xlink:type="simple"
   xlink:href="http://www.xbrl.org/2011/table.xsd#axis-subtree"/>
  <link:arcroleRef arcroleURI="http://xbrl.org/arcrole/2011/axis-filter" xlink:type="simple"
   xlink:href="http://www.xbrl.org/2011/filter-axis.xsd#axis-filter"/>
</link:linkbase>
</nsmap>
<!--  Generated by Arelle(r) http://arelle.org --> 
'''
     )
    from arelle.ModelObjectFactory import parser
    parser, parserLookupName, parserLookupClass = parser(dts,None)
    from lxml import etree
    xmlDocument = etree.parse(file,parser=parser,base_url=updatedTableLinkbaseFile)
    file.close()
    nsmapElt = xmlDocument.getroot()
    #xmlDocument.getroot().init(self)  ## is this needed ??
    for lbElement in  xmlDocument.iter(tag=u"{http://www.xbrl.org/2003/linkbase}linkbase"):
        break
    
    class DocObj(object):  # fake ModelDocument for namespaces
        def __init__(self):
            self.xmlRootElement = lbElement
            self.xmlDocument = xmlDocument    
    docObj = DocObj()
    
    numELRs = 0
    numTables = 0
    
    def copyAttrs(fromElt, toElt, attrTags):
        for attr in attrTags:
            if fromElt.get(attr):
                toElt.set(attr, fromElt.get(attr))

    def generateTable(newLinkElt, newTblElt, srcTblElt, tblAxisRelSet, axisMbrRelSet, visited):
        if srcTblElt is not None:
            for rel in tblAxisRelSet.fromModelObject(srcTblElt):
                srcAxisElt = rel.toModelObject
                if isinstance(srcAxisElt, ModelEuAxisCoord):
                    visited.add(srcAxisElt)
                    newAxisElt = etree.SubElement(newLinkElt, u"{http://xbrl.org/2011/table}ruleAxis")
                    copyAttrs(srcAxisElt, newAxisElt, (u"id", 
                                                       u"{http://www.w3.org/1999/xlink}type",
                                                       u"{http://www.w3.org/1999/xlink}label"))
                    newAxisElt.set(u"abstract", u"true") # always true on root element
                    newArcElt = etree.SubElement(newLinkElt, u"{http://xbrl.org/2011/table}axisArc")
                    copyAttrs(rel, newArcElt, (u"id", 
                                               u"{http://www.w3.org/1999/xlink}type",
                                               u"{http://www.w3.org/1999/xlink}from",
                                               u"{http://www.w3.org/1999/xlink}to",
                                               u"order"))
                    newArcElt.set(u"{http://www.w3.org/1999/xlink}arcrole", XbrlConst.tableBreakdown)
                    newArcElt.set(u"axisDisposition", rel.axisDisposition)
                    generateAxis(newLinkElt, newAxisElt, srcAxisElt, axisMbrRelSet, visited)
                    visited.discard(srcAxisElt)

    def generateAxis(newLinkElt, newAxisParentElt, srcAxisElt, axisMbrRelSet, visited):
        for rel in axisMbrRelSet.fromModelObject(srcAxisElt):
            tgtAxisElt = rel.toModelObject
            if isinstance(tgtAxisElt, ModelEuAxisCoord) and tgtAxisElt not in visited:
                visited.add(tgtAxisElt)
                newAxisElt = etree.SubElement(newLinkElt, u"{http://xbrl.org/2011/table}ruleAxis")
                copyAttrs(tgtAxisElt, newAxisElt, (u"id", 
                                                   u"abstract",
                                                   u"{http://www.w3.org/1999/xlink}type",
                                                   u"{http://www.w3.org/1999/xlink}label"))
                if tgtAxisElt.primaryItemQname:
                    newRuleElt = etree.SubElement(newAxisElt, u"{http://xbrl.org/2008/formula}concept")
                    newQnameElt = etree.SubElement(newRuleElt, u"{http://xbrl.org/2008/formula}qname")
                    newQnameElt.text = XmlUtil.addQnameValue(docObj, tgtAxisElt.primaryItemQname)
                for dimQname, memQname in tgtAxisElt.explicitDims:
                    newRuleElt = etree.SubElement(newAxisElt, u"{http://xbrl.org/2008/formula}explicitDimension")
                    newRuleElt.set(u"dimension", XmlUtil.addQnameValue(docObj, dimQname))
                    newMbrElt = etree.SubElement(newRuleElt, u"{http://xbrl.org/2008/formula}member")
                    newQnameElt = etree.SubElement(newMbrElt, u"{http://xbrl.org/2008/formula}qname")
                    newQnameElt.text = XmlUtil.addQnameValue(docObj, memQname)
                newArcElt = etree.SubElement(newLinkElt, u"{http://xbrl.org/2011/table}axisArc")
                copyAttrs(rel, newArcElt, (u"id", 
                                           u"{http://www.w3.org/1999/xlink}type",
                                           u"{http://www.w3.org/1999/xlink}from",
                                           u"{http://www.w3.org/1999/xlink}to",
                                           u"order"))
                newArcElt.set(u"{http://www.w3.org/1999/xlink}arcrole", XbrlConst.tableAxisSubtree)
                generateAxis(newLinkElt, newAxisElt, tgtAxisElt, axisMbrRelSet, visited)
                visited.discard(tgtAxisElt)
        
    # sort URIs
    linkroleUris = sorted([linkroleUri
                           for linkroleUri in tblAxisRelSet.linkRoleUris])
    
    firstNewLinkElt = None
    roleRefUris = set()
    for linkroleUri in linkroleUris:
        numELRs += 1
        newLinkElt = etree.SubElement(lbElement, u"{http://xbrl.org/2008/generic}link")
        newLinkElt.set(u"{http://www.w3.org/1999/xlink}type", u"extended")
        newLinkElt.set(u"{http://www.w3.org/1999/xlink}role", linkroleUri)
        if firstNewLinkElt is None: firstNewLinkElt = newLinkElt
        # To do: add roleRef if needed
        tblAxisRelSet = dts.relationshipSet(XbrlConst.euTableAxis, linkroleUri)
        axisMbrRelSet = dts.relationshipSet(XbrlConst.euAxisMember, linkroleUri)
        for srcTblElt in tblAxisRelSet.rootConcepts:
            if srcTblElt.tag == u"{http://www.eurofiling.info/2010/rendering}table":
                numTables += 1
                newTblElt = etree.SubElement(newLinkElt, u"{http://xbrl.org/2011/table}table")
                newTblElt.set(u"aspectModel", u"dimensional")
                copyAttrs(srcTblElt, newTblElt, (u"id", 
                                                 u"{http://www.w3.org/1999/xlink}type",
                                                 u"{http://www.w3.org/1999/xlink}label"))
                generateTable(newLinkElt, newTblElt, srcTblElt, tblAxisRelSet, axisMbrRelSet, set())
                
                if linkroleUri not in roleRefUris:
                    srcRoleRefElt = XmlUtil.descendant(srcTblElt.getroottree(), XbrlConst.link, u"roleRef", u"roleURI", linkroleUri)
                    if srcRoleRefElt is not None:
                        roleRefUris.add(linkroleUri)
                        newRoleRefElt = etree.Element(u"{http://www.xbrl.org/2003/linkbase}roleRef")
                        copyAttrs(srcRoleRefElt, newRoleRefElt, (u"roleURI", 
                                                                 u"{http://www.w3.org/1999/xlink}type",
                                                                 u"{http://www.w3.org/1999/xlink}href"))
                        firstNewLinkElt.addprevious(newRoleRefElt)
            
    fh = open(updatedTableLinkbaseFile, u"w", encoding=u"utf-8")
    XmlUtil.writexml(fh, xmlDocument, encoding=u"utf-8")
    fh.close()
    
    dts.info(u"info:updateTableLinkbase",
             _(u"Updated Table Linkbase of %(entryFile)s has %(numberOfLinkroles)s linkroles, %(numberOfTables)s tables in file %(tableLBOutputFile)s."),
             modelObject=dts,
             entryFile=dts.uri, numberOfLinkroles=numELRs, numberOfTables=numTables, tableLBOutputFile=updatedTableLinkbaseFile)

def updateTableLBMenuEntender(cntlr, menu):
    # Extend menu with an item for the savedts plugin
    menu.add_command(label=u"Update table linkbase", 
                     underline=0, 
                     command=lambda: updateTableLBMenuCommand(cntlr) )

def updateTableLBMenuCommand(cntlr):
    # save DTS menu item has been invoked
    if cntlr.modelManager is None or cntlr.modelManager.modelXbrl is None:
        cntlr.addToLog(u"No taxonomy loaded.")
        return

        # get file name into which to save log file while in foreground thread
    updatedTableLinkbaseFile = cntlr.uiFileDialog(u"save",
                                                  title=_(u"arelle - Save Updated Table Linkbase file"),
            initialdir=cntlr.config.setdefault(u"tableLinkbaseFileDir",u"."),
            filetypes=[(_(u"Linkbase file .xml"), u"*.xml")],
            defaultextension=u".xml")
    if not updatedTableLinkbaseFile:
        return False
    import os
    cntlr.config[u"tableLinkbaseFileDir"] = os.path.dirname(updatedTableLinkbaseFile)
    cntlr.saveConfig()

    try: 
        generateUpdatedTableLB(cntlr.modelManager.modelXbrl, updatedTableLinkbaseFile)
    except Exception, ex:
        dts = cntlr.modelManager.modelXbrl
        dts.error(u"exception",
            _(u"Updated table linkbase generation exception: %(error)s"), error=ex,
            modelXbrl=dts,
            exc_info=True)

def updateTableLBCommandLineOptionExtender(parser):
    # extend command line options with a save DTS option
    parser.add_option(u"--save-updated-table-linkbase", 
                      action=u"store", 
                      dest=u"updatedTableLinkbaseFile", 
                      help=_(u"Update table linkbase file from Eurofiling 2010 to XII 2011 syntax."))

def updateTableLBCommandLineXbrlRun(cntlr, options, modelXbrl):
    # extend XBRL-loaded run processing for this option
    if getattr(options, u"updatedTableLinkbaseFile", None):
        if cntlr.modelManager is None or cntlr.modelManager.modelXbrl is None:
            cntlr.addToLog(u"No taxonomy loaded.")
            return
        generateUpdatedTableLB(cntlr.modelManager.modelXbrl, options.updatedTableLinkbaseFile)


__pluginInfo__ = {
    u'name': u'Update Table Linkbase',
    u'version': u'0.9',
    u'description': u"This plug-in updates a table linkbase from Eurofiling 2010 syntax to XII 2011 PWD syntax. "
                   u"The updated linkbase is saved to a local file.  "
                   u"Hrefs in the new file are identical the prior hrefs (not offset considering save-to directory).  ",
    u'license': u'Apache-2',
    u'author': u'Mark V Systems Limited',
    u'copyright': u'(c) Copyright 2012 Mark V Systems Limited, All rights reserved.',
    # classes of mount points (required)
    u'CntlrWinMain.Menu.Tools': updateTableLBMenuEntender,
    u'CntlrCmdLine.Options': updateTableLBCommandLineOptionExtender,
    u'CntlrCmdLine.Xbrl.Run': updateTableLBCommandLineXbrlRun,
}
