### codetube
    Copyright (C) 2011 payload payload@lavabit.com
    Copyright (C) 2011 dodo dodo.the.last@gmail.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>
###

require './ConsoleDummy'
window._ = require 'underscore'
window.formatdate = require 'formatdate'
{ FBD } = require './flashblockdetector'
{ Backbone, Storage } = require './Backbone'
{ Users } = require './collection/user'
{ Options } = require './collection/option'


class Router extends Backbone.Router
    routes:
        "/:owner/:project/"                   : "index"
        "/:owner/:project/tree/:branch/*path" : "tree"

    initialize: () ->
        Backbone.history.start pushState:on

    tree: ->
    index: ->


# we overload the getTransport method to return the last
# working transport first. This reduces wait time on non working
# transports like incompatible websocket versions
real_transport = io.Socket::getTransport

transports = []
io.Socket::getTransport = (override) ->
    real_transport.call(this, override or transports.concat(@transports))


class Client extends Backbone.EventHandler

    constructor: () ->
        @started = no
        buffered = binds:[], emits:[]
        # dummy to accept emits and binds before api is booted
        @api =
            on: (name, callback) ->   buffered.binds.push {name, callback}
            emit: (name, args...) -> buffered.emits.push {name, args}
            fire: (api) ->
                for bind in buffered.binds
                    api.on bind.name, bind.callback
                for emit in buffered.emits
                    api.emit(emit.name, emit.args...)
        do @initialize

    controller: {}

    initialize: () ->
        @collection = new Options
        @router = new Router
        @users = new Users this

    start: () =>
        dummy = @api
        @collection.fetch()
        # we have to detect flashblocker as they cause quite a delay on the socket.io stuff
        now = new Date().getTime()

        start = (has_fb) =>
            if has_fb
                io.transports = io.transports.filter (trans) -> return trans != "flashsocket"
            if cur = @collection.get("transport")
                if cur.get("time") + 3 * 60 * 60 * 1000 > now # 3 hours timeout
                    transports = [cur.get("worked")]
                else
                    cur.destroy()
                    cur = null

            last_transport_try = null
            @api = io.connect "/project", resource:".sio"
            @api.on 'connect', =>
                return if @started
                console.log "connected."
                dummy.fire @api
                @started = yes
                if not cur
                    @collection.create
                        worked: last_transport_try
                        time  : now
                        id    : "transport"
                else
                    cur.set
                        worked: last_transport_try

                @trigger 'start'
            @api.on 'connecting', (type) =>
                console.log('try', type)
                last_transport_try = type

        fb_cache = @collection.get("flashblock")
        if fb_cache and fb_cache.get("time") + 60 * 60 * 1000 > now # 1 hours timeout
            start(fb_cache["detected"])
        else
            fb_cache.destroy() if fb_cache
            FBD.initialize (has_fb) =>
                @collection.create { id: "flashblock", time: now, detected: has_fb }
                start(has_fb)

    bind: (name, callback) =>
        if name is 'start' and @started
            callback()
        else
            super


module.exports = client: window.client = client = new Client

client.bind 'start', () ->
    # defaults
    formatdate.options.max.unit = 6
    formatdate.options.max.amount = 0
    formatdate.hook 'html'

