# (c) 2009-2015 Martin Wendt and contributors; see WsgiDAV https://github.com/mar10/wsgidav
# Original PyFileServer (c) 2005 Ho Chun Wei.
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
"""
WSGI container, that handles the HTTP requests. This object is passed to the 
WSGI server and represents our WsgiDAV application to the outside. 

On init:

    Use the configuration dictionary to initialize lock manager, property manager,
    domain controller. 

    Create a dictionary of share-to-provider mappings.         

    Initialize middleware objects and RequestResolver and setup the WSGI 
    application stack.
      
For every request:

    Find the registered DAV provider for the current request.   
    
    Add or modify info in the WSGI ``environ``:
    
        environ["SCRIPT_NAME"]
            Mount-point of the current share.            
        environ["PATH_INFO"]
            Resource path, relative to the mount path.
        environ["wsgidav.provider"]
            DAVProvider object that is registered for handling the current 
            request. 
        environ["wsgidav.config"]
            Configuration dictionary.
        environ["wsgidav.verbose"]
            Debug level [0-3].

    Log the HTTP request, then pass the request to the first middleware.

    Note: The OPTIONS method for the '*' path is handled directly.

See `Developers info`_ for more information about the WsgiDAV architecture.

.. _`Developers info`: http://wsgidav.readthedocs.org/en/latest/develop.html  
"""
from fs_dav_provider import FilesystemProvider
from wsgidav.dir_browser import WsgiDavDirBrowser
from wsgidav.dav_provider import DAVProvider
from wsgidav.addons.tracim.lock_storage import LockStorage
import time
import sys
import threading
import urllib
import util
from error_printer import ErrorPrinter
from debug_filter import WsgiDavDebugFilter
from http_authenticator import HTTPAuthenticator
from request_resolver import RequestResolver
from property_manager import PropertyManager
from lock_manager import LockManager
#from wsgidav.version import __version__

__docformat__ = "reStructuredText"


# Use these settings, if config file does not define them (or is totally missing)
DEFAULT_CONFIG = {
    "mount_path": None,  # Application root, e.g. <mount_path>/<share_name>/<res_path>               
    "provider_mapping": {},
    "host": "localhost",
    "port": 8080, 
    "ext_servers": [
#                   "paste", 
#                   "cherrypy",
#                   "wsgiref",
                   "cherrypy-bundled",
                   "wsgidav",
                   ],

    "add_header_MS_Author_Via": True,
    "unquote_path_info": False, # See #8
#    "use_text_files": False,

    "propsmanager": None,  # True: use property_manager.PropertyManager                  
    "locksmanager": True,  # True: use lock_manager.LockManager    
    
    # HTTP Authentication Options
    "user_mapping": {},       # dictionary of dictionaries 
    "domaincontroller": None, # None: domain_controller.WsgiDAVDomainController(user_mapping)
    "acceptbasic": True,      # Allow basic authentication, True or False
    "acceptdigest": True,     # Allow digest authentication, True or False
    "defaultdigest": True,    # True (default digest) or False (default basic)

    # Error printer options
    "catchall": False,
    
    "enable_loggers": [
                      ],

    # Verbose Output
    "verbose": 1,        # 0 - no output (excepting application exceptions)         
                         # 1 - show single line request summaries (for HTTP logging)
                         # 2 - show additional events
                         # 3 - show full request/response header info (HTTP Logging)
                         #     request body and GET response bodies not shown
    
    "dir_browser": {
        "enable": True,               # Render HTML listing for GET requests on collections
        "response_trailer": "",       # Raw HTML code, appended as footer
        "davmount": False,            # Send <dm:mount> response if request URL contains '?davmount'
        "ms_mount": False,            # Add an 'open as webfolder' link (requires Windows)
        "ms_sharepoint_plugin": True, # Invoke MS Offce documents for editing using WebDAV
        "ms_sharepoint_urls": False,  # Prepend 'ms-word:ofe|u|' to URL for MS Offce documents
    },
    "middleware_stack": [
        WsgiDavDirBrowser,
        HTTPAuthenticator,
        ErrorPrinter,
        WsgiDavDebugFilter,
    ]
}



def _checkConfig(config):
    mandatoryFields = ["provider_mapping",
                       ]
    for field in mandatoryFields:
        if not field in config:
            raise ValueError("Invalid configuration: missing required field '%s'" % field)




#===============================================================================
# WsgiDAVApp
#===============================================================================
class WsgiDAVApp(object):

    def __init__(self, config):
        self.config = config

        util.initLogging(config["verbose"], config.get("enable_loggers", []))
        
        util.log("Default encoding: %s (file system: %s)" % (sys.getdefaultencoding(), sys.getfilesystemencoding()))
        
        # Evaluate configuration and set defaults
        _checkConfig(config)
        provider_mapping = self.config["provider_mapping"]
#        response_trailer = config.get("response_trailer", "")
        self._verbose = config.get("verbose", 2)

        lockStorage = config.get("locksmanager") 
        if lockStorage is True:
            lockStorage = LockStorage()
            
        if not lockStorage:
            locksManager = None
        else:
            locksManager = LockManager(lockStorage)

        propsManager = config.get("propsmanager")     
        if not propsManager:
            # Normalize False, 0 to None
            propsManager = None
        elif propsManager is True:
            propsManager = PropertyManager()     

        mount_path = config.get("mount_path")
         
        # Instantiate DAV resource provider objects for every share
        self.providerMap = {}
        for (share, provider) in provider_mapping.items():
            # Make sure share starts with, or is, '/' 
            share = "/" + share.strip("/")

            # We allow a simple string as 'provider'. In this case we interpret 
            # it as a file system root folder that is published. 
            if isinstance(provider, basestring):
                provider = FilesystemProvider(provider)

            assert isinstance(provider, DAVProvider)

            provider.setSharePath(share)
            if mount_path:
                provider.setMountPath(mount_path)
            
            # TODO: someday we may want to configure different lock/prop managers per provider
            provider.setLockManager(locksManager)
            provider.setPropManager(propsManager)
            
            self.providerMap[share] = {"provider": provider, "allow_anonymous": False}
            

        
        # Define WSGI application stack
        application = RequestResolver()
        
        domain_controller = None
        dir_browser = config.get("dir_browser", {})
        middleware_stack = config.get("middleware_stack", [])

        
        # Replace WsgiDavDirBrowser to custom class for backward compatibility only
        # In normal way you should insert it into middleware_stack
        if dir_browser.get("enable", True) and "app_class
" in dir_browser.keys():
            config["middleware_stack"] = [m if m != WsgiDavDirBrowser else dir_browser['app_class'] for m in middleware_stack]

        for mw in middleware_stack:
            if mw.isSuitable(config):
                if self._verb
ose >= 2:
                        print "Middleware %s is suitable" % mw
                application = mw(application, config)
                