'use strict';

const AccountsService = imports.gi.AccountsService;
const ExtensionUtils = imports.misc.extensionUtils;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Soup = imports.gi.Soup;

const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Me.imports.lib.convenience;
const { md5 } = Me.imports.lib.md5;
const { log, debug } = Me.imports.utils.log;
const { isValidEmail } = Me.imports.utils.isValidEmail;
const { setInterval, clearInterval } = Me.imports.utils.timing;


const Extension = new Lang.Class({
  Name: 'Gravatar.Extension',

  /*
   ***********************************************
   * Constructor                                 *
   ***********************************************
   */
  _init: function () {
    debug('initializing');
    this._settings = Convenience.getSettings();
    this._tmpDir = '/tmp';
    this._username = GLib.get_user_name();
    this._user = AccountsService.UserManager.get_default().get_user(this._username);
  },

  /*
   ***********************************************
   * Public Methods                              *
   ***********************************************
   */
  enable: function () {
    debug('enabling');
    this._waitForUser(function () {
      this._changedId = this._settings.connect('changed', this._loadIcon.bind(this));
      this._loadIcon();
    }.bind(this));
  },

  disable: function () {
    debug('disabling');
    if (this._changedId) {
      this._settings.disconnect(this._changedId);
      this._changedId = null;
    }

    if (this._userLoop) {
      clearInterval(this._userLoop);
      this._userLoop = null;
    }

    if (this._httpSession) {
      this._httpSession.abort();
      this._httpSession = null;
    }
  },

  /*
   ***********************************************
   * Private Methods                             *
   ***********************************************
   */
  _waitForUser: function (cb) {
    // This fixes an issue where sometimes this._user is not
    // initialized when the extension loads
    if (this._user.get_icon_file() !== null) {
      cb();
      return;
    }
    debug('Waiting for user to initialize...');
    this._userLoop = setInterval(function () {
      debug('User initialized');
      clearInterval(this._userLoop);
      this._userLoop = null;
      cb();
    }.bind(this), 1000);
  },

  /* Settings */
  _getIconSize: function () {
    return this._settings.get_int('icon-size');
  },

  _getHash: function () {
    let email = this._settings.get_string('email').toLowerCase();
    if (!isValidEmail(email)) {
      log('Unable to validate email "' + email + '"');
      return null;
    }
    debug('Hashing "' + email + '"');
    return md5(email);
  },

  /* Set Icon */
  _setIcon: function (icon) {
    log('Setting icon for "' + this._username + '" to "' + icon + '"');
    this._user.set_icon_file(icon);
  },

  /* Download From Gravatar */
  _loadIcon: function () {
    let hash = this._getHash();
    if (hash === null) {
      return;
    }
    try {
      let url = 'http://www.gravatar.com/avatar/' + hash + '?s=' + this._getIconSize() + '&d=mm';
      let request = Soup.Message.new('GET', url);
      let icon = Gio.file_new_for_path(this._tmpDir + '/' + Date.now() + '_' + hash);
      log('Downloading gravatar icon from ' + url);
      debug('Saving to ' + icon.get_path());

      // initialize session
      if (!this._httpSession) {
        debug('Creating new http session');
        this._httpSession = new Soup.Session();
      }
      this._httpSession.abort();

      let fstream = icon.replace(null, false, Gio.FileCreateFlags.NONE, null);
      request.connect('got_chunk', function (msg, chunk) {
        fstream.write(chunk.get_data(), null, chunk.length);
      });

      // download file
      this._httpSession.queue_message(request, function (httpSession, msg) {
        fstream.close(null);
        switch (msg.status_code) {
        case 200:
          log('Download successful');
          this._setIcon(icon.get_path());
          break;
        default:
          log('Failed to download ' + url);
        }
        debug('Deleting ' + icon.get_path());
        icon.delete(null);
      }.bind(this));
    } catch (e) {
      log(e.message);
    }
  },

});


/* exported init */
function init() {
  return new Extension();
}

@@ -2091,32 +2091,16 @@
 ser.
-get_icon_file() !== null
+isLoaded
 ) %7B%0A
@@ -2175,24 +2175,47 @@
 alize...');%0A
+    let loopCount = 0;%0A
     this._us
@@ -2245,24 +2245,78 @@
 nction () %7B%0A
+      loopCount++;%0A      if (this._user.isLoaded) %7B%0A  
       debug(
@@ -2332,24 +2332,26 @@
 tialized');%0A
+  
       clearI
@@ -2373,32 +2373,34 @@
 serLoop);%0A      
+ 
+ 
 this._userLoop =
@@ -2408,29 +2408,208 @@
 null;%0A      
+  
-cb();
+return cb();%0A      %7D%0A      if (loopCount %3E= 30) %7B%0A        clearInterval(this._userLoop);%0A        this._userLoop = null;%0A        log('Timeout waiting for user to initialize');%0A      %7D
 %0A    %7D.bind(

Optimize user initialization loop