"""
$URL: svn+ssh://svn.mems-exchange.org/repos/trunk/dulcinea/lib/common.py $
$Id: common.py 28619 2006-08-18 20:46:32Z dbinger $
"""
import os
import os.path
import sys
from cStringIO import StringIO
from sancho.utest import UTest
import dulcinea
from dulcinea.site_util import get_config_value

def is_qp():
    return os.environ.get('QP') == '1'

if not is_qp():
    from dulcinea.site_util import SiteModule, parse_address, is_live
    from dulcinea.site_util import is_email_enabled
    dulcinea.local = SiteModule()
    sys.modules['dulcinea.local'] = dulcinea.local
    from quixote.ptl import install
    _used = install
    def get_site_name():
        site = os.environ.get('SITE', 'test')
        return site
    import quixote.publish
    from qp.lib.util import import_object

    from durus.client_storage import ClientStorage
    from durus.file_storage import FileStorage
    from durus.connection import Connection

    def create_publisher(connection=None, **kwargs):
        """
        This can only be called when there is no global publisher.
        If no connection is given, a client Connection is constructed.
        Outside code should only call this if it needs to pass extra
        keyword arguments to the Publisher constructor.
        """
        assert quixote.publish.get_publisher() is None
        site = get_site_name()
        if site == 'test':
            assert connection is None
            publisher_class_name = 'dulcinea.ui.publisher.DulcineaPublisher'
            import dulcinea.test.local
            connection = dulcinea.test.local.make_test_connection()
        else:
            publisher_class_name = get_config_value(
                'publisher', site=site,
                fallback='dulcinea.ui.publisher.DulcineaPublisher')
            if connection is None:
                durus_address = get_config_value('durus_address', site=site)
                host, port = parse_address(durus_address)
                storage = ClientStorage(port=port, host=host)
                connection = Connection(storage=storage)
        publisher_class = import_object(publisher_class_name)
        return publisher_class(connection=connection, **kwargs)

    def get_publisher():
        """() -> Publisher
        Return the global publisher, if it already exists.
        If it does not already exist, make one using a client
        storage if possible.
        """
        return quixote.publish.get_publisher() or create_publisher()

    def open_connection(filename=None, readonly=False):
        """(filename=None|str, readonly=True|False) -> Connection
        This can only be called when there is not yet a global publisher.
        This forces a publisher to be made using a FileStorage connection.
        The storage is readonly if the readonly keyword value is True.
         If the filename is given, it is used as the file for the FileStorage.
        If it is not given, the default filename for the site is used.
        """
        assert quixote.publish.get_publisher() is None
        if filename is None:
            site = get_site_name()
            var_directory = get_config_value('var_directory', site=site)
            filename = os.path.join(var_directory, "%s.durus" % site)
        else:
            assert type(filename) is str
        assert readonly in (True, False)
        storage = FileStorage(filename=filename, readonly=readonly)
        publisher = create_publisher(connection=Connection(storage))
        connection = publisher.get_connection()
        assert readonly is False or connection.storage.fp.mode == 'rb'
        return connection

    from quixote import redirect as quixote_redirect
    def redirect(location, permanent=False):
        quixote_redirect(location, permanent=permanent)
        get_publisher().respond_now()
    from quixote import get_field, get_path, get_session
    from quixote import get_request, get_user, get_response

    from quixote.form.css import BASIC_FORM_CSS
    from quixote.form import Form
    from quixote.form.widget import MultipleSelectWidget, ButtonWidget
    from quixote.form.widget import NumberWidget, FloatWidget, IntWidget
    from quixote.form.widget import OptionSelectWidget, CompositeWidget
    from quixote.form.widget import SingleSelectWidget, RadiobuttonsWidget
    from quixote.form.widget import StringWidget, FileWidget, PasswordWidget
    from quixote.form.widget import SubmitWidget, ResetWidget, HiddenWidget
    from quixote.form.widget import TextWidget, CheckboxWidget, SelectWidget
    from quixote.form.widget import WidgetList, WidgetDict, subname, Widget
    from quixote.form.widget import WidgetValueError
    from quixote.html import htmltag, href, url_quote, nl2br
    from quixote.html import stringify, htmltext, htmlescape
    from quixote.html import url_with_query
    from quixote.util import FileStream, StaticFile
    from quixote.util import StaticDirectory as QuixoteStaticDirectory
    from qp.fill.directory import Directory as QPDirectory
    class Directory(QPDirectory):
        """
        This copies the code for two methods here so that the get_path()-type
        functions can be bound to the quixote versions.
        """
        def _q_traverse(self, path):
            """(path: [string]) -> None|Stream|object

            Traverse a path and return the result.  This is what the
            Publisher calls.  The result will be used to set the body of
            the http response.  If the result is None, the Publisher will
            use not_found() to set the 404 response.  If the result is an
            instance of Stream, it will be written out in in chunks.
            Otherwise, the str() of the result of this call will be used
            as the body of the http response.

            Subclasses don't normally need to override this, but may do so.
            This may be useful to provide access control or to implement
            directories that process the entire path themselves.
            """
            component = path[0]
            name = self._q_translate(component)
            if name is None:
                obj = self._q_lookup(component)
            else:
                obj = getattr(self, name)
            if obj is None:
                not_found('%r?' % component)
            if path[1:]:
                if hasattr(obj, '_q_traverse'):
                    result = obj._q_traverse(path[1:])
                else:
                    not_found()
            elif callable(obj):
                result = obj()
            else:
                result = obj
            if result is None:
                not_found()
            else:
                return result

        def __call__(self):
            """() -> None|Stream|object
            If the _q_traverse() of a Directory reaches this instance,
            and there are no more components, it calls this instance.
            We could return None to cause a 404 response, but we'll try
            adding a slash to the end of the url if it looks like that
            appears to be the intent of the current request.
            """
            if (self._q_translate('') is not None and
                not get_request().get_fields()):
                # Fix missing trailing slash.
                return redirect(get_request().get_environ("PATH_INFO") + "/", permanent=True)
            else:
                return None

    class StaticDirectory(QuixoteStaticDirectory):

        def get_exports(self):
            if self.list_directory:
                yield ('', '_q_index', self.path, None)
            files = os.listdir(self.path)
            files.sort()
            for name in files:
                file_path = os.path.join(self.path, name)
                if os.path.islink(file_path):
                    continue
                if os.path.isdir(file_path):
                    yield (name, None, name + '/', None)
                else:
                    yield (name, None, name, None)

    def set_test_environment(input_string='', **env):
        """
        Make a publisher if necessary, and in any case make sure that
        the conection is readonly.
        Make a request with the given body and environment and
        set the request on the publisher, as if the publisher had
        just started processing the request.
        """
        env.setdefault('SCRIPT_NAME', '')
        env.setdefault('PATH_INFO', '/')
        from quixote.http_request import HTTPRequest
        from quixote.logger import DefaultLogger
        import sys
        def __init__(self, **kwargs):
            self.error_log = sys.stdout
            self.access_log = None
            self.error_email = None
        DefaultLogger.__init__ = __init__
        if quixote.publish.get_publisher() is None:
            if get_site_name() in (None, 'test'):
                get_connection()
            else:
                open_connection(readonly=True)
        publisher = get_publisher()
        storage_fp = getattr(get_connection().get_storage(), 'fp', None)
        assert storage_fp is None or storage_fp.mode == 'rb'

        session_cookie_name = get_publisher().get_session_cookie_name()
        session_key = "test"
        cookies='%s="%s"' % (session_cookie_name, session_key)
        env['HTTP_COOKIE'] = cookies

        publisher._set_request(HTTPRequest(StringIO(input_string), env))

        session = get_publisher().session_manager._create_session()
        session.id = session_key
        get_request().session = session
        get_publisher().get_sessions()[session_key] = session
        def nothing(*args):
            pass
        publisher.abort = nothing
        publisher.commit = nothing
        publisher._clear_request = nothing
        quixote.publish._publisher = publisher

    class CommonTest (UTest):
        """
        Run the tests with a readonly connection for the site.
        """
        def _pre(self):
            UTest._pre(self)
            site = get_site_name()
            assert site in (None, 'test') or not is_live(site)
            assert not is_email_enabled()
            set_test_environment()
            get_connection().abort()

    from dulcinea.sendmail import sendmail


    def get_javascript_code():
        return get_response().javascript_code

    def add_javascript_code(name, javascript):
        get_response().add_javascript(name, javascript)
    from dulcinea.ui.directory import get_crumb_tree
