# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is Reportek version 1.0.
#
# The Initial Developer of the Original Code is European Environment
# Agency (EEA).  Portions created by Finsiel are
# Copyright (C) European Environment Agency.  All
# Rights Reserved.
#
# Contributor(s):
# Cornel Nitu, Finsiel Romania

__doc__ = """
      QARepository product module.
      The QARepository is used to make different type of quality assurance checks
      of the Report Documents.
"""
import xmlrpclib
import os

from OFS.Folder import Folder
from AccessControl import ClassSecurityInfo
from AccessControl.Permissions import view_management_screens
import Globals

import constants
import QAScript

class QARepository(Folder):
    """ """
    meta_type = 'Reportek QARepository'
    icon = 'misc_/Reportek/QARepository'

    #security stuff
    security = ClassSecurityInfo()

    def __init__(self):
        """ """
        self.id = constants.QAREPOSITORY_ID
        self.QA_application = 'EnvelopeQAApplication'

    def __setstate__(self,state):
        QARepository.inheritedAttribute('__setstate__')(self, state)
        if not hasattr(self,'QA_application'):
            self.QA_application = 'EnvelopeQAApplication'

    meta_types = ({'name': 'QAScript',         'action': 'manage_addQAScriptForm'},)
    all_meta_types = meta_types

    manage_addQAScriptForm = QAScript.manage_addQAScriptForm
    manage_addQAScript = QAScript.manage_addQAScript

    manage_options = (
        Folder.manage_options[:2]
        +
        (
            {'label' : 'Remote QA Scripts', 'action' : 'manage_qascripts_html'},
        )
        +
        Folder.manage_options[3:-2]
    )

    def getQAApplication(self):
        """ """
        return self.unrestrictedTraverse(self.QA_application, None)

    def _get_local_qa_scripts(self, p_schema=None):
        """ """
        if p_schema:
            return [x for x in self.objectValues('QAScript') if x.xml_schema == p_schema]
        else:
            return self.objectValues('QAScript')

    def _get_remote_qa_scripts(self, p_schema=None):
        """ """
        l_qa_app = self.getQAApplication()
        if not l_qa_app:
            return []
        l_server_url = l_qa_app.RemoteServer
        l_remote_server = l_qa_app.RemoteService
        try:
            l_server = xmlrpclib.ServerProxy(l_server_url, allow_none=True)
            # fixme: Java doesn't interpret <nill/> so no value is returned
            return eval('l_server.%s.listQueries(\'%s\')' %(l_remote_server, p_schema))
        except:
            return []

    def getQAScriptsDescriptions(self):
        """ Loops all local and remote QA scripts for display """
        return [self._get_local_qa_scripts(), self._get_remote_qa_scripts()]

    security.declareProtected('View', 'getQAScriptsForSchema')
    def getQAScriptsForSchema(self, p_schema):
        """ Returns the list of QA script ids available for an XML type
        """
        if not p_schema:
            return []
        l_ret = []
        # local scripts
        l_ret.extend([x.id for x in self._get_local_qa_scripts() if x.xml_schema == p_schema])
        # remote scripts
        l_qa_app = self.getQAApplication()
        if l_qa_app:
            l_server_url = l_qa_app.RemoteServer
            l_remote_server = l_qa_app.RemoteService
            try:
                l_server = xmlrpclib.ServerProxy(l_server_url)
                l_tmp = eval('l_server.%s.listQAScripts(\'%s\')' %(l_remote_server, p_schema))
                l_ret.extend([x[0] for x in l_tmp])
            except:
                pass
        return l_ret

    def getDataflowMappingsContainer(self):
        """ """
        return getattr(self, constants.DATAFLOW_MAPPINGS)

    security.declareProtected('View', 'canRunQAOnFiles')
    def canRunQAOnFiles(self, files):
        """ Returns a list of QA script labels
            which can be manually run against the contained XML files
        """
        l_ret = {}
        l_qa_app = self.getQAApplication()
        if l_qa_app:
            l_server_url = l_qa_app.RemoteServer
            l_remote_server = l_qa_app.RemoteService

        for l_file in files:
            # get the valid schemas for the envelope's dataflows
            l_valid_schemas = self.getDataflowMappingsContainer().getXMLSchemasForDataflows(l_file.dataflow_uris)
            # go on only if it's an XML file with a non-empty valid schema or if no valid schemas
            # are defined for those dataflows
            if l_file.xml_schema_location and (l_file.xml_schema_location in l_valid_schemas or not l_valid_schemas):
                #local scripts
                l_buff = [['loc_%s' % y.id, y.title, y.bobobase_modification_time()] for y in self._get_local_qa_scripts(l_file.xml_schema_location)]
                if len(l_buff):
                    l_ret[l_file.id] = l_buff
                #remote scripts
                if l_qa_app:
                    try:
                        l_server = xmlrpclib.ServerProxy(l_server_url)
                        l_tmp = eval('l_server.%s.listQAScripts(\'%s\')' %(l_remote_server, l_file.xml_schema_location))
                        if len(l_tmp) > 0:
                            # take just the script id and title
                            if l_ret.has_key(l_file.id):
                                l_ret[l_file.id].extend(l_tmp)
                            else:
                                l_ret[l_file.id] = l_tmp
                    except:
                        pass
        return l_ret

    def _runQAScript(self, p_file_url, p_script_id):
        """ Runs the QA script with the specified id against
            the source XML file

            If the id starts with 'loc_', then the script is local (Python),
            otherwise call the query service

            This method can be only called from the browser and the result is 
            displayed in a temporary page
        """
        l_res_ct = 'text/plain'
        l_res_data = QAResult()

        l_file_id = p_file_url.split('/')[-1]
        # local script
        if p_script_id.startswith('loc_'):

            l_script_obj = getattr(self, p_script_id.replace('loc_', ''), None)
            p_file_url = p_file_url.replace('%s/' % self.REQUEST.SERVER_URL, '')
            file_obj = self.unrestrictedTraverse(p_file_url, None)

            if file_obj is None or l_script_obj is None:
                l_res_data.data = 'QA error'
            else:
                if l_script_obj.content_type_out:
                    l_res_ct = l_script_obj.content_type_out

                    #generate 'filename'
                    if l_script_obj.content_type_out in constants.CONTENT_TYPES.keys():
                        output_fname = "%s%s" % (file_obj.id[:file_obj.id.rfind('.')], constants.CONTENT_TYPES[l_script_obj.content_type_out])
                    else:
                        output_fname = "QAResults"

                    #generate extra-parameters
                    params = [file_obj.physicalpath()] #the file path is set default as first parameter
                    for k in l_script_obj.qa_extraparams:
                        params.append(eval(k))

                    #REQUEST.RESPONSE.setHeader('Content-Disposition', 'inline; filename=%s' % output_fname)
                    l_res_data.data = os.popen(l_script_obj.script_url % tuple(params)).read()
                else:
                    l_res_data.data =  'QA error'
            l_tmp = [l_res_ct, l_res_data]
        # remote script
        else:
            l_qa_app = self.getQAApplication()
            l_server_url = l_qa_app.RemoteServer
            l_remote_server = l_qa_app.RemoteService
            l_server = xmlrpclib.ServerProxy(l_server_url)
            l_tmp = eval('l_server.%s.runQAScript(\'%s\', \'%s\')' %(l_remote_server, p_file_url, p_script_id))
        return l_file_id, l_tmp

    security.declareProtected(view_management_screens, 'manage_edit')
    def manage_edit(self, QA_application, REQUEST=None):
        """ """
        self.QA_application = QA_application
        if REQUEST:
            message="Content changed"
            return self.manage_qascripts_html(self,REQUEST,manage_tabs_message=message)

    security.declareProtected(view_management_screens, 'manage_qascripts_html')
    manage_qascripts_html = Globals.DTMLFile('dtml/qascriptsEdit', globals())

    security.declareProtected(view_management_screens, 'index_html')
    index_html = Globals.DTMLFile('dtml/qascriptsIndex', globals())

Globals.InitializeClass(QARepository)

class QAResult:
    """ container for QAScript results """
    def __init__(self):
        self.data = ''