/*
/*
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */

/**
 * RequireJS module for the workspace backend module
 */
define([
  'jquery',
  'TYPO3/CMS/Workspaces/Workspaces',
  'TYPO3/CMS/Backend/Tooltip',
  'TYPO3/CMS/Backend/Severity',
  'TYPO3/CMS/Backend/Modal',
  'TYPO3/CMS/Backend/Wizard',
  'nprogress',
  'TYPO3/CMS/Backend/jquery.clearable'
], function($, Workspaces, Tooltip, Severity, Modal, Wizard, NProgress) {
  'use strict';

  var Backend = {
    workspaceTitle: '',
    identifiers: {
      searchForm: '#workspace-settings-form',
      searchTextField: '#workspace-settings-form input[name="search-text"]',
      searchSubmitBtn: '#workspace-settings-form button[type="submit"]',
      depthSelector: '#workspace-settings-form [name="depth"]',
      languageSelector: '#workspace-settings-form select[name="languages"]',
      actionForm: '#workspace-actions-form',
      chooseStageAction: '#workspace-actions-form [name="stage-action"]',
      chooseSelectionAction: '#workspace-actions-form [name="selection-action"]',
      chooseMassAction: '#workspace-actions-form [name="mass-action"]',
      container: '#workspace-panel',
      actionIcons: '#workspace-action-icons',
      toggleAll: '.t3js-toggle-all',
      previewLinksButton: '.t3js-preview-link',
      pagination: '#workspace-pagination'
    },
    settings: {
      depth: TYPO3.settings.Workspaces.depth,
      dir: 'ASC',
      id: TYPO3.settings.Workspaces.id,
      language: TYPO3.settings.Workspaces.language,
      limit: 30,
      query: '',
      sort: 'label_Live',
      start: 0,
      filterTxt: ''
    },
    paging: {
      currentPage: 1,
      totalPages: 1,
      totalItems: 0
    },
    allToggled: false,
    elements: {}, // filled in Backend.getElements()
    latestPath: '',
    markedRecordsForMassAction: [],
    indentationPadding: 26
  };

  Backend.initialize = function() {
    Backend.getElements();
    Backend.registerEvents();

    if (TYPO3.settings.Workspaces.depth > 0) {
      Backend.elements.$depthSelector.val(TYPO3.settings.Workspaces.depth);
    }

    Backend.loadWorkspaceComponents();
  };

  Backend.getElements = function() {
    Backend.elements.$searchForm = $(Backend.identifiers.searchForm);
    Backend.elements.$searchTextField = $(Backend.identifiers.searchTextField);
    Backend.elements.$searchSubmitBtn = $(Backend.identifiers.searchSubmitBtn);
    Backend.elements.$depthSelector = $(Backend.identifiers.depthSelector);
    Backend.elements.$languageSelector = $(Backend.identifiers.languageSelector);
    Backend.elements.$container = $(Backend.identifiers.container);
    Backend.elements.$tableBody = Backend.elements.$container.find('tbody');
    Backend.elements.$actionIcons = $(Backend.identifiers.actionIcons);
    Backend.elements.$toggleAll = $(Backend.identifiers.toggleAll);
    Backend.elements.$chooseStageAction = $(Backend.identifiers.chooseStageAction);
    Backend.elements.$chooseSelectionAction = $(Backend.identifiers.chooseSelectionAction);
    Backend.elements.$chooseMassAction = $(Backend.identifiers.chooseMassAction);
    Backend.elements.$previewLinksButton = $(Backend.identifiers.previewLinksButton);
    Backend.elements.$pagination = $(Backend.identifiers.pagination);
  };

  Backend.registerEvents = function() {
    $(document).on('click', '[data-action="swap"]', function(e) {
      var $tr = $(e.target).closest('tr');
      Workspaces.checkIntegrity(
        {
          selection: [
            {
              liveId: $tr.data('uid'),
              versionId: $tr.data('t3ver_oid'),
              table: $tr.data('table')
            }
          ],
          type: 'selection'
        }
      ).done(function(response) {
        if (response[0].result.result === 'warning') {
          Backend.addIntegrityCheckWarningToWizard();
        }

        Wizard.setup.forceSelection = false;
        Wizard.addSlide(
          'swap-confirm',
          'Swap',
          TYPO3.lang['window.swap.message'],
          Severity.info
        );
        Wizard.addFinalProcessingSlide(function() {
          // We passed this slide, swap the record now
          Workspaces.sendRemoteRequest(
            Workspaces.generateRemoteActionsPayload('swapSingleRecord', [
              $tr.data('table'),
              $tr.data('t3ver_oid'),
              $tr.data('uid')
            ])
          ).done(function() {
            Wizard.dismiss();
            Backend.getWorkspaceInfos();
            Backend.refreshPageTree();
          });
        }).done(function() {
          Wizard.show();
        });
      });
    }).on('click', '[data-action="prevstage"]', function(e) {
      Backend.sendToStage($(e.target).closest('tr'), 'prev');
    }).on('click', '[data-action="nextstage"]', function(e) {
      Backend.sendToStage($(e.target).closest('tr'), 'next');
    }).on('click', '[data-action="changes"]', Backend.viewChanges
    ).on('click', '[data-action="preview"]', Backend.openPreview
    ).on('click', '[data-action="open"]', function(e) {
      var $tr = $(e.target).closest('tr'),
        newUrl = TYPO3.settings.FormEngine.moduleUrl + '&returnUrl=' + encodeURIComponent(document.location.href) + '&id=' + TYPO3.settings.Workspaces.id + '&edit[' + $tr.data('table') + '][' + $tr.data('uid') + ']=edit';

      // Append workspace of record in all-workspaces view
      if (TYPO3.settings.Workspaces.allView) {
        newUrl += '&workspace=' + $tr.data('t3ver_wsid');
      }
      window.location.href = newUrl;
    }).on('click', '[data-action="version"]', function(e) {
      var $tr = $(e.target).closest('tr');
      if ($tr.data('table') === 'pages') {
        top.loadEditId($tr.data('t3ver_oid'));
      } else {
        top.loadEditId($tr.data('pid'));
      }
    }).on('click', '[data-action="remove"]', Backend.confirmDeleteRecordFromWorkspace
    ).on('click', '[data-action="expand"]', function(e) {
      var $me = $(this),
        $target = Backend.elements.$tableBody.find($me.data('target')),
        iconIdentifier;

      if ($target.first().attr('aria-expanded') === 'true') {
        iconIdentifier = 'apps-pagetree-expand';
      } else {
        iconIdentifier = 'apps-pagetree-collapse';
      }

      $me.html(Backend.getPreRenderedIcon(iconIdentifier));
    });

    Backend.elements.$searchForm.on('submit', function(e) {
      e.preventDefault();
      Backend.settings.filterTxt = Backend.elements.$searchTextField.val();
      Backend.getWorkspaceInfos();
    });

    Backend.elements.$searchTextField.on('keyup', function() {
      var $me = $(this);

      if ($me.val() !== '') {
        Backend.elements.$searchSubmitBtn.removeClass('disabled');
      } else {
        Backend.elements.$searchSubmitBtn.addClass('disabled');
        Backend.getWorkspaceInfos();
      }
    }).clearable(
      {
        onClear: function() {
          Backend.elements.$searchSubmitBtn.addClass('disabled');
          Backend.settings.filterTxt = '';
          Backend.getWorkspaceInfos();
        }
      }
    );

    // checkboxes in the table
    Backend.elements.$toggleAll.on('click', function() {
      Backend.allToggled = !Backend.allToggled;
      Backend.elements.$tableBody.find('input[type="checkbox"]').prop('checked', Backend.allToggled).trigger('change');
    });
    Backend.elements.$tableBody.on('change', 'tr input[type=checkbox]', Backend.handleCheckboxChange);

    // Listen for depth changes
    Backend.elements.$depthSelector.on('change', function(e) {
      var $me = $(this);
      Backend.settings.depth = $me.val();

      Backend.getWorkspaceInfos();
    });

    // Generate preview links
    Backend.elements.$previewLinksButton.on('click', Backend.generatePreviewLinks);

    // Listen for language changes
    Backend.elements.$languageSelector.on('change', function(e) {
      var $me = $(this);
      Backend.settings.language = $me.val();

      Workspaces.sendRemoteRequest([
        Workspaces.generateRemoteActionsPayload('saveLanguageSelection', [$me.val()]),
        Workspaces.generateRemotePayload('getWorkspaceInfos', Backend.settings)
      ]).done(function(response) {
        Backend.elements.$languageSelector.prev().html($me.find(':selected').data('icon'));
        Backend.renderWorkspaceInfos(response[1].result);
      });
    });

    // Listen for actions
    Backend.elements.$chooseStageAction.on('change', Backend.sendToSpecificStageAction);
    Backend.elements.$chooseSelectionAction.on('change', Backend.runSelectionAction);
    Backend.elements.$chooseMassAction.on('change', Backend.runMassAction);

    // clicking an action in the paginator
    Backend.elements.$pagination.on('click', 'a[data-action]', function(e) {
      e.preventDefault();

      var $el = $(this),
        reload = false;

      switch ($el.data('action')) {
        case 'previous':
          if (Backend.paging.currentPage > 1) {
            Backend.paging.currentPage--;
            reload = true;
          }
          break;
        case 'next':
          if (Backend.paging.currentPage < Backend.paging.totalPages) {
            Backend.paging.currentPage++;
            reload = true;
          }
          break;
        case 'page':
          Backend.paging.currentPage = parseInt($el.data('page'));
          reload = true;
          break;
      }

      if (reload) {
        // Adjust settings
        Backend.settings.start = Backend.settings.limit * (Backend.paging.currentPage - 1);
        Backend.getWorkspaceInfos();
      }
    });
  };

  Backend.handleCheckboxChange = function(e) {
    var $checkbox = $(this),
      $tr = $checkbox.parents('tr'),
      table = $tr.data('table'),
      uid = $tr.data('uid'),
      t3ver_oid = $tr.data('t3ver_oid'),
      record = table + ':' + uid + ':' + t3ver_oid;

    if ($checkbox.prop('checked')) {
      Backend.markedRecordsForMassAction.push(record);
      $tr.addClass('warning');
    } else {
      var index = Backend.markedRecordsForMassAction.indexOf(record);
      if (index > -1) {
        Backend.markedRecordsForMassAction.splice(index, 1);
      }
      $tr.removeClass('warning');
    }

    Backend.elements.$chooseStageAction.prop('disabled', Backend.markedRecordsForMassAction.length === 0);
    Backend.elements.$chooseSelectionAction.prop('disabled', Backend.markedRecordsForMassAction.length === 0);
    Backend.elements.$chooseMassAction.prop('disabled', Backend.markedRecordsForMassAction.length > 0);
  };

  /**
   * Generates the diff view of a record
   *
   * @param {Object} diff
   * @return {$}
   */
  Backend.generateDiffView = function(diff) {
    var $diff = $('<div />', {class: 'diff'});

    for (var i = 0; i < diff.length; ++i) {
      $diff.append(
        $('<div />', {class: 'diff-item'}).append(
          $('<div />', {class: 'diff-item-title'}).text(diff[i].label),
          $('<div />', {class: 'diff-item-result diff-item-result-inline'}).html(diff[i].content)
        )
      );
    }
    return $diff;
  };

  /**
   * Generates the comments view of a record
   *
   * @param {Object} comments
   * @return {$}
   */
  Backend.generateCommentView = function(comments) {
    var $comments = $('<div />');

    for (var i = 0; i < comments.length; ++i) {
      var $panel = $('<div />', {class: 'panel panel-default'});

      if (comments[i].user_comment.length > 0) {
        $panel.append(
          $('<div />', {class: 'panel-body'}).html(comments[i].user_comment)
        );
      }

      $panel.append(
        $('<div />', {class: 'panel-footer'}).append(
          $('<span />', {class: 'label label-success'}).text(comments[i].stage_title),
          $('<span />', {class: 'label label-info'}).text(comments[i].tstamp)
        )
      );

      $comments.append(
        $('<div />', {class: 'media'}).append(
          $('<div />', {class: 'media-left text-center'}).text(comments[i].user_username).prepend(
            $('<div />').html(comments[i].user_avatar)
          ),
          $('<div />', {class: 'media-body'}).append($panel)
        )
      );
    }

    return $comments;
  };

  /**
   * Sends a record to a stage
   *
   * @param {Object} $row
   * @param {String} direction
   */
  Backend.sendToStage = function($row, direction) {
    var nextStage,
      stageWindowAction,
      stageExecuteAction;

    if (direction === 'next') {
      nextStage = $row.data('nextStage');
      stageWindowAction = 'sendToNextStageWindow';
      stageExecuteAction = 'sendToNextStageExecute';
    } else if (direction === 'prev') {
      nextStage = $row.data('prevStage');
      stageWindowAction = 'sendToPrevStageWindow';
      stageExecuteAction = 'sendToPrevStageExecute';
    } else {
      throw 'Invalid direction given.';
    }

    Workspaces.sendRemoteRequest(
      Workspaces.generateRemoteActionsPayload(stageWindowAction, [
        $row.data('uid'), $row.data('table'), $row.data('t3ver_oid')
      ])
    ).done(function(response) {
      var $modal = Workspaces.renderSendToStageWindow(response);
      $modal.on('button.clicked', function(e) {
        if (e.target.name === 'ok') {
          var $form = $(e.currentTarget).find('form'),
            serializedForm = $form.serializeObject();

          serializedForm.affects = {
            table: $row.data('table'),
            nextStage: nextStage,
            t3ver_oid: $row.data('t3ver_oid'),
            uid: $row.data('uid'),
            elements: []
          };

          Workspaces.sendRemoteRequest([
            Workspaces.generateRemoteActionsPayload(stageExecuteAction, [serializedForm]),
            Workspaces.generateRemotePayload('getWorkspaceInfos', Backend.settings)
          ]).done(function(response) {
            $modal.modal('hide');
            Backend.renderWorkspaceInfos(response[1].result);
            Backend.refreshPageTree();
          });
        }
      });
    });
  };

  /**
   * Loads the workspace components, like available stage actions and items of the workspace
   */
  Backend.loadWorkspaceComponents = function() {
    Workspaces.sendRemoteRequest([
      Workspaces.generateRemotePayload('getWorkspaceInfos', Backend.settings),
      Workspaces.generateRemotePayload('getStageActions', {}),
      Workspaces.generateRemoteMassActionsPayload('getMassStageActions', {}),
      Workspaces.generateRemotePayload('getSystemLanguages', {})
    ]).done(function(response) {
      Backend.elements.$depthSelector.prop('disabled', false);

      // Records
      Backend.renderWorkspaceInfos(response[0].result);

      // Stage actions
      var stageActions = response[1].result.data,
        i;
      for (i = 0; i < stageActions.length; ++i) {
        Backend.elements.$chooseStageAction.append(
          $('<option />').val(stageActions[i].uid).text(stageActions[i].title)
        );
      }

      // Mass actions
      var massActions = response[2].result.data;
      for (i = 0; i < massActions.length; ++i) {
        Backend.elements.$chooseSelectionAction.append(
          $('<option />').val(massActions[i].action).text(massActions[i].title)
        );

        Backend.elements.$chooseMassAction.append(
          $('<option />').val(massActions[i].action).text(massActions[i].title)
        );
      }

      // Languages
      var languages = response[3].result.data;
      for (i = 0; i < languages.length; ++i) {
        var $option = $('<option />').val(languages[i].uid).text(languages[i].title).data('icon', languages[i].icon);
        if (String(languages[i].uid) === String(TYPO3.settings.Workspaces.language)) {
          $option.prop('selected', true);
          Backend.elements.$languageSelector.prev().html(languages[i].icon);
        }
        Backend.elements.$languageSelector.append($option);
      }
      Backend.elements.$languageSelector.prop('disabled', false);
    });
  };

  /**
   * Gets the workspace infos
   *
   * @return {Promise}
   * @protected
   */
  Backend.getWorkspaceInfos = function() {
    Workspaces.sendRemoteRequest(
      Workspaces.generateRemotePayload('getWorkspaceInfos', Backend.settings)
    ).done(function(response) {
      Backend.renderWorkspaceInfos(response[0].result);
    });
  };

  /**
   * Renders fetched workspace informations
   *
   * @param {Object} result
   */
  Backend.renderWorkspaceInfos = function(result) {
    Backend.elements.$tableBody.children().remove();
    Backend.allToggled = false;
    Backend.elements.$chooseStageAction.prop('disabled', true);
    Backend.elements.$chooseSelectionAction.prop('disabled', true);
    Backend.elements.$chooseMassAction.prop('disabled', result.data.length === 0);

    Backend.buildPagination(result.total);

    for (var i = 0; i < result.data.length; ++i) {
      var item = result.data[i],
        $actions = $('<div />', {class: 'btn-group'}),
        $integrityIcon = '';
      $actions.append(
        Backend.getAction(item.Workspaces_CollectionChildren > 0 && item.Workspaces_CollectionCurrent !== '', 'expand', 'apps-pagetree-collapse').attr('title', TYPO3.lang['tooltip.expand']).attr('data-target', '[data-collection="' + item.Workspaces_CollectionCurrent + '"]').attr('data-toggle', 'collapse'),
        $('<button />', {
          class: 'btn btn-default',
          'data-action': 'changes',
          'data-toggle': 'tooltip',
          title: TYPO3.lang['tooltip.showChanges']
        }).append(Backend.getPreRenderedIcon('actions-document-info')),
        Backend.getAction(item.allowedAction_swap && item.Workspaces_CollectionParent === '', 'swap', 'actions-version-swap-version').attr('title', TYPO3.lang['tooltip.swap']),
        Backend.getAction(item.allowedAction_view, 'preview', 'actions-version-workspace-preview').attr('title', TYPO3.lang['tooltip.viewElementAction']),
        $('<button />', {
          class: 'btn btn-default',
          'data-action': 'open',
          'data-toggle': 'tooltip',
          title: TYPO3.lang['tooltip.editElementAction']
        }).append(Backend.getPreRenderedIcon('actions-open')),
        $('<button />', {
          class: 'btn btn-default',
          'data-action': 'version',
          'data-toggle': 'tooltip',
          title: TYPO3.lang['tooltip.openPage']
        }).append(Backend.getPreRenderedIcon('actions-version-page-open')),
        Backend.getAction(item.allowedAction_delete, 'remove', 'actions-version-document-remove').attr('title', TYPO3.lang['tooltip.discardVersion']),
        $('<label />', {class: 'btn btn-default btn-checkbox'}).append(
          $('<input />', {type: 'checkbox'}),
          $('<span />', {class: 't3-icon fa'})
        )
      );

      if (item.integrity.messages !== '') {
        $integrityIcon = $(TYPO3.settings.Workspaces.icons[item.integrity.status]);
        $integrityIcon
          .attr('data-toggle', 'tooltip')
          .attr('data-placement', 'top')
          .attr('data-html', true)
          .attr('title', item.integrity.messages);
      }

      if (Backend.latestPath !== item.path_Workspace) {
        Backend.latestPath = item.path_Workspace;
        Backend.elements.$tableBody.append(
          $('<tr />').append(
            $('<th />', {colspan: 6}).text(Backend.latestPath)
          )
        );
      }

      var rowConfiguration = {
        'data-uid': item.uid,
        'data-pid': item.livepid,
        'data-t3ver_oid': item.t3ver_oid,
        'data-t3ver_wsid': item.t3ver_wsid,
        'data-table': item.table,
        'data-next-stage': item.value_nextStage,
        'data-prev-stage': item.value_prevStage,
        'data-stage': item.stage
      };

      if (item.Workspaces_CollectionParent !== '') {
        rowConfiguration['data-collection'] = item.Workspaces_CollectionParent;
        rowConfiguration['class'] = 'collapse';
      }

      Backend.elements.$tableBody.append(
        $('<tr />', rowConfiguration).append(
          $('<td />', {
            class: 't3js-title-workspace',
            style: item.Workspaces_CollectionLevel > 0 ? 'padding-left: ' + Backend.indentationPadding * item.Workspaces_CollectionLevel + 'px' : ''
          }).html(item.icon_Workspace + '&nbsp;' + '<a href="#" data-action="changes"><span class="item-state-' + item.state_Workspace + '">' + item.label_Workspace + '</span></a>'),
          $('<td />', {class: 't3js-title-live'}).html(item.icon_Live + '&nbsp;' + item.label_Live),
          $('<td />').text(item.label_Stage),
          $('<td />').html($integrityIcon),
          $('<td />').html(item.language.icon),
          $('<td />', {class: 'text-right nowrap'}).append($actions)
        )
      );

      Tooltip.initialize('[data-toggle="tooltip"]', {
        delay: {
          show: 500,
          hide: 100
        },
        trigger: 'hover',
        container: 'body'
      });
    }
  };

  /**
   * Renders the pagination
   *
   * @param {Number} totalItems
   */
  Backend.buildPagination = function(totalItems) {
    if (totalItems === 0) {
      Backend.elements.$pagination.contents().remove();
      return;
    }

    Backend.paging.totalItems = totalItems;
    Backend.paging.totalPages = Math.ceil(totalItems / Backend.settings.limit);

    if (Backend.paging.totalPages === 1) {
      // early abort if only one page is available
      Backend.elements.$pagination.contents().remove();
      return;
    }

    var $ul = $('<ul />', {class: 'pagination pagination-block'}),
      liElements = [],
      $controlFirstPage = $('<li />').append(
        $('<a />', {'data-action': 'previous'}).append(
          $('<span />', {class: 't3-icon fa fa-arrow-left'})
        )
      ),
      $controlLastPage = $('<li />').append(
        $('<a />', {'data-action': 'next'}).append(
          $('<span />', {class: 't3-icon fa fa-arrow-right'})
        )
      );

    if (Backend.paging.currentPage === 1) {
      $controlFirstPage.disablePagingAction();
    }

    if (Backend.paging.currentPage === Backend.paging.totalPages) {
      $controlLastPage.disablePagingAction();
    }

    for (var i = 1; i <= Backend.paging.totalPages; i++) {
      var $li = $('<li />', {class: Backend.paging.currentPage === i ? 'active' : ''});
      $li.append(
        $('<a />', {'data-action': 'page', 'data-page': i}).append(
          $('<span />').text(i)
        )
      );
      liElements.push($li);
    }

    $ul.append($controlFirstPage, liElements, $controlLastPage);
    Backend.elements.$pagination.html($ul);
  };

  /**
   * View changes of a record
   *
   * @param {Event} e
   */
  Backend.viewChanges = function(e) {
    e.preventDefault();

    var $tr = $(e.target).closest('tr');

    Workspaces.sendRemoteRequest(
      Workspaces.generateRemotePayload('getRowDetails', {
        stage: $tr.data('stage'),
        t3ver_oid: $tr.data('t3ver_oid'),
        table: $tr.data('table'),
        uid: $tr.data('uid')
      })
    ).done(function(response) {
      var item = response[0].result.data[0],
        $content = $('<div />'),
        $tabsNav = $('<ul />', {class: 'nav nav-tabs', role: 'tablist'}),
        $tabsContent = $('<div />', {class: 'tab-content'}),
        modalButtons = [];

      $content.append(
        $('<p />').html(TYPO3.lang['path'].replace('{0}', item.path_Live)),
        $('<p />').html(TYPO3.lang['current_step'].replace('{0}', item.label_Stage).replace('{1}', item.stage_position).replace('{2}', item.stage_count))
      );

      if (item.diff.length > 0) {
        $tabsNav.append(
          $('<li />', {role: 'presentation'}).append(
            $('<a />', {
              href: '#workspace-changes',
              'aria-controls': 'workspace-changes',
              role: 'tab',
              'data-toggle': 'tab'
            }).text(TYPO3.lang['window.recordChanges.tabs.changeSummary'])
          )
        );
        $tabsContent.append(
          $('<div />', {role: 'tabpanel', class: 'tab-pane', id: 'workspace-changes'}).append(
            $('<div />', {class: 'form-section'}).append(
              Backend.generateDiffView(item.diff)
            )
          )
        );
      }

      if (item.comments.length > 0) {
        $tabsNav.append(
          $('<li />', {role: 'presentation'}).append(
            $('<a />', {
              href: '#workspace-comments',
              'aria-controls': 'workspace-comments',
              role: 'tab',
              'data-toggle': 'tab'
            }).html(TYPO3.lang['window.recordChanges.tabs.comments'] + '&nbsp;').append(
              $('<span />', {class: 'badge'}).text(item.comments.length)
            )
          )
        );
        $tabsContent.append(
          $('<div />', {role: 'tabpanel', class: 'tab-pane', id: 'workspace-comments'}).append(
            $('<div />', {class: 'form-section'}).append(
              Backend.generateCommentView(item.comments)
            )
          )
        );
      }

      if (item.history.total > 0) {
        $tabsNav.append(
          $('<li />', {role: 'presentation'}).append(
            $('<a />', {
              href: '#workspace-history',
              'aria-controls': 'workspace-history',
              role: 'tab',
              'data-toggle': 'tab'
            }).text(TYPO3.lang['window.recordChanges.tabs.history'])
          )
        );

        $tabsContent.append(
          $('<div />', {role: 'tabpanel', class: 'tab-pane', id: 'workspace-history'}).append(
            $('<div />', {class: 'form-section'}).append(
              Backend.generateHistoryView(item.history.data)
            )
          )
        );
      }

      // Mark the first tab and pane as active
      $tabsNav.find('li').first().addClass('active');
      $tabsContent.find('.tab-pane').first().addClass('active');

      // Attach tabs
      $content.append(
        $('<div />').append(
          $tabsNav,
          $tabsContent
        )
      );

      if ($tr.data('stage') !== $tr.data('prevStage')) {
        modalButtons.push({
          text: item.label_PrevStage.title,
          active: true,
          btnClass: 'btn-default',
          name: 'prevstage',
          trigger: function() {
            Modal.currentModal.trigger('modal-dismiss');
            Backend.sendToStage($(e.target).closest('tr'), 'prev');
          }
        });
      }

      modalButtons.push({
        text: item.label_NextStage.title,
        active: true,
        btnClass: 'btn-default',
        name: 'nextstage',
        trigger: function() {
          Modal.currentModal.trigger('modal-dismiss');
          Backend.sendToStage($(e.target).closest('tr'), 'next');
        }
      });
      modalButtons.push({
        text: TYPO3.lang['close'],
        active: true,
        btnClass: 'btn-info',
        name: 'cancel',
        trigger: function() {
          Modal.currentModal.trigger('modal-dismiss');
        }
      });

      Modal.show(
        TYPO3.lang['window.recordInformation'].replace('{0}', $.trim($tr.find('.t3js-title-live').text())),
        $content,
        Severity.info,
        modalButtons
      );
    });
  };

  /**
   * Opens a record in a preview window
   *
   * @param {Event} e
   */
  Backend.openPreview = function(e) {
    var $tr = $(e.target).closest('tr');

    Workspaces.sendRemoteRequest(
      Workspaces.generateRemoteActionsPayload('viewSingleRecord', [
        $tr.data('table'), $tr.data('uid')
      ])
    ).done(function(response) {
      eval(response[0].result);
    });
  };

  /**
   * Renders the record's history
   *
   * @param {Object} data
   */
  Backend.generateHistoryView = function(data) {
    var $history = $('<div />');

    for (var i = 0; i < data.length; ++i) {
      var $panel = $('<div />', {class: 'panel panel-default'}),
        $diff;

      if (typeof data[i].differences === 'object') {
        if (data[i].differences.length === 0) {
          // Somehow here are no differences. What a pity, skip that record
          continue;
        }
        $diff = $('<div />', {class: 'diff'});

        for (var j = 0; j < data[i].differences.length; ++j) {
          $diff.append(
            $('<div />', {class: 'diff-item'}).append(
              $('<div />', {class: 'diff-item-title'}).text(data[i].differences[j].label),
              $('<div />', {class: 'diff-item-result diff-item-result-inline'}).html(data[i].differences[j].html)
            )
          );
        }

        $panel.append(
          $('<div />').append($diff)
        );
      } else {
        $panel.append(
          $('<div />', {class: 'panel-body'}).text(data[i].differences)
        );
      }
      $panel.append(
        $('<div />', {class: 'panel-footer'}).append(
          $('<span />', {class: 'label label-info'}).text(data[i].datetime)
        )
      );

      $history.append(
        $('<div />', {class: 'media'}).append(
          $('<div />', {class: 'media-left text-center'}).text(data[i].user).prepend(
            $('<div />').html(data[i].user_avatar)
          ),
          $('<div />', {class: 'media-body'}).append($panel)
        )
      );
    }

    return $history;
  };

  /**
   * Shows a confirmation modal and deletes the selected record from workspace.
   *
   * @param {Event} e
   */
  Backend.confirmDeleteRecordFromWorkspace = function(e) {
    var $tr = $(e.target).closest('tr');
    var $modal = Modal.confirm(
      TYPO3.lang['window.discard.title'],
      TYPO3.lang['window.discard.message'],
      Severity.warning,
      [
        {
          text: TYPO3.lang['cancel'],
          active: true,
          btnClass: 'btn-default',
          name: 'cancel',
          trigger: function() {
            $modal.modal('hide');
          }
        }, {
        text: TYPO3.lang['ok'],
        btnClass: 'btn-warning',
        name: 'ok'
      }
      ]
    );
    $modal.on('button.clicked', function(e) {
      if (e.target.name === 'ok') {
        Workspaces.sendRemoteRequest([
          Workspaces.generateRemoteActionsPayload('deleteSingleRecord', [
            $tr.data('table'),
            $tr.data('uid')
          ])
        ]).done(function() {
          $modal.modal('hide');
          Backend.getWorkspaceInfos();
          Backend.refreshPageTree();
        });
      }
    });
  };

  /**
   * Runs a mass action
   */
  Backend.runSelectionAction = function() {
    var selectedAction = Backend.elements.$chooseSelectionAction.val(),
      integrityCheckRequired = selectedAction !== 'discard';

    if (selectedAction.length === 0) {
      // Don't do anything if that value is empty
      return;
    }

    var affectedRecords = [];
    for (var i = 0; i < Backend.markedRecordsForMassAction.length; ++i) {
      var affected = Backend.markedRecordsForMassAction[i].split(':');
      affectedRecords.push({
        table: affected[0],
        liveId: affected[2],
        versionId: affected[1]
      });
    }

    if (!integrityCheckRequired) {
      Wizard.setup.forceSelection = false;
      Backend.renderSelectionActionWizard(selectedAction, affectedRecords);
    } else {
      Workspaces.checkIntegrity(
        {
          selection: affectedRecords,
          type: 'selection'
        }
      ).done(function(response) {
        Wizard.setup.forceSelection = false;
        if (response[0].result.result === 'warning') {
          Backend.addIntegrityCheckWarningToWizard();
        }
        Backend.renderSelectionActionWizard(selectedAction, affectedRecords);
      });
    }
  };

  /**
   * Adds a slide to the wizard concerning an integrity check warning.
   */
  Backend.addIntegrityCheckWarningToWizard = function() {
    Wizard.addSlide(
      'integrity-warning',
      'Warning',
      TYPO3.lang['integrity.hasIssuesDescription'] + '<br>' + TYPO3.lang['integrity.hasIssuesQuestion'],
      Severity.warning
    );
  };

  /**
   * Renders the wizard for selection actions
   *
   * @param {String} selectedAction
   * @param {Object} affectedRecords
   */
  Backend.renderSelectionActionWizard = function(selectedAction, affectedRecords) {
    Wizard.addSlide(
      'mass-action-confirmation',
      TYPO3.lang['window.selectionAction.title'],
      $('<p />').text(TYPO3.lang['tooltip.' + selectedAction + 'Selected']),
      Severity.warning
    );
    Wizard.addFinalProcessingSlide(function() {
      Workspaces.sendRemoteRequest(
        Workspaces.generateRemoteActionsPayload('executeSelectionAction', {
          action: selectedAction,
          selection: affectedRecords
        })
      ).done(function() {
        Backend.getWorkspaceInfos();
        Wizard.dismiss();
        Backend.refreshPageTree();
      });
    }).done(function() {
      Wizard.show();

      Wizard.getComponent().on('wizard-dismissed', function() {
        Backend.elements.$chooseSelectionAction.val('');
      });
    });
  };

  /**
   * Runs a mass action
   */
  Backend.runMassAction = function() {
    var selectedAction = Backend.elements.$chooseMassAction.val(),
      integrityCheckRequired = selectedAction !== 'discard';

    if (selectedAction.length === 0) {
      // Don't do anything if that value is empty
      return;
    }

    if (!integrityCheckRequired) {
      Wizard.setup.forceSelection = false;
      Backend.renderMassActionWizard(selectedAction);
    } else {
      Workspaces.checkIntegrity(
        {
          language: Backend.settings.language,
          type: selectedAction
        }
      ).done(function(response) {
        Wizard.setup.forceSelection = false;
        if (response[0].result.result === 'warning') {
          Backend.addIntegrityCheckWarningToWizard();
        }
        Backend.renderMassActionWizard(selectedAction);
      });
    }
  };

  /**
   * Renders the wizard for mass actions
   *
   * @param {String} selectedAction
   */
  Backend.renderMassActionWizard = function(selectedAction) {
    var massAction,
      doSwap = false;

    switch (selectedAction) {
      case 'publish':
        massAction = 'publishWorkspace';
        break;
      case 'swap':
        massAction = 'publishWorkspace';
        doSwap = true;
        break;
      case 'discard':
        massAction = 'flushWorkspace';
        break;
    }

    if (massAction === null) {
      throw 'Invalid mass action ' + selectedAction + ' called.';
    }

    Wizard.setup.forceSelection = false;
    Wizard.addSlide(
      'mass-action-confirmation',
      TYPO3.lang['window.massAction.title'],
      $('<p />').html(TYPO3.lang['tooltip.' + selectedAction + 'All'] + '<br><br>' + TYPO3.lang['tooltip.affectWholeWorkspace']),
      Severity.warning
    );
    Wizard.addFinalProcessingSlide(function() {
      Workspaces.sendRemoteRequest(
        Workspaces.generateRemoteMassActionsPayload(massAction, {
          init: true,
          total: 0,
          processed: 0,
          language: Backend.settings.language,
          swap: doSwap
        })
      ).done(function(response) {
        var payload = response[0].result;
        Workspaces.sendRemoteRequest(
          Workspaces.generateRemoteMassActionsPayload(massAction, payload)
        ).done(function() {
          Backend.getWorkspaceInfos();
          Wizard.dismiss();
        });
      });
    }).done(function() {
      Wizard.show();

      Wizard.getComponent().on('wizard-dismissed', function() {
        Backend.elements.$chooseMassAction.val('');
      });
    });
  };

  /**
   * Sends marked records to a stage
   *
   * @param {Event} e
   */
  Backend.sendToSpecificStageAction = function(e) {
    var affectedRecords = [],
      stage = $(e.currentTarget).val();
    for (var i = 0; i < Backend.markedRecordsForMassAction.length; ++i) {
      var affected = Backend.markedRecordsForMassAction[i].split(':');
      affectedRecords.push({
        table: affected[0],
        uid: affected[1],
        t3ver_oid: affected[2]
      });
    }
    Workspaces.sendRemoteRequest(
      Workspaces.generateRemoteActionsPayload('sendToSpecificStageWindow', [
        stage, affectedRecords
      ])
    ).done(function(response) {
      var $modal = Workspaces.renderSendToStageWindow(response);
      $modal.on('button.clicked', function(e) {
        if (e.target.name === 'ok') {
          var $form = $(e.currentTarget).find('form'),
            serializedForm = $form.serializeObject();

          serializedForm.affects = {
            elements: affectedRecords,
            nextStage: stage
          };

          Workspaces.sendRemoteRequest([
            Workspaces.generateRemoteActionsPayload('sendToSpecificStageExecute', [serializedForm]),
            Workspaces.generateRemotePayload('getWorkspaceInfos', Backend.settings)
          ]).done(function(response) {
            $modal.modal('hide');
            Backend.renderWorkspaceInfos(response[1].result);
            Backend.refreshPageTree();
          });
        }
      }).on('modal-destroyed', function() {
        Backend.elements.$chooseStageAction.val('');
      });
    });
  };

  /**
   * Reloads the page tree
   */
  Backend.refreshPageTree = function() {
    if (top.TYPO3 && top.TYPO3.Backend && top.TYPO3.Backend.NavigationContainer && top.TYPO3.Backend.NavigationContainer.PageTree) {
      top.TYPO3.Backend.NavigationContainer.PageTree.refreshTree();
    }
  };

  /**
   * Renders the action button based on the user's permission.
   *
   * @returns {$}
   * @private
   */
  Backend.getAction = function(condition, action, iconIdentifier) {
    if (condition) {
      return $('<button />', {
        class: 'btn btn-default',
        'data-action': action,
        'data-toggle': 'tooltip'
      }).append(Backend.getPreRenderedIcon(iconIdentifier))
    }
    return $('<span />', {class: 'btn btn-default disabled'}).append(Backend.getPreRenderedIcon('empty-empty'));
  };

  /**
   * Fetches and renders available preview links
   */
  Backend.generatePreviewLinks = function() {
    Workspaces.sendRemoteRequest(
      Workspaces.generateRemoteActionsPayload('generateWorkspacePreviewLinksForAllLanguages', [
        Backend.settings.id
      ])
    ).done(function(response) {
      var result = response[0].result,
        $list = $('<dl />');

      $.each(result, function(language, url) {
        $list.append(
          $('<dt />').text(language),
          $('<dd />').append(
            $('<a />', {href: url, target: '_blank'}).text(url)
          )
        );
      });

      Modal.show(
        TYPO3.lang['previewLink'],
        $list,
        Severity.info,
        [{
          text: TYPO3.lang['ok'],
          active: true,
          btnClass: 'btn-info',
          name: 'ok',
          trigger: function() {
            Modal.currentModal.trigger('modal-dismiss');
          }
        }],
        ['modal-inner-scroll']
      );
    });
  };

  /**
   * Gets the pre-rendered icon
   * This method is intended to be dropped once we use Fluid's StandaloneView.
   *
   * @param {String} identifier
   * @returns {$}
   */
  Backend.getPreRenderedIcon = function(identifier) {
    return Backend.elements.$actionIcons.find('[data-identifier="' + identifier + '"]').clone();
  };

  /**
   * Serialize a form to a JavaScript object
   *
   * @see http://stackoverflow.com/a/1186309/4828813
   * @return {Object}
   */
  $.fn.serializeObject = function() {
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
      if (typeof o[this.name] !== 'undefined') {
        if (!o[this.name].push) {
          o[this.name] = [o[this.name]];
        }
        o[this.name].push(this.value || '');
      } else {
        o[this.name] = this.value || '';
      }
    });
    return o;
  };

  /**
   * Changes the markup of a pagination action being disabled
   */
  $.fn.disablePagingAction = function() {
    $(this).addClass('disabled').find('.t3-icon').unwrap().wrap($('<span />'));
  };

  $(Backend.initialize);
});