else:
    from qp.pub.common import get_publisher as qp_get_publisher
    def get_publisher():
        publisher = qp_get_publisher()
        if publisher:
            return publisher
        from qp.lib.site import Site
        site = Site(os.environ.get('SITE'))
        publisher = site.get_publisher()
        return publisher
    import dulcinea.uiqp
    import sys
    sys.modules['dulcinea.ui'] = dulcinea.uiqp
    dulcinea.ui = dulcinea.uiqp
    def get_site_name():
        return get_publisher().get_site().get_name()
    from qpy import stringify, h8
    htmltext = h8
    htmlescape = h8.quote
    from qp.fill.html import htmltag, href, nl2br, url_quote, url_with_query
    from qp.pub.common import get_request, get_user, get_response
    from qp.pub.common import redirect, get_path, get_session
    def get_field(x, default=None):
        return get_request().get_field(x, default)
    from qp.fill.css import BASIC_FORM_CSS
    from qp.fill.directory import Directory, get_crumb_tree
    from qp.fill.form import Form, add_javascript_code, get_javascript_code
    from qp.fill.static import FileStream, StaticFile, StaticDirectory
    from qp.fill.widget import MultipleSelectWidget, ButtonWidget
    from qp.fill.widget import NumberWidget, FloatWidget, IntWidget
    from qp.fill.widget import OptionSelectWidget, CompositeWidget
    from qp.fill.widget import SingleSelectWidget, RadiobuttonsWidget
    from qp.fill.widget import StringWidget, FileWidget, PasswordWidget
    from qp.fill.widget import SubmitWidget, ResetWidget, HiddenWidget
    from qp.fill.widget import TextWidget, CheckboxWidget, SelectWidget
    from qp.fill.widget import WidgetList, WidgetDict, subname, Widget
    from qp.fill.widget import WidgetValueError
    from qp.pub.common import header, page

    def set_test_environment(input_string='', **env):
        env.setdefault('SCRIPT_NAME', '')
        env.setdefault('PATH_INFO', '/')
        env.setdefault('SERVER_NAME', 'example.org')
        from qp.pub.hit import Hit
        session_key = "test"
        cookies='%s="%s"' % (get_site_name(), session_key)
        env['HTTP_COOKIE'] = cookies
        hit = Hit(StringIO(input_string), env)
        publisher = get_publisher()
        publisher.set_hit(hit)
        session = publisher.create_session()
        publisher.get_sessions()[session_key] = session
        hit.set_session(session)
        def nothing(*args):
            pass
        publisher.commit = nothing

    class CommonTest (UTest):

        def _pre(self):
            set_test_environment()
            get_connection().abort()

    from qp.mail.send import sendmail
    import dulcinea
    class Local (object):
        def __getattr__(self, name):
            return getattr(get_publisher(), name)

    dulcinea.local = Local()
    sys.modules['dulcinea.local'] = dulcinea.local


