!function( $ ){

  "use strict";

  var Translatable = function( element, options ) {
    this.$element = $(element);
    this.options = $.extend({}, $.fn.translatable.defaults, options);
    if (!this.$element.data('translateTag'))
        return;

    var self = this;
    this.fetch('ajax.php/i18n/langs').then(function(json) {
      self.langs = json;
      if (Object.keys(self.langs).length) self.decorate();
    });
  },
  // Class-static variables
  urlcache = {};

  Translatable.prototype = {

    constructor: Translatable,

    fetch: function( url, data, callback ) {
      if ( !urlcache[ url ] ) {
        urlcache[ url ] = $.Deferred(function( defer ) {
          $.ajax( url, { data: data, dataType: 'json' } )
            .then( defer.resolve, defer.reject );
        }).promise();
      }
      return urlcache[ url ].done( callback );
    },

    decorate: function() {
      this.$translations = $('<ul class="translations"></ul>');
      this.$status = $('<li class="status"><i class="icon-spinner icon-spin"></i> Loading ...</li>')
        .appendTo(this.$translations);
      this.$footer = $('<div class="add-translation"></div>');
      this.$select = $('<select name="locale"></select>');
      this.$menu = $(this.options.menu).appendTo('body');
      this.$container = $('<div class="translatable"></div>')
          .prependTo(this.$element.parent())
          .append(this.$element);
      this.$button = $(this.options.button).insertAfter(this.$container);
      //this.$menu.append('<a class="close pull-right" href=""><i class="icon-remove-circle"></i></a>')
      //    .on('click', $.proxy(this.hide, this));
      this.$menu.append(this.$translations).append(this.$footer);
      this.shown = false;
      this.populated = false;

      this.$button.on('click', $.proxy(this.toggle, this));

      this.$element
        .addClass('translatable')
        .focus($.proxy(function() { this.addClass('focus'); }, this.$container))
        .blur($.proxy(function() { this.removeClass('focus'); }, this.$container));
      getConfig().then($.proxy(function(c) {
        $('<span class="flag"></span>')
          .addClass('flag-' + c.primary_lang_flag)
          .insertAfter(this);
        }, this.$element));
    },

    buildAdd: function() {
      var self=this;
      this.$footer
        .append($('<form method="post"></form>')
          .append(this.$select)
          .append($('<button type="button"><i class="icon-plus-sign"></i> Add</button>')
            .on('click', $.proxy(this.define, this))
          )
        );
      this.fetch('ajax.php/i18n/langs').then(function(langs) {
        $.each(langs, function(k, v) {
          self.$select.append($('<option>').val(k).text(v));
        });
      });
    },

    populate: function() {
      var self=this;
      if (this.populated)
        return;
      this.buildAdd();
      this.fetch('ajax.php/i18n/translate/' + this.$element.data('translateTag'))
      .then(function(json) {
        $.each(json, function(k,v) {
          self.add(k, v);
        });
        if (!Object.keys(json).length) {
          self.$status.text('Not currently translated');
        }
        else
          self.$status.remove();
      });
      self.populated = true;
    },

    define: function(e) {
      this.add($('option:selected', this.$select).val());
    },

    add: function(lang, text) {
      this.$translations.append(
        $('<li>')
        .append($('<label class="language">').text(this.langs[lang])
          .append($('<input type="text" data-lang="'+lang+'">')
            .on('change', $.proxy(this.showCommit, this))
            .val(text)
          )
        )
      );
      $('option[value='+lang+']', this.$select).remove();
      if (!$('option', this.$select).length)
        this.$footer.hide();
      this.$status.remove();
    },

    showCommit: function(e) {
      if (this.$commit)
          return this.$commit.show();

      return this.$commit = $('<div class="language-commit"></div>')
        .insertAfter(this.$translations)
        .append($('<button type="button" class="commit"><i class="fa fa-save icon-save"></i> Save</button>')
          .on('click', $.proxy(this.commit, this))
        );
    },

    commit: function(e) {
      var changes = {}, self = this;
      $('input[type=text]', this.$translations).each(function() {
        changes[$(this).data('lang')] = $(this).val();
      });
      $.ajax('ajax.php/i18n/translate/' + this.$element.data('translateTag'), {
        type: 'post',
        data: changes,
        success: function() {
          self.$commit.hide();
        }
      });
    },

    toggle: function(e) {
      e.stopPropagation();
      e.preventDefault();

      if (this.shown)
        this.hide();
      else
        this.show();
    },

    show: function() {
      if (this.shown)
          return this;

      var pos = $.extend({}, this.$container.offset(), {
        height: this.$container[0].offsetHeight
      })

      this.$menu.css({
        top: pos.top + pos.height
      , left: pos.left
      });

      this.populate();

      this.$menu.show();
      this.shown = true;
      return this;
    },

    hide: function() {
      if (this.shown) {
        this.$menu.hide();
        this.shown = false;
      }
      return this;
    }


  };

  /* PLUGIN DEFINITION
   * =========================== */

  $.fn.translatable = function ( option ) {
    return this.each(function () {
      var $this = $(this),
        data = $this.data('translatable'),
        options = typeof option == 'object' && option;
      if (!data) $this.data('translatable', (data = new Translatable(this, options)));
      if (typeof option == 'string') data[option]();
    });
  };

  $.fn.translatable.defaults = {
    menu: '<div class="translations dropdown-menu"></div>',
    button: '<button class="translatable"><i class="fa fa-globe icon-globe"></i></button>'
  };

  $.fn.translatable.Constructor = Translatable;

}( window.jQuery );