# encoding: utf-8
class ChallengesController < ApplicationController
  layout "base_shixun"
  before_filter :check_authentication, :except => [:index]
  before_filter :find_shixun, :only => [:index, :new, :create, :destroy, :challenge_build, :update_evaluation, :add_choose_question, :new_choose_question,
                                          :choose_type_show, :edit_choose_question, :update_choose_question, :destroy_challenge_choose]
  before_filter :find_challenge, :only => [:show, :edit, :update, :challenge_build, :index_up, :index_down, :destroy, :update_evaluation, :add_choose_question,
                                           :show_choose_question, :create_choose_question, :create_choice_question, :new_choose_question, :choose_type_show, :edit_choose_question, :update_choose_question, :destroy_challenge_choose]
  before_filter :build_challege_from_params, :only => [:new, :create]
  before_filter :tpi_manager_allowed, :only => [:challenge_build, :destroy, :edit, :new, :create]
  before_filter :allowed_view, :only => [:show]
  before_filter :query_challeges, :only => [:show, :edit, :update, :update_evaluation]
  skip_before_filter :verify_authenticity_token, :only => [:create_choose_question, :update_choose_question]
  #before_filter :find_shixun_language, :only => [:show, :new, :edit]
  before_filter :base_index, :only => [:index, :index_down, :index_up, :destroy]
  before_filter :view_allow, :only => [:show]

  include ApplicationHelper

  ##{
  # @url: 判断新建与编辑提交的url}
  def new
    # 顶部导航
    @challenge = Challenge.new
    @st = params[:st].to_i
    @challenge.st = @st
    @url = shixun_challenges_path(@shixun, :st => @st)
    @method = "post"
    @project_menu_type = 11
    @task_pass_sample =  PlatformSample.where(:samples_type => 'taskPass').first.try(:contents)
    respond_to do |format|
      format.html { render :action => 'new', :layout => 'base_shixun' }
    end
  end

  def create
    ActiveRecord::Base.transaction do
      begin
        challenge_count = @shixun.challenges.count
        @challenge = Challenge.new(params[:challenge])
        @challenge.position = challenge_count + 1
        @challenge.shixun = @shixun
        @challenge.user = User.current
        @challenge.st = params[:st].to_i
        @challenge.modify_time = Time.now

        # 实训是否需要重启
        # 非实践任务创建第一个阶段时调用 publishGame, 避免不包含实践任务的实训进行模拟实战时报错
        shixun_modify_status_without_publish(@shixun, 1) if @challenge.position != 1
        @challenge.save!
        if params[:challenge_tag].present?
          params[:challenge_tag].each do |input|
            ChallengeTag.create!(:name => input, :challenge_id => @challenge.id)
          end
        end
        redirect_to shixun_challenge_path(@challenge, :shixun_id => @shixun)
      rescue Exception => e
        flash[:error] = "#{e.message}"
        redirect_to new_shixun_challenge_path(:shixun_id => @shixun)
        raise ActiveRecord::Rollback
      end
    end
  end

  # 处理新建challenge返回的pipeline片段
  def fragment_from_jenkins

  end

  def index
    base_index
    respond_to do |format|
      format.js
      format.html
    end
  rescue ActiveRecord::RecordNotFound
    render_404
  end

  def show
    @tab = params[:tab].nil? ? 1 : params[:tab].to_i
    challenge_num = Challenge.where(:shixun_id => @shixun).count
    challenge_pos = @challenge.position
    if challenge_pos < challenge_num
      @next_challenge = Challenge.where(:shixun_id => @shixun, :position => challenge_pos + 1).first
    end
    @prev_challenge = Challenge.where(:shixun_id => @shixun, :position => challenge_pos - 1).first if challenge_pos - 1 > 0
    respond_to do |format|
      format.html
      format.js
    end
  end

  ##{
  # @action: 判断新建与编辑提交的url}
  def edit
    @tab = params[:tab].blank? ? 1 : params[:tab].to_i
    @url = shixun_challenge_path(@challenge, :shixun_id => @shixun, :tab => @tab)
    @method= "put"
    respond_to do |format|
      format.html
      format.js
    end
  end

  def update
    ActiveRecord::Base.transaction do
      tab = params[:tab].to_i
      @challenge.update_attributes(params[:challenge])
      if tab == 1
        @challenge.challenge_tags.delete_all
        if params[:challenge_tag].present?
          params[:challenge_tag].each do |input|
            ChallengeTag.create!(:name => input, :challenge_id => @challenge.id)
          end
        end
      elsif tab == 2
        path = @challenge.path
        exec_path = @challenge.exec_path
        sets_output = @test_sets.map(&:output)
        sets_input = @test_sets.map(&:input)
        sets_open = @test_sets.map(&:is_public)
        params_hidden = params[:test_set][:hidden].map{|hidden| hidden.to_i == 0}
        # 测试集变化则需要更新(输入、 输出、 是否隐藏)
        if sets_output != params[:test_set][:output] || sets_open != params_hidden || sets_input != params[:test_set][:input]
          @test_sets.delete_all unless @test_sets.blank?
          if params[:test_set][:hidden].length > 0
            params[:test_set][:input].each_with_index do |input, index|
              unless (input[index] == params[:test_set][:output][index] && input[index].nil?)
                TestSet.create(:challenge_id => @challenge.id, :input => "#{input}", :output => "#{params[:test_set][:output][index]}", :is_public => params_hidden[index], :position => (index + 1))
              end
            end
          end
          @challenge.update_column(:modify_time, Time.now)
          # 测试集的
          @shixun.myshixuns.update_all(:system_tip => 0)
        end
        # 关卡评测执行文件如果被修改,需要修改脚本内容
        script = modify_shixun_script @shixun, @shixun.evaluate_script
        @shixun.update_column(:evaluate_script, script)
        if path != params[:challenge][:path]
          shixun_modify_status_without_publish(@shixun, 1)
        end
        Attachment.attach_files(@challenge, params[:attachments])
      end
      redirect_to shixun_challenge_path(@challenge, :shixun_id => @shixun, :tab => tab)
    end
  end

  def new_choose_question
    @challenge_choose = ChallengeChoose.new
    @url = "#{create_choose_question_shixun_challenge_path(@challenge, :shixun_id => @shixun)}"
    respond_to do |format|
      format.js
    end
  end

  def create_choose_question
    ActiveRecord::Base.transaction do
      begin
        @challenge_choose = ChallengeChoose.new
        @challenge_choose.challenge_id = @challenge.id
        @challenge_choose.subject = params[:choose][:subject]
        @challenge_choose.answer = params[:choose][:answer]
        @challenge_choose.standard_answer = params[:standard_answer]
        @challenge_choose.score  = params[:challenge][:score].to_i
        @challenge_choose.difficult = params[:challenge][:difficulty].to_i
        @challenge_choose.position = @challenge.challenge_chooses.count + 1
        @challenge_choose.category = @challenge_choose.standard_answer.length == 1 ? 1 : 2

        if @challenge_choose.save!
          # 创建选项
          params[:question][:cnt].each_with_index do |test, index|
            answer = params[:choice][:answer][index] == "0" ? false : true
            ChallengeQuestion.create(:option_name => test, :challenge_choose_id => @challenge_choose.id, :position => index, :right_key => answer)
          end
          # 创建单选多选的技能标签
          if params[:challenge_tag].present?
            params[:challenge_tag].each do |tag|
              ChallengeTag.create(:name => tag, :challenge_choose_id => @challenge_choose.id, :challenge_id => @challenge.id)
            end
          end
        end
      rescue Exception => e
        flash[:error] = "#{e.message}"
        raise ActiveRecord::Rollback
      end
    end
  end

  def show_choose_question
    @challenge_choose = ChallengeChoose.find params[:choose_id]

    respond_to do |format|
      format.js
    end
  end

  def update_choose_question
    @challenge_choose = ChallengeChoose.where(:id => params[:choose_id]).first
    ActiveRecord::Base.transaction do
      if params[:standard_answer] != @challenge_choose.standard_answer
        @challenge.update_column(:modify_time, Time.now)
      end
      category = params[:standard_answer].length > 1 ? 2 : 1
      score = params[:challenge] ? params[:challenge][:score].to_i : @challenge_choose.score
      difficult = params[:challenge] ? params[:challenge][:difficulty].to_i : @challenge_choose.difficult
      @challenge_choose.update_attributes(:subject => params[:choose][:subject],
                                          :answer => params[:choose][:answer],
                                          :standard_answer => params[:standard_answer],
                                          :score => score,
                                          :difficult => difficult,
                                          :category => category)
      begin
        @challenge_choose.challenge_questions.delete_all
        params[:question][:cnt].each_with_index do |test, index|
          answer = params[:choice][:answer][index] == "0" ? false : true
          ChallengeQuestion.create(:option_name => test, :challenge_choose_id => @challenge_choose.id, :position => index, :right_key => answer)
        end
        @challenge_choose.challenge_tags.delete_all unless @challenge_choose.challenge_tags.blank?
        if params[:challenge_tag].present?
          params[:challenge_tag].each do |tag|
            ChallengeTag.create(:name => tag, :challenge_choose_id => @challenge_choose.id, :challenge_id => @challenge.id)
          end
        end
        @challenge_choose = ChallengeChoose.find params[:choose_id]
      rescue Exception => e
        flash[:error] = "#{e.message}"
        raise ActiveRecord::Rollback
      end
    end
  end

  def edit_choose_question
    @challenge_choose = ChallengeChoose.find params[:choose_id]
    @url = "#{update_choose_question_shixun_challenge_path(@challenge, :shixun_id => @shixun, :choose_id => params[:choose_id])}"
    respond_to do |format|
      format.js
    end
  end

  def choose_type_show
    @challenge_choose = ChallengeChoose.where(:id => params[:choose_id]).first
    @index = params[:index].to_i
    respond_to do |format|
      format.js
    end
  end

  def destroy_challenge_choose
    ActiveRecord::Base.transaction do
      @challenge_choose = ChallengeChoose.where(:id => params[:choose_id]).first
      pos = @challenge_choose.position
      @challenge.challenge_chooses.where("position > ?", pos).update_all("position = position - 1")
      @challenge_choose.destroy
      # 发起重置请求
      shixun_modify_status_without_publish(@shixun, 1)
      redirect_to shixun_challenge_path(@challenge, :shixun_id => @shixun)
    end
  end

  def add_choose_question
    @category = params[:category].to_i
    @position = params[:position].to_i
    #@challenge_choose = @challenge.challenge_chooses
    respond_to do |format|
        format.js
    end
  end

  def destroy
    next_challenges = @shixun.challenges.where("position > #{@challenge.position}")
    next_challenges.update_all("position = position - 1")
    shixun_modify_status_without_publish(@shixun, 1)
    @challenge.destroy
    # 关卡位置被删除,需要修改脚本
    script = modify_shixun_script @shixun, @shixun.evaluate_script
    @shixun.update_column(:evaluate_script, script)

    base_index
    respond_to do |format|
      format.js
      format.html{redirect_to shixun_challenges_path(@shixun)}
    end
  end


  def update_evaluation
    ActiveRecord::Base.transaction do
      path = @challenge.path
      exec_path = @challenge.exec_path
      @challenge.update_attributes(params[:challenge])
      begin
        if params[:tab].to_i == 2
          sets_output = @test_sets.map(&:output)
          sets_input = @test_sets.map(&:input)
          sets_open = @test_sets.map(&:is_public)
          params_hidden = params[:test_set][:hidden].map{|hidden| hidden.to_i == 0}
          # 测试集变化则需要更新(输入、 输出、 是否隐藏)
          if sets_output != params[:test_set][:output] || sets_open != params_hidden || sets_input != params[:test_set][:input]
            @test_sets.delete_all unless @test_sets.blank?
            if params[:test_set][:hidden].length > 0
              params[:test_set][:input].each_with_index do |input, index|
                unless (input[index] == params[:test_set][:output][index] && input[index].nil?)
                  TestSet.create(:challenge_id => @challenge.id, :input => input, :output => params[:test_set][:output][index], :is_public => params_hidden[index], :position => (index + 1))
                end
              end
            end
            @challenge.update_column(:modify_time, Time.now)
            # 测试集的
            @shixun.myshixuns.update_all(:system_tip => 0)
          end

          # 关卡评测执行文件如果被修改,需要修改脚本内容
          if exec_path != params[:challenge][:exec_path]
            script = modify_shixun_script @shixun, @shixun.evaluate_script
            @shixun.update_column(:evaluate_script, script)
          end

          # 学员任务文件路径更新不需要重置
          # if path != params[:challenge][:path]
          #   shixun_modify_status_without_publish(@shixun, 1)
          # end

          Attachment.attach_files(@challenge, params[:attachments])
        elsif params[:tab].to_i == 5
          @challenge_tags.delete_all unless @challenge_tags.blank?
          unless params[:knowledge].blank?
            params[:knowledge][:input].each do |input|
              ChallengeTag.create!(:name => input, :challenge_id => @challenge.id)
            end
          end
        end
        if params[:tab].to_i == 5
          respond_to do |format|
            format.js{redirect_to edit_shixun_challenge_path(@challenge, :shixun_id => @shixun, :tab => params[:tab])}
          end
        else
          redirect_to edit_shixun_challenge_path(@challenge, :shixun_id => @shixun, :tab => params[:tab])
        end
      rescue Exception => e
        flash[:error] = "#{e.message}"
        redirect_to edit_shixun_challenge_path(@challenge, :shixun_id => @shixun, :tab => params[:tab])
        raise ActiveRecord::Rollback
      end
    end
  end

  def index_down
    next_challenge = @challenge.next_challenge
    position = @challenge.position
    @challenge.update_attribute(:position, (position + 1))
    next_challenge.update_attribute(:position, next_challenge.position - 1)
    # 关卡位置被修改,需要修改脚本
    script = modify_shixun_script @shixun, @shixun.evaluate_script
    @shixun.update_column(:evaluate_script, script)

    base_index
  end

  def index_up
    position = @challenge.position
    last_challenge = @challenge.last_challenge
    @challenge.update_attribute(:position, (position - 1))
    last_challenge.update_attribute(:position, last_challenge.position + 1)
    # 关卡位置被修改,需要修改脚本
    script = modify_shixun_script @shixun, @shixun.evaluate_script
    @shixun.update_column(:evaluate_script, script)

    base_index
  end

  # build job 只负责发送请求
  def challenge_build
    gitUrl = gitlab_url@shixun
    gitUrl = Base64.urlsafe_encode64(gitUrl)
    taskId = params[:id]
    jobName = @shixun.forked_form
    step = @challenge.position
    jenkins_shixuns = Redmine::Configuration['jenkins_shixuns']
    if @challenge.status == 0
      params = {:jobName => "#{jobName}", :taskId => "#{taskId}", :step => "#{step}",  :gitUrl => "#{gitUrl}"}
      uri = URI("#{jenkins_shixuns}/jenkins-exec/api/buildJob")
      res = uri_exec uri, params
      # @challenge.update_attribute(:status, 1)
    end
    respond_to do |format|
      format.js
    end
  end

  private
  # 过滤掉对指定单位公开的用户(超级管理员和实训管理者除外)
  def view_allow
    shixun_view_allow @shixun
  end

  def count_input input, output
    if input.length == 0 && output.length == 0
      result = 0
    else
      if input.length > output.length

      end
    end
  end

  def tpi_manager_allowed
     unless User.current.manager_of_shixun?(@shixun)
       render_403
     end
  end

  def allowed_view
    unless (allow_to_view_challenge(@challenge, @shixun) || User.current.manager_of_shixun?(@shixun))
      render_403
    end
  end

  def build_challege_from_params
    if params[:id].blank?
      @challenge = Challenge.new
      @challenge.shixun = @shixun
      if params[:st].to_i == 0
        @challenge.st = 1
      end
    else
      @challenge = @shixun.challenges.find(params[:id])
    end

    @challenge.shixun = @shixun
    @challenge.user ||= User.current
  end

  def query_challeges
    @test_sets = @challenge.test_sets
    @challenge_tags = @challenge.challenge_tags
  end

  # index/index_down/index_up/destroy等方法公共部分
  def base_index
    @manager = User.current.manager_of_shixun?(@shixun)
    # 当前用户开启的实训
    @current_myshixun = @shixun.myshixuns.where(:user_id => User.current).first
    if @current_myshixun.present?
      @challenges = Challenge.select([:id, :subject, :user_id, :shixun_id, :position, :st, :score]).where(:shixun_id => @shixun)
      @current_modify = ShixunModify.where(:myshixun_id => @current_myshixun.id, :shixun_id => @shixun.try(:id), :status => 1).first
    else
      @challenges = @shixun.challenges
    end
  end

  def find_challenge
    @challenge = Challenge.find(params[:id])
    @shixun = @challenge.shixun
  rescue ActiveRecord::RecordNotFound
    render_404
  end

  # Find project of id params[:id]
  def find_shixun
    shixun_id = params[:shixun_id] || (params[:challenge] && params[:challenge][:shixun_id])
    @shixun = Shixun.find_by_identifier(shixun_id)
    if @shixun.nil?
      render_404
      return
    else
      if (@shixun.status == 0 && !User.current.manager_of_shixun?(@shixun)) || @shixun.status == -1
        render_403
        return
      end
    end
  rescue ActiveRecord::RecordNotFound
    render_404
  end

  def find_shixun_language
    language = @shixun.language
    @language = language_switch language
  end

  def default_format_js
    response.headers['content--type'] = 'text/javascript'
    request.format = 'js'
  end
end