def get_fields():
    return get_request().get_fields()

def header(title, *args, **kwargs):
    return get_publisher().header(title, *args, **kwargs)

def page(title, *content, **kwargs):
    return get_publisher().page(title, *content, **kwargs)

def footer(*args, **kwargs):
    return get_publisher().footer(*args, **kwargs)

def not_found(*args, **kwargs):
    return get_publisher().not_found(*args, **kwargs)

def access_denied(body=None):
    return get_publisher().respond('Access Denied',
        body or 'That is not currently allowed.', status=403)

def invalid_query(body='Unable to answer that query.'):
    return get_publisher().respond('Invalid Query',
        body or 'Unable to answer that query.', status=400)

def format_user(user, **kwargs):
    return get_publisher().format_user(user, **kwargs)

def format_user_profile(user):
    return get_publisher().format_user_profile(user)

def format_date(date):
    return get_publisher().format_date(date)

def format_date_time(date):
    return get_publisher().format_date_time(date)

def format_login_agreement():
    return get_publisher().format_login_agreement()

def get_feedback_domain():
    return get_publisher().get_feedback_domain()

def get_feedback_addresses():
    return get_publisher().get_feedback_addresses()

def get_site_title():
    return get_publisher().get_site_title()

def get_connection():
    return get_publisher().get_connection()


_used = [get_publisher, stringify, htmltext, htmlescape, htmltag, href,
         url_quote, nl2br, url_with_query, get_request, get_user, get_response,
         get_field, redirect, get_path, get_session,
         Form, StringWidget, FileWidget, PasswordWidget, TextWidget,
         CheckboxWidget, SelectWidget, SingleSelectWidget, RadiobuttonsWidget,
         MultipleSelectWidget, ButtonWidget, SubmitWidget, ResetWidget,
         HiddenWidget, NumberWidget, FloatWidget, IntWidget,
         OptionSelectWidget, CompositeWidget, WidgetList, WidgetDict,
         subname, Widget, WidgetValueError, FileStream, Directory,
         header, footer, page, StaticFile, StaticDirectory,
         format_user, format_user_profile, format_date, format_date_time,
         format_login_agreement, get_feedback_domain, get_feedback_addresses,
         BASIC_FORM_CSS, CommonTest, sendmail, get_crumb_tree,
         add_javascript_code, get_javascript_code]


