# -*- coding: utf-8 -*-
"""
    sockjs.tornado.router
    ~~~~~~~~~~~~~~~~~~~~~

    SockJS protocol router implementation.
"""

from tornado import ioloop, version_info

from sockjs.tornado import transports, session, sessioncontainer, static, stats, proto


DEFAULT_SETTINGS = {
    # Sessions check interval in seconds
    'session_check_interval': 1,
    # Session expiration in seconds
    'disconnect_delay': 5,
    # Heartbeat time in seconds. Do not change this value unless
    # you absolutely sure that new value will work.
    'heartbeat_delay': 25,
    # Enabled protocols
    'disabled_transports': [],
    # SockJS location
    'sockjs_url': 'https://cdn.jsdelivr.net/sockjs/0.3/sockjs.min.js',
    # Max response body size
    'response_limit': 128 * 1024,
    # Enable or disable JSESSIONID cookie handling
    'jsessionid': True,
    # Should sockjs-tornado flush messages immediately or queue then and
    # flush on next ioloop tick
    'immediate_flush': True,
    # Enable or disable Nagle for persistent transports
    'disable_nagle': True,
    # Enable IP checks for polling transports. If enabled, all subsequent
    # polling calls should be from the same IP address.
    'verify_ip': True,
    # list of allowed origins for websocket connections
    # or "*" - accept all websocket connections
    'websocket_allow_origin': "*"
    }

GLOBAL_HANDLERS = [
    ('xhr_send', transports.XhrSendHandler),
    ('jsonp_send', transports.JSONPSendHandler)
]

TRANSPORTS = {
    'websocket': transports.WebSocketTransport,
    'xhr': transports.XhrPollingTransport,
    'xhr_streaming': transports.XhrStreamingTransport,
    'jsonp': transports.JSONPTransport,
    'eventsource': transports.EventSourceTransport,
    'htmlfile': transports.HtmlFileTransport
}

STATIC_HANDLERS = {
    '/chunking_test': static.ChunkingTestHandler,
    '/info': static.InfoHandler,
    '/iframe[0-9-.a-z_]*.html': static.IFrameHandler,
    '/websocket': transports.RawWebSocketTransport,
    '/?': static.GreetingsHandler
}


class SockJSRouter(object):
    """SockJS protocol router"""
    def __init__(self,
                 connection,
                 prefix='',
                 user_settings=dict(),
                 io_loop=None):
        """Constructor.

        `connection`
            SockJSConnection class
        `prefix`
            Connection prefix
        `user_settings`
            Settings dictionary
        `io_loop`
            Optional IOLoop instance
        """

        # TODO: Version check
        if version_info[0] < 2:
            raise Exception('sockjs-tornado requires Tornado 2.0 or higher.')

        # Store connection class
        self._connection = connection

        # Initialize io_loop
        self.io_loop = io_loop or ioloop.IOLoop.instance()

        # Settings
        self.settings = DEFAULT_SETTINGS.copy()
        if user_settings:
            self.settings.update(user_settings)

        self.websockets_enabled = 'websocket' not in self.settings['disabled_transports']
        self.cookie_needed = self.settings['jsessionid']

        # Sessions
        self._sessions = sessioncontainer.SessionContainer()

        check_interval = self.settings['session_check_interval'] * 1000
        self._sessions_cleanup = ioloop.PeriodicCallback(self._sessions.expire,
                                                         check_interval,
                                                         self.io_loop)
        self._sessions_cleanup.start()

        # Stats
        self.stats = stats.StatsCollector(self.io_loop)

        # Initialize URLs
        base = prefix + r'/[^/.]+/(?P<session_id>[^/.]+)'

        # Generate global handler URLs
        self._transport_urls = [('%s/%s$' % (base, p[0]), p[1], dict(server=self))
                                for p in GLOBAL_HANDLERS]

        for k, v in TRANSPORTS.items():
            if k in self.settings['disabled_transports']:
                continue

            # Only version 1 is supported
            self._transport_urls.append(
                (r'%s/%s$' % (base, k),
                 v,
                 dict(server=self))