/**
  This controller supports all actions related to a topic

  @class TopicController
  @extends Discourse.ObjectController
  @namespace Discourse
  @module Discourse
**/
Discourse.TopicController = Discourse.ObjectController.extend({
  userFilters: new Em.Set(),
  multiSelect: false,
  bestOf: false,
  summaryCollapsed: true,
  loading: false,
  loadingBelow: false,
  loadingAbove: false,
  needs: ['header', 'modal', 'composer', 'quoteButton'],

  selectedPosts: function() {
    var posts = this.get('content.posts');
    if (!posts) return null;
    return posts.filterProperty('selected');
  }.property('content.posts.@each.selected'),

  selectedCount: function() {
    if (!this.get('selectedPosts')) return 0;
    return this.get('selectedPosts').length;
  }.property('selectedPosts'),

  canMoveSelected: function() {
    if (!this.get('content.can_move_posts')) return false;
    // For now, we can move it if we can delete it since the posts need to be deleted.
    return this.get('canDeleteSelected');
  }.property('canDeleteSelected'),

  canDeleteSelected: function() {
    var selectedPosts = this.get('selectedPosts');
    if (!(selectedPosts && selectedPosts.length > 0)) return false;

    var canDelete = true;
    selectedPosts.each(function(p) {
      if (!p.get('can_delete')) {
        canDelete = false;
        return false;
      }
    });
    return canDelete;
  }.property('selectedPosts'),

  multiSelectChanged: function() {
    // Deselect all posts when multi select is turned off
    if (!this.get('multiSelect')) {
      var posts = this.get('content.posts');
      if (posts) {
        posts.forEach(function(p) {
          p.set('selected', false);
        });
      }
    }
  }.observes('multiSelect'),

  hideProgress: function() {
    if (!this.get('content.loaded')) return true;
    if (!this.get('currentPost')) return true;
    if (this.get('content.filtered_posts_count') < 2) return true;
    return false;
  }.property('content.loaded', 'currentPost', 'content.filtered_posts_count'),

  selectPost: function(post) {
    post.toggleProperty('selected');
  },

  toggleMultiSelect: function() {
    this.toggleProperty('multiSelect');
  },

  toggleSummary: function() {
    this.toggleProperty('summaryCollapsed');
  },

  moveSelected: function() {
    var modalController = this.get('controllers.modal');
    if (!modalController) return;

    modalController.show(Discourse.MoveSelectedView.create({
      topic: this.get('content'),
      selectedPosts: this.get('selectedPosts')
    }));
  },

  deleteSelected: function() {
    var topicController = this;
    return bootbox.confirm(Em.String.i18n("post.delete.confirm", {
      count: this.get('selectedCount')
    }), function(result) {
      if (result) {
        var selectedPosts = topicController.get('selectedPosts');
        Discourse.Post.deleteMany(selectedPosts);
        topicController.get('content.posts').removeObjects(selectedPosts);
      }
    });
  },

  jumpTop: function() {
    Discourse.URL.routeTo(this.get('content.url'));
  },

  jumpBottom: function() {
    Discourse.URL.routeTo(this.get('content.lastPostUrl'));
  },

  cancelFilter: function() {
    this.set('bestOf', false);
    this.get('userFilters').clear();
  },

  replyAsNewTopic: function(post) {
    // TODO shut down topic draft cleanly if it exists ...
    var composerController = this.get('controllers.composer');
    var promise = composerController.open({
      action: Discourse.Composer.CREATE_TOPIC,
      draftKey: Discourse.Composer.REPLY_AS_NEW_TOPIC_KEY
    });
    var postUrl = "" + location.protocol + "//" + location.host + (post.get('url'));
    var postLink = "[" + (this.get('title')) + "](" + postUrl + ")";

    promise.then(function() {
      Discourse.Post.loadQuote(post.get('id')).then(function(q) {
        composerController.appendText("" + (Em.String.i18n("post.continue_discussion", {
          postLink: postLink
        })) + "\n\n" + q);
      });
    });
  },

  // Topic related
  reply: function() {
    this.get('controllers.composer').open({
      topic: this.get('content'),
      action: Discourse.Composer.REPLY,
      draftKey: this.get('content.draft_key'),
      draftSequence: this.get('content.draft_sequence')
    });
  },

  toggleParticipant: function(user) {
    this.set('bestOf', false);
    var username = Em.get(user, 'username');
    var userFilters = this.get('userFilters');
    if (userFilters.contains(username)) {
      userFilters.remove(username);
    } else {
      userFilters.add(username);
    }
  },

  /**
    Show or hide the bottom bar, depending on our filter options.

    @method updateBottomBar
  **/
  updateBottomBar: function() {

    var postFilters = this.get('postFilters');

    if (postFilters.bestOf) {
      this.set('filterDesc', Em.String.i18n("topic.filters.best_of", {
        n_best_posts: Em.String.i18n("topic.filters.n_best_posts", { count: this.get('filtered_posts_count') }),
        of_n_posts: Em.String.i18n("topic.filters.of_n_posts", { count: this.get('posts_count') })
      }));
    } else if (postFilters.userFilters.length > 0) {
      this.set('filterDesc', Em.String.i18n("topic.filters.user", {
        n_posts: Em.String.i18n("topic.filters.n_posts", { count: this.get('filtered_posts_count') }),
        by_n_users: Em.String.i18n("topic.filters.by_n_users", { count: postFilters.userFilters.length })
      }));
    } else {
      // Hide the bottom bar
      $('#topic-filter').slideUp();
      return;
    }

    $('#topic-filter').slideDown();
  },

  enableBestOf: function(e) {
    this.set('bestOf', true);
    this.get('userFilters').clear();
  },

  postFilters: function() {
    if (this.get('bestOf') === true) return { bestOf: true };
    return { userFilters: this.get('userFilters') };
  }.property('userFilters.[]', 'bestOf'),

  loadPosts: function(opts) {
    var topicController = this;
    this.get('content').loadPosts(opts).then(function () {
      Em.run.next(function () { topicController.updateBottomBar(); });
    });
  },

  reloadPosts: function() {
    var topic = this.get('content');
    if (!topic) return;

    var posts = topic.get('posts');
    if (!posts) return;

    // Leave the first post -- we keep it above the filter controls
    posts.removeAt(1, posts.length - 1);

    this.set('loadingBelow', true);

    var topicController = this;
    var postFilters = this.get('postFilters');
    return Discourse.Topic.find(this.get('id'), postFilters).then(function(result) {
      var first = result.posts.first();
      if (first) {
        topicController.set('currentPost', first.post_number);
      }
      $('#topic-progress .solid').data('progress', false);
      result.posts.each(function(p) {
        // Skip the first post
        if (p.post_number === 1) return;
        posts.pushObject(Discourse.Post.create(p, topic));
      });

      Em.run.next(function () { topicController.updateBottomBar(); });

      topicController.set('filtered_posts_count', result.filtered_posts_count);
      topicController.set('loadingBelow', false);
      topicController.set('seenBottom', false);
    });
  }.observes('postFilters'),

  deleteTopic: function(e) {
    var topicController = this;
    this.unsubscribe();
    this.get('content').destroy().then(function() {
      topicController.set('message', Em.String.i18n('topic.deleted'));
      topicController.set('loaded', false);
    });
  },

  toggleVisibility: function() {
    this.get('content').toggleStatus('visible');
  },

  toggleClosed: function() {
    this.get('content').toggleStatus('closed');
  },

  togglePinned: function() {
    this.get('content').toggleStatus('pinned');
  },

  toggleArchived: function() {
    this.get('content').toggleStatus('archived');
  },

  convertToRegular: function() {
    this.get('content').convertArchetype('regular');
  },

  startTracking: function() {
    var screenTrack = Discourse.ScreenTrack.create({ topic_id: this.get('content.id') });
    screenTrack.start();
    this.set('content.screenTrack', screenTrack);
  },

  stopTracking: function() {
    var screenTrack = this.get('content.screenTrack');
    if (screenTrack) screenTrack.stop();
    this.set('content.screenTrack', null);
  },

  // Toggle the star on the topic
  toggleStar: function(e) {
    this.get('content').toggleStar();
  },

  /**
    Clears the pin from a topic for the currentUser

    @method clearPin
  **/
  clearPin: function() {
    this.get('content').clearPin();
  },

  // Receive notifications for this topic
  subscribe: function() {
    var bus = Discourse.MessageBus;

    // there is a condition where the view never calls unsubscribe, navigate to a topic from a topic
    bus.unsubscribe('/topic/*');

    var topicController = this;
    bus.subscribe("/topic/" + (this.get('content.id')), function(data) {
      var topic = topicController.get('content');
      if (data.notification_level_change) {
        topic.set('notification_level', data.notification_level_change);
        topic.set('notifications_reason_id', data.notifications_reason_id);
        return;
      }
      var posts = topic.get('posts');
      if (posts.some(function(p) {
        return p.get('post_number') === data.post_number;
      })) {
        return;
      }

      // Robin, TODO when a message comes in we need to figure out if it even goes
      //  in this view ... for now fixed the general case
      topic.set('filtered_posts_count', topic.get('filtered_posts_count') + 1);
      topic.set('highest_post_number', data.post_number);
      topic.set('last_poster', data.user);
      topic.set('last_posted_at', data.created_at);
      Discourse.notifyTitle();
    });
  },

  unsubscribe: function() {
    var topicId = this.get('content.id');
    if (!topicId) return;
    Discourse.MessageBus.unsubscribe("/topic/" + topicId);
  },

  // Post related methods
  replyToPost: function(post) {
    var composerController = this.get('controllers.composer');
    var quoteController = this.get('controllers.quoteButton');
    var quotedText = Discourse.BBCode.buildQuoteBBCode(quoteController.get('post'), quoteController.get('buffer'));
    quoteController.set('buffer', '');

    if (composerController.get('content.topic.id') === post.get('topic.id') &&
        composerController.get('content.action') === Discourse.Composer.REPLY) {
      composerController.set('content.post', post);
      composerController.set('content.composeState', Discourse.Composer.OPEN);
      composerController.appendText(quotedText);
    } else {
      var promise = composerController.open({
        post: post,
        action: Discourse.Composer.REPLY,
        draftKey: post.get('topic.draft_key'),
        draftSequence: post.get('topic.draft_sequence')
      });
      promise.then(function() { composerController.appendText(quotedText); });
    }
    return false;
  },

  // Edits a post
  editPost: function(post) {
    this.get('controllers.composer').open({
      post: post,
      action: Discourse.Composer.EDIT,
      draftKey: post.get('topic.draft_key'),
      draftSequence: post.get('topic.draft_sequence')
    });
  },

  toggleBookmark: function(post) {
    if (!Discourse.get('currentUser')) {
      alert(Em.String.i18n("bookmarks.not_bookmarked"));
      return;
    }
    post.toggleProperty('bookmarked');
    return false;
  },

  clearFlags: function(actionType) {
    actionType.clearFlags();
  },

  // Who acted on a particular post / action type
  whoActed: function(actionType) {
    actionType.loadUsers();
  },

  showPrivateInviteModal: function() {
    var modal = Discourse.InvitePrivateModalView.create({
      topic: this.get('content')
    });

    var modalController = this.get('controllers.modal');
    if (modalController) {
      modalController.show(modal);
    }
  },

  showInviteModal: function() {
    var modalController = this.get('controllers.modal');
    if (modalController) {
      modalController.show(Discourse.InviteModalView.create({
        topic: this.get('content')
      }));
    }
  },

  // Clicked the flag button
  showFlags: function(post) {
    var modalController = this.get('controllers.modal');
    if (modalController) {
      modalController.show(Discourse.FlagView.create({
        post: post,
        controller: this
      }));
    }
  },

  showHistory: function(post) {
    var modalController = this.get('controllers.modal');
    if (modalController) {
      modalController.show(Discourse.HistoryView.create({
        originalPost: post
      }));
    }
  },

  recoverPost: function(post) {
    post.set('deleted_at', null);
    post.recover();
  },

  deletePost: function(post) {
    // Moderators can delete posts. Regular users can only create a deleted at message.
    if (Discourse.get('currentUser.moderator')) {
      post.set('deleted_at', new Date());
    } else {
      post.set('cooked', Discourse.Markdown.cook(Em.String.i18n("post.deleted_by_author")));
      post.set('can_delete', false);
      post.set('version', post.get('version') + 1);
    }
    post.destroy();
  },

  postRendered: function(post) {
    var onPostRendered = this.get('onPostRendered');
    if (onPostRendered) {
      onPostRendered(post);
    }
  }
});


