/*global imce:true*/
(function ($, Drupal, imce) {
  'use strict';

  /**
   * @file
   * Defines imce Upload Queue and Upload Queue Item.
   */

  /**
   * Upload queue constructor.
   */
  imce.UploadQueue = function (conf) {
    this.construct(conf);
  };

  /**
   * Upload queue prototype.
   */
  var Uq = imce.UploadQueue.prototype;

  /**
   * Constructs upload queue.
   */
  Uq.construct = function (conf) {
    var Uq = this;
    Uq.items = {};
    Uq.queue = [];
    Uq.conf = $.extend({name: 'files[imce][]'}, conf);
    Uq.createEl();
  };

  /**
   * Creates upload queue element.
   */
  Uq.createEl = function () {
    var Uq = this;
    var el = Uq.el;
    var inputEl;
    var accept;
    if (!el) {
      el = Uq.el = imce.createEl('<div class="imce-uq"><span class="imce-uq-button imce-ficon imce-ficon-plus"><span class="imce-uq-label">' + Drupal.t('Add file') + '</span><input type="file" class="imce-uq-input" multiple /></span><div class="imce-uq-items"></div></div>');
      inputEl = Uq.inputEl = el.firstChild.lastChild;
      inputEl.onchange = imce.eUqInputChange;
      if (accept = Uq.conf.accept) {
        inputEl.accept = accept;
      }
      Uq.itemsEl = el.lastChild;
      el.Uq = inputEl.Uq = Uq;
    }
    return el;
  };

  /**
   * Starts the queue.
   */
  Uq.start = function () {
    var Uq = this;
    if (!Uq.running && Uq.queue.length) {
      if (Uq.next()) {
        Uq.running = true;
        imce.uploadSetBusy(true);
      }
    }
    return Uq.running;
  };

  /**
   * Ends the queue.
   */
  Uq.end = function () {
    if (this.running) {
      this.running = false;
      imce.uploadSetBusy(false);
      imce.getTbb('upload').closePopup();
    }
  };

  /**
   * Process the first available item in the queue.
   */
  Uq.next = function () {
    var i;
    var Item;
    var queue = this.queue.slice(0);
    for (i = 0; Item = queue[i]; i++) {
      // Remove completed items from the queue.
      if (Item.completed) {
        Item.remove();
      }
      else if (Item.start()) {
        return Item;
      }
    }
    // No items left. End the queue if running.
    this.end();
  };

  /**
   * Select files from a file reference list.
   */
  Uq.selectFiles = function (list) {
    var i;
    var file;
    var Item;
    var ret;
    var path = imce.activeFolder.getPath();
    for (i = 0; file = list[i]; i++) {
      if (imce.validateFileUpload(file)) {
        Item = new imce.UploadQueueItem(file, path);
        if (this.addItem(Item)) {
          if (!ret) {
            ret = {};
          }
          ret[i] = Item.id;
        }
        else {
          Item.remove();
        }
      }
    }
    return ret;
  };

  /**
   * Returns a queue item.
   */
  Uq.getItem = function (id) {
    return this.items[id];
  };

  /**
   * Adds a queue item.
   */
  Uq.addItem = function (Item) {
    var existing;
    var Uq = this;
    var id = Item.id;
    // Check existing
    if (existing = Uq.getItem(id)) {
      existing.remove(true);
    }
    Item.Uq = Uq;
    Uq.items[id] = Uq.queue[Uq.queue.length] = Item;
    Uq.itemsEl.appendChild(Item.el);
    return Item;
  };

  /**
   * Removes a queue item.
   */
  Uq.removeItem = function (Item, quick) {
    var Uq = this;
    var queue = Uq.queue;
    var i = $.inArray(Item, queue);
    if (i !== -1) {
      queue.splice(i, 1);
      delete Uq.items[Item.id];
      if (quick) {
        $(Item.el).remove();
      }
      else {
        $(Item.el).fadeOut(1000, imce.eUqItemFadeout);
      }
      return Item;
    }
  };

  /**
   * Prepare ajax options for an item.
   */
  Uq.ajaxPrepare = function (Item) {
    var i;
    var field;
    var data;
    var formData;
    var Folder;
    var Uq = this;
    var file = Item.file;
    var dest = Item.destination;
    // Check file and destination
    if (!file || !dest || !(Folder = imce.getFolder(dest))) {
      return;
    }
    // Prepare form data
    data = $(Uq.inputEl.form).serializeArray().concat([{name: 'active_path', value: dest}], Item.formData || []);
    formData = new FormData();
    for (i = 0; field = data[i]; i++) {
      if (field.name) {
        formData.append(field.name, field.value);
      }
    }
    formData.append(Uq.conf.name, Item.file);
    // Extend default ajax options
    return $.extend(imce.ajaxDefaults(), {
      data: formData,
      processData: false,
      contentType: false,
      customBeforeSend: imce.xUqItemBeforeSend,
      customComplete: imce.xUqItemComplete,
      xhr: imce.xUqItemXhr,
      itemId: Item.id,
      activeFolder: Folder
    });
  };


  /**
   * Upload queue item constructor.
   */
  imce.UploadQueueItem = function (file, destination) {
    this.construct(file, destination);
  };

  /**
   * Upload queue item prototype.
   */
  var UqItem = imce.UploadQueueItem.prototype;

  /**
   * Constructs upload queue item.
   */
  UqItem.construct = function (file, destination) {
    this.file = file;
    this.destination = destination;
    this.id = imce.joinPaths(destination, file.name);
    this.createEl();
  };

  /**
   * Creates upload queue element.
   */
  UqItem.createEl = function () {
    var cancelEl;
    var name;
    var Item = this;
    var el = Item.el;
    var file = Item.file;
    if (!el) {
      name = Drupal.checkPlain(file.name);
      el = Item.el = imce.createEl('<div class="imce-uqi"><div class="imce-uqi-cancel"></div><div class="imce-uqi-info"><span class="imce-uqi-name" title="' + name + '">' + name + '</span><span class="imce-uqi-size">' + imce.formatSize(file.size) + '</span></div><div class="imce-uqi-progress"><div class="imce-uqi-bar"></div></div><div class="imce-uqi-percent">' + Drupal.t('!percent%', {'!percent': 0}) + '</div></div>');
      el.Item = Item;
      // Set cancel element events
      cancelEl = el.firstChild;
      cancelEl.onclick = imce.eUqItemCancelClick;
      cancelEl.onmousedown = imce.eUqItemCancelMousedown;
    }
    return el;
  };

  /**
   * Removes the item from queue.
   */
  UqItem.remove = function (quick) {
    var ret;
    var Item = this;
    var Uq = Item.Uq;
    Item.stop();
    if (Uq) {
      Uq.removeItem(Item, quick);
    }
    Item.Uq = Item.xhr = Item.file = Item.formData = Item.el.Item = null;
    return ret;
  };

  /**
   * Start processing the item.
   */
  UqItem.start = function () {
    var opt;
    var Item = this;
    var Uq = Item.Uq;
    if (Uq && !Item.active && !Item.completed) {
      // Get ajax options
      if (opt = Uq.ajaxPrepare(Item)) {
        Item.active = true;
        $(Item.el).addClass('active');
        Item.xhr = $.ajax(opt);
        Uq.activeItem = Item;
        return Uq.activeItem;
      }
    }
  };

  /**
   * Stops processing the item.
   */
  UqItem.stop = function () {
    var Item = this;
    if (Item.active) {
      Item.active = false;
      $(Item.el).removeClass('active');
      if (Item.xhr) {
        Item.xhr.abort();
      }
      // Make sure the item is completed
      Item.complete();
    }
  };

  /**
   * Sets the item as completed.
   */
  UqItem.complete = function (status) {
    var Item = this;
    var Uq = Item.Uq;
    if (!Item.completed) {
      Item.completed = true;
      Item.status = status;
      $(Item.el).addClass(status ? 'success' : 'fail');
      if (status) {
        $('.imce-uqi-percent', Item.el).html(Drupal.t('!percent%', {'!percent': 100}));
      }
      // Check if this is the active item of the queue
      if (Uq && Uq.activeItem === Item) {
        Uq.activeItem = null;
        // Continue queue
        if (Uq.running) {
          Uq.next();
        }
      }
      // Make sure the item is stopped
      Item.stop();
    }
  };

  /**
   * Sets item progress.
   */
  UqItem.progress = function (percent) {
    $(this.el).find('.imce-uqi-percent').text(Drupal.t('!percent%', {'!percent': percent * 1})).end().find('.imce-uqi-bar').css('width', percent * 1 + '%');
  };


  /**
   * Change event of upload queue input
   */
  imce.eUqInputChange = function () {
    this.Uq.selectFiles(this.files);
    imce.uploadResetInput(this);
    if (imce.getConf('upload_auto_start', 1)) {
      $('.imce-upload-button', this.form).trigger('click');
    }
  };

  /**
   * Click event for cancel button of queue item.
   */
  imce.eUqItemCancelClick = function (event) {
    var Item = $(this).closest('.imce-uqi')[0].Item;
    if (Item) {
      Item.remove(true);
    }
    return false;
  };

  /**
   * Mousedown event for cancel button of queue item.
   */
  imce.eUqItemCancelMousedown = function (event) {
    return false;
  };

  /**
   * Fadeout callback for queue item.
   */
  imce.eUqItemFadeout = function () {
    $(this).remove();
  };

  /**
   * Ajax beforeSend handler of upload queue.
   */
  imce.xUqItemBeforeSend = function (xhr) {
    // Replaced by imce.xUqItemXhr
  };

  /**
   * Ajax xhr handler of upload queue.
   */
  imce.xUqItemXhr = function () {
    var id = this.itemId;
    var xhr = new XMLHttpRequest();
    xhr.upload.onprogress = function (e) {
      var Item = imce.activeUq.getItem(id);
      if (Item) {
        Item.progress(parseInt(e.loaded * 100 / e.total));
      }
    };
    return xhr;
  };

  /**
   * Ajax complete handler of upload queue.
   */
  imce.xUqItemComplete = function (xhr, status) {
    var opt = this;
    var Item = imce.activeUq.getItem(opt.itemId);
    status = !!(opt.response && opt.response.added);
    if (Item) {
      Item.complete(status);
    }
  };

})(jQuery, Drupal, imce);
