text: /**
   * @namespace jsxc.fileTransfer
   * @type {Object}
   */
  jsxc.fileTransfer = {};
  
  /**
   * Make bytes more human readable.
   *
   * @memberOf jsxc.fileTransfer
   * @param  {Integer} byte
   * @return {String}
   */
  jsxc.fileTransfer.formatByte = function(byte) {
     var s = ['', 'KB', 'MB', 'GB', 'TB'];
     var i;
  
     for (i = 1; i < s.length; i++) {
        if (byte < 1024) {
           break;
        }
        byte /= 1024;
     }
  
     return (Math.round(byte * 10) / 10) + s[i - 1];
  };
  
  /**
   * Start file transfer dialog.
   *
   * @memberOf jsxc.fileTransfer
   * @param  {String} jid
   */
  jsxc.fileTransfer.startGuiAction = function(jid) {
     var bid = jsxc.jidToBid(jid);
     var res = Strophe.getResourceFromJid(jid);
  
     if (!res && !jsxc.xmpp.httpUpload.ready) {
        if (jsxc.fileTransfer.isWebrtcCapable(bid)) {
           jsxc.fileTransfer.selectResource(bid, jsxc.fileTransfer.startGuiAction);
        } else {
           jsxc.gui.window.postMessage({
              bid: bid,
              direction: jsxc.Message.SYS,
              msg: $.t('No_proper_file_transfer_method_available')
           });
        }
  
        return;
     }
  
     jsxc.fileTransfer.showFileSelection(jid);
  };
  
  /**
   * Show select dialog for file transfer capable resources.
   *
   * @memberOf jsxc.fileTransfer
   * @param  {String} bid
   * @param  {Function} success_cb Called if user selects resource
   * @param  {Function} error_cb Called if no resource was found or selected
   */
  jsxc.fileTransfer.selectResource = function(bid, success_cb, error_cb) {
     var win = jsxc.gui.window.get(bid);
     var jid = win.data('jid');
     var res = Strophe.getResourceFromJid(jid);
  
     var fileCapableRes = jsxc.webrtc.getCapableRes(jid, jsxc.webrtc.reqFileFeatures);
     var resources = Object.keys(jsxc.storage.getUserItem('res', bid)) || [];
  
     if (res === null && resources.length === 1 && fileCapableRes.length === 1) {
        // only one resource is available and this resource is also capable to receive files
        res = fileCapableRes[0];
        jid = bid + '/' + res;
  
        success_cb(jid);
     } else if (fileCapableRes.indexOf(res) >= 0) {
        // currently used resource is capable to receive files
        success_cb(bid + '/' + res);
     } else if (fileCapableRes.indexOf(res) < 0) {
        // show selection dialog
        jsxc.gui.window.selectResource(bid, $.t('Your_contact_uses_multiple_clients_'), function(data) {
           if (data.status === 'unavailable') {
              jsxc.gui.window.hideOverlay(bid);
  
              if (typeof error_cb === 'function') {
                 error_cb();
              }
           } else if (data.status === 'selected') {
              success_cb(bid + '/' + data.result);
           }
        }, fileCapableRes);
     }
  };
  
  /**
   * Show file selector.
   *
   * @memberOf jsxc.fileTransfer
   * @param  {String} jid
   */
  jsxc.fileTransfer.showFileSelection = function(jid) {
     var bid = jsxc.jidToBid(jid);
     var msg = $('<div><div><label><input type="file" name="files" /><label></div></div>');
     msg.addClass('jsxc_chatmessage');
  
     jsxc.gui.window.showOverlay(bid, msg, true);
  
     // open file selection for user
     msg.find('label').click();
  
     msg.find('[type="file"]').change(function(ev) {
        var file = ev.target.files[0]; // FileList object
  
        if (!file) {
           return;
        }
  
        jsxc.fileTransfer.fileSelected(jid, msg, file);
     });
  };
  
  jsxc.fileTransfer.showFileTooLarge = function(bid, file) {
     var maxSize = jsxc.fileTransfer.formatByte(jsxc.options.get('httpUpload').maxSize);
     var fileSize = jsxc.fileTransfer.formatByte(file.size);
  
     jsxc.gui.window.postMessage({
        bid: bid,
        direction: jsxc.Message.SYS,
        msg: $.t('File_too_large') + ' (' + fileSize + ' > ' + maxSize + ')'
     });
  
     jsxc.gui.window.hideOverlay(bid);
  };
  
  /**
   * Callback for file selector.
   *
   * @memberOf jsxc.fileTransfer
   * @param  {String} jid
   * @param  {jQuery} msg jQuery object of temporary file message
   * @param  {File} file selected file
   */
  jsxc.fileTransfer.fileSelected = function(jid, msg, file) {
     var bid = jsxc.jidToBid(jid);
     var httpUploadOptions = jsxc.options.get('httpUpload') || {};
     var maxSize = httpUploadOptions.maxSize || -1;
  
     if (file.transportMethod !== 'webrtc' && jsxc.xmpp.httpUpload.ready && maxSize >= 0 && file.size > maxSize) {
        jsxc.debug('File too large for http upload.');
  
        if (jsxc.fileTransfer.isWebrtcCapable(bid)) {
           // try data channels
           file.transportMethod = 'webrtc';
  
           jsxc.fileTransfer.selectResource(bid, function(jid) {
              jsxc.fileTransfer.fileSelected(jid, msg, file);
           }, function() {
              jsxc.fileTransfer.showFileTooLarge(bid, file);
           });
        } else {
           jsxc.fileTransfer.showFileTooLarge(bid, file);
        }
  
        return;
     } else if (!jsxc.xmpp.httpUpload.ready && Strophe.getResourceFromJid(jid)) {
        // http upload not available
        file.transportMethod = 'webrtc';
     }
  
     var attachment = $('<div>');
     attachment.addClass('jsxc_attachment');
     attachment.addClass('jsxc_' + file.type.replace(/\//, '-'));
     attachment.addClass('jsxc_' + file.type.replace(/^([^/]+)\/.*/, '$1'));
  
     msg.empty().append(attachment);
  
     if (FileReader && file.type.match(/^image\//)) {
        // show image preview
        var img = $('<img alt="preview">').attr('title', file.name);
        img.attr('src', jsxc.options.get('root') + '/img/loading.gif');
        img.appendTo(attachment);
  
        var reader = new FileReader();
  
        reader.onload = function() {
           img.attr('src', reader.result);
        };
  
        reader.readAsDataURL(file);
     } else {
        attachment.text(file.name + ' (' + file.size + ' byte)');
     }
  
     $('<button>').addClass('jsxc_btn jsxc_btn-primary').text($.t('Send')).click(function() {
        // user confirmed file transfer
        jsxc.gui.window.hideOverlay(bid);
        msg.remove();
  
        var message = jsxc.gui.window.postMessage({
           bid: bid,
           direction: 'out',
           attachment: {
              name: file.name,
              size: file.size,
              type: file.type,
              data: (file.type.match(/^image\//)) ? img.attr('src') : null
           }
        });
  
        if (file.transportMethod === 'webrtc') {
           var sess = jsxc.webrtc.sendFile(jid, file);
  
           sess.sender.on('progress', function(sent, size) {
              jsxc.gui.window.updateProgress(message, sent, size);
  
              if (sent === size) {
                 message.received();
              }
           });
        } else {
           // progress is updated in xmpp.httpUpload.uploadFile
           jsxc.xmpp.httpUpload.sendFile(file, message);
        }
     }).appendTo(msg);
  
     $('<button>').addClass('jsxc_btn jsxc_btn-default').text($.t('Abort')).click(function() {
        // user aborted file transfer
        jsxc.gui.window.hideOverlay(bid);
     }).appendTo(msg);
  };
  
  /**
   * Enable/disable icons for file transfer.
   *
   * @memberOf jsxc.fileTransfer
   * @param  {String} bid
   */
  jsxc.fileTransfer.updateIcons = function(bid) {
     var win = jsxc.gui.window.get(bid);
  
     if (!win || win.length === 0 || !jsxc.xmpp.conn) {
        return;
     }
  
     jsxc.debug('Update file transfer icons for ' + bid);
  
     if (jsxc.xmpp.httpUpload.ready) {
        win.find('.jsxc_sendFile').removeClass('jsxc_disabled');
  
        return;
     } else if (!jsxc.fileTransfer.isWebrtcCapable(bid)) {
        win.find('.jsxc_sendFile').addClass('jsxc_disabled');
  
        return;
     }
  
     var jid = win.data('jid');
     var res = Strophe.getResourceFromJid(jid);
     var fileCapableRes = jsxc.webrtc.getCapableRes(bid, jsxc.webrtc.reqFileFeatures);
     var resources = Object.keys(jsxc.storage.getUserItem('res', bid) || {}) || [];
  
     if (fileCapableRes.indexOf(res) > -1 || (res === null && fileCapableRes.length === 1 && resources.length === 1)) {
        win.find('.jsxc_sendFile').removeClass('jsxc_disabled');
     } else {
        win.find('.jsxc_sendFile').addClass('jsxc_disabled');
     }
  };
  
  jsxc.fileTransfer.isWebrtcCapable = function(bid) {
     return !jsxc.muc.isGroupchat(bid);
  };
  
  $(document).on('update.gui.jsxc', function(ev, bid) {
     jsxc.fileTransfer.updateIcons(bid);
  });
  