 # IPython Support
 #**************************************************
 
-class IPythonNotebookServer
-    constructor: (@project_id, @path) ->  # path = a directory where server serves files from
-
-    start_server: (cb) =>  # cb(err, base url)
+ipython_notebook_server = (opts) ->
+    opts = defaults opts,
+        project_id : required
+        path       : required   # directory from which the files are served
+        cb         : required   # cb(err, server)
+
+    I = new IPythonNotebookServer(opts.project_id, opts.path)
+    I.start_server (err, base) =>
+        opts.cb(err, I)
+
+class IPythonNotebookServer  # call ipython_notebook_server above
+    constructor: (@project_id, @path) ->
+
+    start_server: (cb) =>
         salvus_client.exec
             project_id : @project_id
             path       : @path

        s = path_split(@filename)
        @path = s.head
        @file = s.tail
        @server = new IPythonNotebookServer(@editor.project_id, @path)

        @doc = syncdoc.synchronized_string
            project_id : @editor.project_id
            filename   : @filename
            cb         : () =>


        @doc.on 'sync', @doc_sync


        # This is where we put the page itself
        @notebook = @element.find(".salvus-ipython-notebook-notebook")

        con = @element.find(".salvus-ipython-notebook-connecting")
        con.show().icon_spin(start:true)
        @server.start_server (err, url) =>
            @url = url
            if err
                alert_message(type:"error", message:"Unable to start IPython server -- #{url}")
                con.show().icon_spin(false).hide()
                return

            wait_for_url_to_work
                url : url
                cb  : (err) =>
                    con.show().icon_spin(false).hide()
                    if err
                        alert_message(type:"error", message:"Unable to connect to IPython server -- #{url}")
                        return
                    @iframe_uuid = misc.uuid()
                    @iframe = $("<iframe name=#{@iframe_uuid} id=#{@iframe_uuid}>").attr('src', url + @file)
                    @notebook.html('').append(@iframe)
                    @show()

                    # Monkey patch the IPython html so clicking on the IPython logo pops up a a new tab with the dashboard,
                    # instead of messing up our embedded view.
                    attempts = 0
                    f = () =>
                        attempts += 1
                        if attempts >= 100
                            # just give up -- this isn't at all critical; don't want to waste resources.
                            return
                        @frame = window.frames[@iframe_uuid]
                        if not @frame? or not @frame.$? or not @frame.IPython? or not @frame.IPython.notebook?
                            setTimeout(f, 100)
                        else
                            a = @frame.$("#ipython_notebook").find("a")
                            if a.length == 0
                                setTimeout(f, 100)
                            else
                                a.attr('target', '_blank')
                                @frame.$('<style type=text/css></style>').html(".container{width:98%; margin-left: 0;}").appendTo(@frame.$("body"))
                                @_save_checkpoint = @frame.IPython.notebook.save_checkpoint
                                @frame.IPython.notebook.save_checkpoint = @save
                                #try
                                g = () =>
                                    @doc_sync()
                                setTimeout(g, 250)  # TODO --

                                setInterval(@autosync, 3000)
                                #catch e
                                #    console.log("can't set initial version since json invalid -- #{@doc.live()}")

                    setTimeout(f, 100)

    autosync: () =>
        if @frame.IPython.notebook.dirty

                console.log(err, output)
                cb?(err)

get_with_retry = (opts) ->
    opts = defaults opts,
        url           : required
        initial_delay : 100
        max_delay     : 15000     # once delay hits this, give up
        factor        : 1.2       # for exponential backoff
        cb            : required  # cb(err, data)  # data = content of that url
    delay = opts.initial_delay
    f = () =>
        if delay >= opts.max_delay  # too many attempts
            opts.cb("unable to connect to remote server")
            return
        $.get(opts.url, (data) ->
            if 'ECONNREFUSED' in data
                delay *= opts.factor
                setTimeout(f, delay)
            else
                opts.cb(false, data)
        ).fail(() ->
            delay *= 1.2
            setTimeout(f, delay)
