
class PullRequestsController < ApplicationController
  before_filter :authorize_logged
  before_filter :find_project_and_repository
  before_filter :connect_gitlab, :only => [:index, :show, :create, :accept_pull_request, :pull_request_commits, :pull_request_changes, :new,
                                              :update_pull_request, :pull_request_comments, :create_pull_request_comment]

  layout "base_projects"
  include PullRequestsHelper
  include ApplicationHelper

  # 返回json格式
  def index
    type = params[:type]
    case type
      when nil, "1"
        @requests = @g.merge_requests(@project.gpid).select{|request| request.state == "opened" || request.state == "reopened"}
      when "2"
        @requests = @g.merge_requests(@project.gpid).select{|request| request.state == "merged"}
      when "3"
        @requests = @g.merge_requests(@project.gpid).select{|request| request.state == "closed"}
    end
    @requests_opened_count = @requests.count
    @requests_merged_count = @g.merge_requests(@project.gpid).select{|request| request.state == "merged"}.count
    @requests_closed_count = @g.merge_requests(@project.gpid).select{|request| request.state == "closed"}.count

    @limit = 10
    @is_remote = true
    @count = type_count(type, @requests_opened_count, @requests_merged_count, @requests_closed_count)
    @pages = Paginator.new @count, @limit, params['page'] || 1
    @offset ||= @pages.offset
    @requests = paginateHelper @requests, 10
    respond_to do |format|
      format.html
      format.js
    end
  end

  # 主要取源项目和目标项目分支及标识（用户名/版本库名）
  def new
    identifier = get_rep_identifier_by_project @project
    @source_project_name = "#{get_user_name(@project.user_id)}/#{identifier}"
    @source_rev = @g.branches(@project.gpid).map{|b| b.name}

    # 获取forked源项目信息
    if @project.forked_from_project_id
      @forked_project = Project.find(@project.forked_from_project_id)
      identifier = get_rep_identifier_by_project @forked_project
      @forked_project_name = "#{get_user_name(@forked_project.user_id)}/#{identifier}"
      @forked_rev = @g.branches(@forked_project.gpid).map{|b| b.name}
    end
  end

  # Creates a merge request.
  # If the operation is successful, 200 and the newly created merge request is returned. If an error occurs, an error number and a message explaining the reason is returned.
  #
  # @example
  #   Gitlab.create_merge_request(5, 'New merge request',
  #     :source_branch => 'source_branch', :target_branch => 'target_branch')
  #   Gitlab.create_merge_request(5, 'New merge request',
  #     :source_branch => 'source_branch', :target_branch => 'target_branch', :assignee_id => 42)
  #
  # @param  [Integer] project The ID of a project.
  # @param  [String] title The title of a merge request.
  # @param  [Hash] options A customizable set of options.
  # @option options [String] :source_branch (required) The source branch name.
  # @option options [String] :target_branch (required) The target branch name.
  # @option options [Integer] :assignee_id (optional) The ID of a user to assign merge request.
  # @return [Gitlab::ObjectifiedHash] Information about created merge request.
  def create
    title = params[:title]
    description = params[:description]
    source_branch = params[:source_branch]
    target_branch = params[:target_branch]
    begin
      # 如果传送了目标项目ID，则PR请求发至目标项目
      if params[:forked_project_id] && params[:source_project] == "forked_project_name"
        target_project_id = params[:forked_project_id].to_i
        request = @g.create_merge_request(@project.gpid, title, User.current.gid, :description => description, :source_branch => source_branch, :target_branch => target_branch, :target_project_id => target_project_id)
        @fork_project_name = Project.find(@project.forked_from_project_id).try(:name)
        @fork_pr_message = true if @fork_project_name
      else
        request = @g.create_merge_request(@project.gpid, title, User.current.gid, :description => description, :source_branch => source_branch, :target_branch => target_branch)
        respond_to do |format|
          format.js{redirect_to project_pull_request_path(request.id, :project_id => @project.id)}
        end
      end
    rescue Exception => e
      @message = e.message
    end
  end

  def show
    @type = params[:type]
    @request = @g.merge_request(@project.gpid, params[:id])
    @commits = @g.merge_request_commits(@project.gpid, params[:id].to_i)
    @commits_count = @commits.count
    @changes = @g.merge_request_changes(@project.gpid, params[:id]).try(:changes)
    @changes_count = @changes.count
    @comments = @g.merge_request_comments(@project.gpid, params[:id]).reverse
    @comments_count = @comments.count

    @limit = 10
    @is_remote = true
    @count = @comments_count
    @pages = Paginator.new @count, @limit, params['page'] || 1
    @offset ||= @pages.offset
    @comments = paginateHelper @comments, 10
  end

  # Accept a merge request.
  # If merge success you get 200 OK.
  # Accept a merge request.
  #
  # @example
  #   Gitlab.accept_pull_rquest(5, 1)
  #
  # @param  [Integer] project The ID of a project.
  # @param  [Integer] id The ID of a merge request.
  # @return [Gitlab::ObjectifiedHash]
  def accept_pull_request
    begin
      status = @g.accept_merge_rquest(@project.gpid, params[:id], User.current.gid)
      PullRequest.create(:pull_request_id => status.id, :user_id => User.current.id, :gpid => status.project_id)
      respond_to do |format|
        format.js{redirect_to project_pull_request_path(status.id, :project_id => @project.id)}
      end
    rescue Exception => e
      @message = e.message
    end
  end

  # Updates a merge request.
  #
  # @example
  #   Gitlab.update_merge_request(5, 42, :title => 'New title')
  #
  # @param  [Integer] project The ID of a project.
  # @param  [Integer] id The ID of a merge request.
  # @param  [Hash] options A customizable set of options.
  # @option options [String] :title The title of a merge request.
  # @option options [String] :source_branch The source branch name.
  # @option options [String] :target_branch The target branch name.
  # @option options [Integer] :assignee_id The ID of a user to assign merge request.
  # @option options [String] :state_event New state (close|reopen|merge).
  # @return [Gitlab::ObjectifiedHash] Information about updated merge request.
  def update_pull_request
    begin
      @g.update_merge_request(@project.gpid, params[:id], User.current.gid, :state_event => params[:state])
      respond_to do |format|
        format.html{redirect_to project_pull_request_path(params[:id], :project_id => @project.id)}
      end
    rescue Exception => e
      @message = e.message
    end
  end

  # Creates a merge request.
  #
  # @example
  #   Gitlab.create_merge_request(5, 'New merge request',
  #     :source_branch => 'source_branch', :target_branch => 'target_branch')
  #   Gitlab.create_merge_request(5, 'New merge request',
  #     :source_branch => 'source_branch', :target_branch => 'target_branch', :assignee_id => 42)
  def create_pull_request_comment
    content = params[:pull_request_comment]
    begin
      @comments = @g.create_merge_request_comment(@project.gpid, params[:id], content, User.current.gid)
      respond_to do |format|
        format.html{redirect_to project_pull_request_path(params[:id], :project_id => @project.id)}
      end
    rescue Exception => e
      @message = e.message
    end
  end

  # Gets the comments on a merge request.
  #
  # @example
  #   Gitlab.merge_request_comments(5, 1)
  def pull_request_comments
    begin
      @comments = @g.merge_request_comments(@project.gpid, params[:id]).reverse
      @comments_count = @comments.count

      @limit = 10
      @is_remote = true
      @count = @comments_count
      @pages = Paginator.new @count, @limit, params['page'] || 1
      @offset ||= @pages.offset
      @comments = paginateHelper @comments, 10
    rescue Exception => e
      @message = e.message
    end
  end

  # Get a list of merge request commits.
  # Parameters:
  # id (required) - The ID of a project
  # merge_request_id (required) - The ID of MR
  def pull_request_commits
    begin
      @type = params[:type]
      @commits = @g.merge_request_commits(@project.gpid, params[:id])
      @commits_count = @commits.count

      @limit = 10
      @is_remote = true
      @count = @commits_count
      @pages = Paginator.new @count, @limit, params['page'] || 1
      @offset ||= @pages.offset
      @commits = paginateHelper @commits, 10
    rescue Exception => e
      @message = e.message
    end
  end

  # Shows information about the merge request including its files and changes. With GitLab 8.2 the return fields upvotes and downvotes are deprecated and always return 0.
  # Parameters:
  # id (required) - The ID of a project
  # merge_request_id (required) - The ID of MR
  def pull_request_changes
    begin
      @type = params[:type]
      @changes = @g.merge_request_changes(@project.gpid, params[:id]).try(:changes)
      @changes_count = @changes.count

      @limit = 10
      @is_remote = true
      @count = @changes_count
      @pages = Paginator.new @count, @limit, params['page'] || 1
      @offset ||= @pages.offset
      @changes = paginateHelper @changes, 10
    rescue Exception => e
      @message = e.message
    end
  end

  private
  def authorize_logged
    if !User.current.logged?
      redirect_to signin_path
      return
    end
  end

  def connect_gitlab
    @g = Gitlab.client
  end

  def find_project_and_repository
    @project = Project.find(params[:project_id])
    render_404 if @project.gpid.blank?
    @repository = Repository.where(:project_id => @project.id, :type => "Repository::Gitlab")
  rescue ActiveRecord::RecordNotFound
    render_404
  end

end
