define([
    '/api/config?cb=' + Math.random().toString(16).substring(2),
    '/customize/messages.js?app=poll',
    'table.js',
    'wizard.js',
    '/bower_components/textpatcher/TextPatcher.js',
    '/bower_components/chainpad-listmap/chainpad-listmap.js',
    '/bower_components/chainpad-crypto/crypto.js',
    '/common/cryptpad-common.js',
    '/common/visible.js',
    '/common/notify.js',
    '/bower_components/file-saver/FileSaver.min.js',
    '/bower_components/jquery/dist/jquery.min.js',
], function (Config, Messages, Table, Wizard, TextPatcher, Listmap, Crypto, Cryptpad, Visible, Notify) {
    var $ = window.jQuery;
    var saveAs = window.saveAs;

    Cryptpad.styleAlerts();
    console.log("Initializing your realtime session...");

    /*  TODO
        * set range of dates/times
          * (pair of date pickers)
        * hide options within that range
        * show hidden options
        * add notes to a particular time slot

        * check or uncheck options for a particular user
        * mark preference level? (+1, 0, -1)

        * delete/hide columns/rows

        // let users choose what they want the default input to be...

        * date
          - http://foxrunsoftware.github.io/DatePicker/ ?
        * ???
    */

    var secret = Cryptpad.getSecrets();
    var readOnly = secret.keys && !secret.keys.editKeyStr;
    if (!secret.keys) {
        secret.keys = secret.key;
    }
    if (readOnly) {
        $('#mainTitle').html($('#mainTitle').html() + ' - ' + Messages.readonly);
        $('#adduser, #addoption, #howToUse').remove();
    }

    var module = window.APP = {
        Cryptpad: Cryptpad,
    };

    module.getResults = function () {
        if (!module.ready) { return []; }
        var table = module.rt.proxy.table;
        var cells = table.cells;
        var rows = table.rows;

        return Object.keys(rows).map(function (id) {
            var text = rows[id];
            var count = Object.keys(cells).filter(function (c) {
                return c.indexOf(id) !== -1 && cells[c];
            }).length;
            return {
                text: text,
                count: count,
            };
        }).sort(function (a,b) {
            return b.count - a.count;
        });
    };

    var getLastName = module.getLastName = function (cb) {
        Cryptpad.getAttribute('username', function (err, userName) {
            cb(err, userName || '');
        });
    };

    var setName = module.setName = function (uname, cb) {
        if (typeof(uname) !== 'string') {
            return void cb(new Error('expected string'));
        }
        uname = Cryptpad.fixHTML(uname.trim()).slice(0, 32);
        Cryptpad.setAttribute('username', uname, function (err, data) {
            if (err) { return void cb(err); }
            cb(void 0, uname);
        });
    };

    module.Wizard = Wizard;

    // special UI elements
    var $title = $('#title').attr('placeholder', Messages.poll_titleHint || 'title');
    var $description = $('#description').attr('placeholder', Messages.poll_descriptionHint || 'description');

    var items = [$title, $description];

    var Uid = function (prefix, f) {
        f = f || function () {
            return Number(Math.random() * Number.MAX_SAFE_INTEGER)
                .toString(32).replace(/\./g, '');
        };
        return function () { return prefix + '-' + f(); };
    };

    var xy = function (x, y) { return x + '_' + y; };
    var parseXY = function (id) {
        var p = id.split('_');
        return {
            x: p[0],
            y: p[1],
        };
    };

    var Input = function (opt) { return $('<input>', opt); };
    var Checkbox = function (id) {
        var p = parseXY(id);

        var proxy = module.rt.proxy;

        var $div = $('<div>', {
            'class': 'checkbox-contain',
        });

        var $cover = $('<span>', {
            'class': 'cover'
        });

        var $label = $('<label>', {
            'for': id,
        }); //.text("WAT");

        var $check = Input({
            id: id,
            name: id,
            type:'checkbox',
        }).on('change', function () {
            //console.log("(%s, %s) => %s", p.x, p.y, $check[0].checked);
            var checked = proxy.table.cells[id] = $check[0].checked? 1: 0;
            if (checked) {
                $cover.addClass('yes');
            }
            else {
                $cover.removeClass('yes');
            }
        });

        if (p.x === module.activeColumn) {
            $check.addClass('editable');
        }

        $div
            //.append($label)
            .append($check)
            .append($label);
        $check.after($cover);

        return $div; //$check;
    };
    var Text = function () { return Input({type:'text'}); };

    var table = module.table = Table($('#table'), xy);

    var setEditable = function (bool) {
        if (readOnly && bool) { return; }
        module.isEditable = bool;

        items.forEach(function ($item) {
            $item.attr('disabled', !bool);
       });

        if (!bool) {
            $('input[id^="y"]').each(function (i, e) {
                var $option = $(this);
                $option.attr('disabled', true);
                console.log($option.val());
            });
        }
    };

    var coluid = Uid('x');
    var rowuid = Uid('y');

    var addIfAbsent = function (A, e) {
        if (A.indexOf(e) !== -1) { return; }
        A.push(e);
    };

    var removeRow = function (proxy, uid) {
        if (readOnly) { return; }
        // remove proxy.table.rows[uid]

        proxy.table.rows[uid] = undefined;
        delete proxy.table.rows[uid];

        // remove proxy.table.rowsOrder

        var order = proxy.table.rowsOrder;
        order.splice(order.indexOf(uid), 1);

        // remove all cells including uid
        // proxy.table.cells
        Object.keys(proxy.table.cells).forEach(function (cellUid) {
            if (cellUid.indexOf(uid) === -1) { return; }
            proxy.table.cells[cellUid] = undefined;
            delete proxy.table.cells[cellUid];
        });

        // remove elements from DOM
        table.removeRow(uid);
    };

    var removeColumn = function (proxy, uid) {
        if (readOnly) { return; }
        // remove proxy.table.cols[uid]
        proxy.table.cols[uid] = undefined;
        delete proxy.table.rows[uid];

        // remove proxy.table.colsOrder
        var order = proxy.table.colsOrder;
        order.splice(order.indexOf(uid), 1);

        // remove all cells including uid
        Object.keys(proxy.table.cells).forEach(function (cellUid) {
            if (cellUid.indexOf(uid) === -1) { return; }
            proxy.table.cells[cellUid] = undefined;
            delete proxy.table.cells[cellUid];
        });

        // remove elements from DOM
        table.removeColumn(uid);
    };

    var removeFromArray = function (A, e) {
        var i = A.indexOf(e);
        if (i === -1) { return; }
        A.splice(i, 1);
    };

    var makeUserEditable = module.makeUserEditable = function (id, bool) {
        if (readOnly) { return; }
        var $name = $('input[type="text"][id="' + id + '"]').attr('disabled', !bool);

        var $edit = $name.parent().find('.edit');

        $edit[bool?'addClass':'removeClass']('editable');

        var $sel = $('input[id^="' + id + '"]')
            [bool?'addClass':'removeClass']('editable')
            .attr('disabled', !bool);

        if (bool) {
            var $target = $('tfoot td')
                .eq(module.rt.proxy.table.colsOrder.indexOf(id) + 1);

            if ($target.length) {
                var $save = $('<span>', {
                    'class': 'save action',
                    'for': id,
                })
                .text(Messages.commitButton)
                .click(function () {
                    module.activeColumn = '';
                    makeUserEditable(id, false);
                });
                $target.append($save);
            }

            module.activeColumn = id;
            module.rt.proxy.table.colsOrder.forEach(function (coluid) {
                if (coluid !== id) { makeUserEditable(coluid, false); }
            });
        } else {
            $('.save[for="' + id + '"]').remove();
        }

        return $sel;
    };

    var makeUser = function (proxy, id, value) {
        var $user = Input({
            id: id,
            type: 'text',
            placeholder: Messages.poll_userPlaceholder,
            disabled: true,
        }).on('keyup change', function () {
            proxy.table.cols[id] = $user.val() || "";
        });

        var $edit = $('<span>', {
                'class': 'edit',
                title: Messages.poll_editUserTitle,
            }).click(function () {
                if ($edit.hasClass('editable')) { return; }
                Cryptpad.confirm(Messages.poll_editUser,
                    function (yes) {
                        if (!yes) { return; }
                        makeUserEditable(id, true);
                        $edit.addClass('editable');
                        $edit.text("");
                        module.activeColumn = id;
                    });
            });

        var $remove = $('<span>', {
                'class': 'remove',
                'title': Messages.poll_removeUserTitle,
            }).text('✖').click(function () {
                Cryptpad.confirm(Messages.poll_removeUser,
                    function (yes) {
                        if (!yes) { return; }
                        // remove commit button, and anything else...
                        makeUserEditable(id, false);
                        removeColumn(proxy, id);
                        table.removeColumn(id);
                    });
            });

        if (readOnly) {
            $edit = '';
            $remove = '';
        }

        var $wrapper = $('<div>', {
            'class': 'text-cell',
        })
            .append($edit)
            .append($user)
            .append($remove);

        proxy.table.cols[id] = value || "";
        addIfAbsent(proxy.table.colsOrder, id);
        table.addColumn($wrapper, Checkbox, id);
        return $user;
    };

    var scrollDown = module.scrollDown = function (px) {
        if (module.scrolling) { return; }

        module.scrolling = true;

        var top = $(window).scrollTop() + px + 'px';
        $('html, body').animate({
            scrollTop: top,
        }, {
            duration: 200,
            easing: 'swing',
            complete: function () {
                module.scrolling = false;
            }
        });
    };

    var makeOptionEditable = function (id, bool) {
        if (readOnly) { return; }
        if (bool) {
            module.rt.proxy.table.rowsOrder.forEach(function (rowuid) {
                $('#' + rowuid)
                    .attr('disabled', rowuid !== id)
                    .closest('td')
                    .find('.edit')
                    .removeClass('editable');
            });
            return;
        }
        $('input[id^="y"]').attr('disabled', true);
    };

    var makeOption = function (proxy, id, value) {
        var $option = Input({
            type: 'text',
            placeholder: Messages.optionPlaceholder,
            id: id,
        }).on('keyup change', function () {
            proxy.table.rows[id] = $option.val();
        }).attr('disabled', true);

        var $edit = $('<span>', {
            'class': 'edit',
            title: Messages.poll_editOptionTitle,
        })
        .click(function () {
            if ($edit.hasClass('editable')) { return; }
            Cryptpad.confirm(Messages.poll_editOption,
                function (yes) {
                    if (!yes) { return; }
                    makeOptionEditable(id, true);
                    $edit.addClass('editable');
                    $edit.text("");
                    module.activeOption = id;
                });
        });

        var $remove = $('<span>', {
            'class': 'remove',
            'title': Messages.poll_removeOptionTitle,
        }).text('✖').click(function () {
            var msg = Messages.poll_removeOption;
            Cryptpad.confirm(msg, function (yes) {
                if (!yes) { return; }
                removeRow(proxy, id);
                table.removeRow(id);
            });
        });

        if (readOnly) {
            $edit = '';
            $remove = '';
        }

        var $wrapper = $('<div>', {
            'class': 'text-cell',
        })
            .append($edit)
            .append($option)
            .append($remove);

        proxy.table.rows[id] = value || "";
        addIfAbsent(proxy.table.rowsOrder, id);

        var $row = table.addRow($wrapper, Checkbox, id);

        if (module.ready) {
            scrollDown($row.height());
        }

        return $option;
    };

    $('#adduser').click(function () {
        if (!module.isEditable) { return; }
        var id = coluid();

        var msg = Messages.poll_addUser;
        Cryptpad.prompt(msg, "", function (name) {
            if (!(name && name.trim())) { return; }
            makeUser(module.rt.proxy, id, name).val(name);
            makeUserEditable(id, true).focus();
        });
    });

    $('#addoption').click(function () {
        if (!module.isEditable) { return; }
        var id = rowuid();

        var msg = Messages.poll_addOption;
        Cryptpad.prompt(msg, "", function (option) {
            if (option === null || !option) { return; }
            makeOption(module.rt.proxy, id, option).val(option).focus();
        });
        //makeOption(module.rt.proxy, id).focus();
    });

    Wizard.$getOptions.click(function () {
        Cryptpad.confirm(Messages.wizardConfirm, function (yes) {
            if (!yes) { return; }
            var options = Wizard.computeSlots(function (a, b) {
                return a + ' ('+ b + ')';
            });

            var proxy = module.rt.proxy;

            options.forEach(function (text) {
                var id = rowuid();
                makeOption(proxy, id, text).val(text);
            });
            Wizard.hide();
        });
    });

    // notifications
    var unnotify = function () {
        if (!(module.tabNotification &&
            typeof(module.tabNotification.cancel) === 'function')) { return; }
        module.tabNotification.cancel();
    };

    var notify = function () {
        if (!(Visible.isSupported() && !Visible.currently())) { return; }
        unnotify();
        module.tabNotification = Notify.tab(1000, 10);
    };

    var updateTitle = function (newTitle) {
        if (newTitle === document.title) { return; }
        // Change the title now, and set it back to the old value if there is an error
        var oldTitle = document.title;
        document.title = newTitle;
        Cryptpad.setPadTitle(newTitle, function (err, data) {
            if (err) {
                console.log("Couldn't set pad title");
                console.error(err);
                document.title = oldTitle;
                return;
            }
        });
    };

    // don't make changes until the interface is ready
    setEditable(false);

    var ready = function (info) {
        module.users = info.userList.users;

        console.log("Your realtime object is ready");
        module.ready = true;

        var proxy = module.rt.proxy;
        var First = false;

        if (proxy.metadata && proxy.metadata.title) {
            updateTitle(proxy.metadata.title);
        }

        // ensure that proxy.info and proxy.table exist
        ['info', 'table'].forEach(function (k) {
            if (typeof(proxy[k]) === 'undefined') {
                // you seem to be the first person to have visited this pad...
                First = true;
                proxy[k] = {};
            }
        });

        // table{cols,rows,cells}
        ['cols', 'rows', 'cells'].forEach(function (k) {
            if (typeof(proxy.table[k]) === 'undefined') { proxy.table[k] = {}; }
        });

        // table{rowsOrder,colsOrder}
        ['rows', 'cols'].forEach(function (k) {
            var K = k + 'Order';

            if (typeof(proxy.table[K]) === 'undefined') {
                //console.log("Creating %s", K);
                proxy.table[K] = [];

                Object.keys(proxy.table[k]).forEach(function (uid) {
                    addIfAbsent(proxy.table[K], uid);
                });
            }
        });

        // HERE TODO make this idempotent so you can call it again

        // cols
        proxy.table.colsOrder.forEach(function (uid) {
            var val = proxy.table.cols[uid];
            makeUser(proxy, uid, val).val(val);
        });

        // rows
        proxy.table.rowsOrder.forEach(function (uid) {
            var val = proxy.table.rows[uid];
            makeOption(proxy, uid, val).val(val);
        });

        // cells
        Object.keys(proxy.table.cells).forEach(function (uid) {
            //var p = parseXY(uid);
            var box = document.getElementById(uid);
            if (!box) {
                console.log("Couldn't find an element with uid [%s]", uid);
                return;
            }
            var checked = box.checked = proxy.table.cells[uid] ? true : false;
            if (checked) {
                $(box).closest('.checkbox-contain').find('.cover').addClass('yes');
            }
        });

        items.forEach(function ($item) {
            var id = $item.attr('id');

            $item.on('change keyup', function () {
                var val = $item.val();
                proxy.info[id] = val;
            });

            if (typeof(proxy.info[id]) !== 'undefined') {
                $item.val(proxy.info[id]);
            }
        });

        // listen for visibility changes
        if (Visible.isSupported()) {
            Visible.onChange(function (yes) {
                if (yes) { unnotify(); }
            });
        }

        proxy
        .on('change', [], function () {
            notify();
        })
        .on('change', ['info'], function (o, n, p) {
            var $target = $('#' + p[1]);
            var el = $target[0];
            var selects;
            var op;

            if (el && ['textarea', 'text'].indexOf(el.type) !== -1) {
                op = TextPatcher.diff(o, n);
                selects = ['selectionStart', 'selectionEnd'].map(function (attr) {
                    var before = el[attr];
                    var after = TextPatcher.transformCursor(el[attr], op);
                    return after;
                });
                $target.val(n);

                if (op) {
                    el.selectionStart = selects[0];
                    el.selectionEnd = selects[1];
                }
            }

            console.log("change: (%s, %s, [%s])", o, n, p.join(', '));
        })
        .on('change', ['table'], function (o, n, p) {
            var id = p[p.length -1];
            var type = p[1];

            if (typeof(o) === 'undefined' &&
                ['cols', 'rows', 'cells'].indexOf(type) !== -1) {
                switch (type) {
                    case 'cols':
                        makeUser(proxy, id, n);
                        break;
                    case 'rows':
                        makeOption(proxy, id, n);
                        break;
                    case 'cells':
                        //
                        break;
                    default:
                        console.log("Unhandled table element creation");
                        break;
                }
            }

            var el = document.getElementById(id);
            if (!el) { 
                console.log("Couldn't find the element you wanted!");
                return;
            }

            switch (p[1]) {
                case 'cols':
                    console.log("[Table.cols change] %s (%s => %s)@[%s]", id, o, n, p.slice(0, -1).join(', '));
                    el.value = n;
                    break;
                case 'rows':
                    console.log("[Table.rows change] %s (%s => %s)@[%s]", id, o, n, p.slice(0, -1).join(', '));
                    el.value = n;
                    break;
                case 'cells':
                    console.log("[Table.cell change] %s (%s => %s)@[%s]", id, o, n, p.slice(0, -1).join(', '));
                    var checked = el.checked = proxy.table.cells[id] ? true: false;

                    var $parent = $(el).closest('.checkbox-contain');

                    if (!$parent.length) { console.log("couldn't find parent element of checkbox"); return; }

                    if (checked) {
                        $parent.find('.cover').addClass('yes');
                    } else {
                        $parent.find('.cover').removeClass('yes');
                    }
                    break;
                default:
                    console.log("[Table change] (%s => %s)@[%s]", o, n, p.join(', '));
                    break;
            }
        })
        .on('change', ['metadata'], function (o, n, p) {
            var newTitle = proxy.metadata.title;
            updateTitle(newTitle);
        })
        .on('remove', [], function (o, p, root) {
            //console.log("remove: (%s, [%s])", o, p.join(', '));
            //console.log(p, o, p.length);

            switch (p[1]) {
                case 'cols':
                    console.log("[Table.cols removal] [%s]", p[2]);
                    table.removeColumn(p[2]);
                    return false;
                case 'rows':
                    console.log("[Table.rows removal] [%s]", p[2]);
                    table.removeRow(p[2]);
                    return false;
                case 'rowsOrder':
                    Object.keys(proxy.table.rows)
                        .forEach(function (rowId) {
                            if (proxy.table.rowsOrder.indexOf(rowId) === -1) {
                                proxy.table.rows[rowId] = undefined;
                                delete proxy.table.rows[rowId];
                            }
                        });
                    break;
                case 'colsOrder':
                    Object.keys(proxy.table.cols)
                        .forEach(function (colId) {
                            if (proxy.table.colsOrder.indexOf(colId) === -1) {
                                proxy.table.cols[colId] = undefined;
                                delete proxy.table.cols[colId];
                            }

                        });
                    break;
                case 'cells':
                    // cool story bro
                    break;
                default:
                    console.log("[Table removal] [%s]", p.join(', '));
                    break;
            }

        })
        .on('disconnect', function (info) {
            setEditable(false);
        });


        var $toolbar = $('#toolbar');

        var Button = function (opt) {
            return $('<button>', opt);
        };

        var suggestName = module.suggestName = function () {
            var parsed = Cryptpad.parsePadUrl(window.location.href);
            var name = Cryptpad.getDefaultName(parsed, []);

            if (document.title.slice(0, name.length) === name) {
                return $title.val() || document.title;
            } else {
                return document.title || $title.val() || name;
            }
        };

        /* add a forget button */
        var forgetCb = function (err, title) {
            if (err) { return; }
            document.title = title;
        };
        var $forgetPad = Cryptpad.createButton('forget', false, {}, forgetCb)
            .text(Messages.forgetButton)
            .removeAttr('style')
            .attr('class', 'action button forget');
        $toolbar.append($forgetPad);

        /* add a rename button */
        var renameCb = function (err, title) {
            if (err) { return; }
            document.title = title;
            var proxy = module.rt.proxy;
            if (proxy.metadata) {
                proxy.metadata.title = title;
            }
            else {
                proxy.metadata = {title: title};
            }
        };
        var $setTitle = Cryptpad.createButton('rename', true, {suggestName: suggestName}, renameCb)
            .text(Messages.renameButton)
            .removeAttr('style')
            .attr('class', 'action button rename');
        $toolbar.append($setTitle);

        if (!readOnly) {
            $toolbar.append(Button({
                id: 'wizard',
                'class': 'wizard button action',
                title: Messages.wizardTitle,
            }).text(Messages.wizardButton).click(function () {
                Wizard.show();
                if (Wizard.hasBeenDisplayed) { return; }
                Cryptpad.log(Messages.wizardLog);
                Wizard.hasBeenDisplayed = true;
            }));
        }

/*
        if (!readOnly && module.viewHash) {
            /* add a 'links' button
            var $links = Cryptpad.createButton('readonly', true, {viewHash: module.viewHash})
                .text(Messages.getViewButton)
                .removeAttr('style')
                .attr('class', 'action button readonly');
            $toolbar.append($links);
        }
*/

        /* Import/Export buttons */
        /*
        $toolbar.append(Button({
            id: 'import',
            'class': 'import button action',
            title: 'IMPORT', // TODO translate
        }).text('IMPORT') // TODO translate
        .click(function () {
            var proxy = module.rt.proxy;

            console.log("pew pew");
            if (!module.ready) { return; }

            console.log("bang bang");
            Cryptpad.importContent('text/plain', function (content, file) {
                var parsed;
                try {
                    parsed = JSON.parse(content);
                } catch (err) {
                    Cryptpad.alert("Could not parse imported content");
                    return;
                }
                console.log(content);
                //module.rt.update(parsed);
            })();
        }));

        $toolbar.append(Button({
            id: 'export',
            'class': 'export button action',
            title: 'EXPORT', // TODO translate
        }).text("EXPORT") // TODO translate
        .click(function () {
            if (!module.ready) { return; }
            var proxy = module.rt.proxy;

            var title = suggestName();

            var text = JSON.stringify(proxy, null, 2);

            Cryptpad.prompt(Messages.exportPrompt, title + '.json', function (filename) {
                if (filename === null) { return; }
                var blob = new Blob([text], {
                    type: 'application/json',
                });
                saveAs(blob, filename);
            });
        }));*/


        setEditable(true);
        return;

        // shortcircuiting before all of this code since it's not quite the
        // behaviour we want, and it's a bit of work to make it Do The Right Thing
/*
        if (First) {
            // assume the first user to the poll wants to be the administrator...
            // TODO prompt them with questions to set up their poll...
        }

        Cryptpad.getPadAttribute('column', function (err, column) {
            if (readOnly) { return; }
            if (err) {
                console.log("unable to retrieve column");
                return;
            }

            module.activeColumn = '';
            var promptForName = function () {

                var followUp = function (name) {
                    if (!name) { return; }
                    var id = module.activeColumn = coluid();

                    Cryptpad.setPadAttribute('column', id, function (err) {
                        if (err) { return void console.error("Couldn't remember your column id"); }
                        makeUser(module.rt.proxy, id, name).focus().val(name);
                        makeUserEditable(id, true);
                    });
                };

                getLastName(function (err, uname) {
                    if (!uname) {
                        return void Cryptpad.prompt(Messages.promptName, "", function (name, ev) {
                            if (!(name || module.isEditable)) { return; }
                            followUp(name);
                        });
                    }
                    followUp(uname);
                });
            };

            if (column === null) { return void promptForName(); }

            // column might be defined, but that column might have been deleted...
            if (proxy.table.colsOrder.indexOf(column) === -1) { return void promptForName(); }
        });*/
    };

    var config = {
        websocketURL: Cryptpad.getWebsocketURL(),
        channel: secret.channel,
        data: {},
        // our public key
        validateKey: secret.keys.validateKey || undefined,
        readOnly: readOnly,
        crypto: Crypto.createEncryptor(secret.keys),
    };

    // don't initialize until the store is ready.
    Cryptpad.ready(function () {

        var rt = window.rt = module.rt = Listmap.create(config);
        rt.proxy.on('create', function (info) {
            var realtime = module.realtime = info.realtime;

            var editHash;
            var viewHash = module.viewHash = Cryptpad.getViewHashFromKeys(info.channel, secret.keys);
            if (!readOnly) {
                editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
            }
            // set the hash
            if (!readOnly) { Cryptpad.replaceHash(editHash); }

            module.patchText = TextPatcher.create({
                realtime: realtime,
                logging: true,
            });
            Cryptpad.getPadTitle(function (err, title) {
                title = document.title = title || info.channel.slice(0, 8);

                Cryptpad.setPadTitle(title, function (err, data) {
                    if (err) {
                        console.log("unable to remember pad");
                        console.log(err);
                        return;
                    }
                });
            });
        }).on('ready', ready)
        .on('disconnect', function () {
            setEditable(false);
            Cryptpad.alert(Messages.common_connectionLost);
        });
    });

});