#coding=utf-8
class GamesController < ApplicationController
  layout "base_myshixun"
  skip_before_filter :verify_authenticity_token, :only => [:file_update]
  before_filter :find_myshixun, :only => [:index]
  before_filter :find_game, :only => [:show, :game_build, :entry,:next_step, :prev_step,:outputs_show, :file_edit, :file_update, :get_waiting_time, :web_display, :check_test_sets,
                                      :game_status, :change_status, :answer, :minus_score, :refresh_game_list, :reset_original_code, :reset_new_code, :evaluating_choice,
                                      :sync_codes, :myshixun_repair, :system_update, :enter_game, :get_repository_contents, :sync_modify_time, :challenges]
  before_filter :find_repository, :only => [:entry, :file_edit, :file_update, :reset_original_code, :reset_new_code, :html_show, :get_repository_contents]
  before_filter :allowd_manager, :except => [:show]
  # before_filter :allowd_view, :only => [:show]
  before_filter :find__shixun_language, :only => [:entry]
  include ApplicationHelper
  include GamesHelper
  CODES = %W(1 2 3 4 5 6 7 8 9 A B C D E F G H J K L N M O P Q R S T U V W X Y Z)
  require 'open3'

  # 同步更新最新代码
  # 同步完成后,需要更新myshixun的commit_id为实训的commit最新值
  # --------------------------
  # 新思路,有冲突则则重置,没有冲突直接pull
  # identifier为password---
  # --------------------------
  def sync_codes
    g = Gitlab.client
    shixun_tomcat = Redmine::Configuration['shixun_tomcat']
    begin
      shixun_new_commit = g.commits(@myshixun.shixun.try(:gpid)).first.try(:id)
      if @myshixun.commit_id != shixun_new_commit
        if @myshixun.reset_time != @myshixun.shixun.try(:reset_time)
          flag = 2
        else
          flag = 0
        end
      else
        flag = 1
      end
      git_myshixun_url = gitlab_url @myshixun
      login = @myshixun.shixun.try(:git_login)
      # 如果educoder不是当前项目的成员,则需要把educoder设置成管理员,为了便于权限验证
      # REDO:如果用educoder的话,可能其他成员也可以推代码
      educoder_gid = Redmine::Configuration['educoder_gid']
      Gitlab.client.add_team_member(@myshixun.gpid, educoder_gid, 40)
      
      git_shixun_url = gitlab_url @myshixun.shixun
      git_myshixun_url = Base64.urlsafe_encode64(git_myshixun_url)
      git_shixun_url = Base64.urlsafe_encode64(git_shixun_url)
      params = {tpiID: "#{@myshixun.try(:id)}", :tpiGitURL => "#{git_myshixun_url}", :tpmGitURL => "#{git_shixun_url}", :identifier => "xinhu1ji2qu3"}
      uri = "#{shixun_tomcat}/bridge/game/resetTpmRepository"
      res = uri_exec uri, params
      if (res && res['code'] != 0)
        render :json => {:status => -1, :message => "实训云平台繁忙(繁忙等级:95)"}
        return
      end
      shixun_new_commit = g.commits(@myshixun.shixun.try(:gpid)).first.try(:id)
      Rails.logger.info("#######Game -- myshixun")
      @myshixun.update_attributes!(:commit_id => shixun_new_commit, :reset_time => @myshixun.shixun.try(:reset_time))
      if @game.challenge.st == 0 && @game.challenge.path.present?
        paths = @game.challenge.path.split(";")
        paths.each do |path|
          game_code_init @game.id, path.try(:strip)
        end
      end
      render :json => {:status => 1, :message => "success", :path => @game.challenge.path}
    rescue Exception => e
      @message = e.try(:message)
      logger.error(e)
      respond_to do |format|
        format.js
      end
    end
  end

  def enter_game
    if @game.status == 3
      @game.update_attributes(:status => 0, :open_time => Time.now)
      redirect_to myshixun_game_path( @game, :myshixun_id => @myshixun)
    end
  end

  # 出现代码不存在、脚本异常等自动修复
  # 88错误的修复等
  def myshixun_repair
    shixun_tomcat = Redmine::Configuration['shixun_tomcat']
    begin
      git_myshixun_url = gitlab_url @myshixun
      git_myshixun_url = Base64.urlsafe_encode64(git_myshixun_url)
      params = {tpiID: "#{@myshixun.try(:id)}", :tpiGitURL => "#{git_myshixun_url}", :tpmID => "#{@myshixun.shixun.try(:id)}"}
      uri = "#{shixun_tomcat}/bridge/game/solveProblems"
      res = uri_exec uri, params
      if (res && res['code'] != 0)
        @message = "实训云平台繁忙(繁忙等级:96)"
        raise("实训云平台繁忙(繁忙等级:96)")
      end
      respond_to do |format|
        format.js{ redirect_to myshixun_game_path(@game, :myshixun_id => @myshixun)}
      end
    rescue Exception => e
      @message = e.try(:message)
      logger.error(e)
      respond_to do |format|
        format.js
      end
    end
  end

  def index
    @games = @myshixun.games.includes(:challenge)
    @games_count = @games.count
    respond_to do |format|
      format.html
      format.js
    end
  end

  # mushixun的版本库必须创建时就创建
  # 首次进入版本库自动打开文件
  # path:""  && path: @game.path
  # @praise 判断是否点赞
  # @tread 判断是否踩
  # git_repository_url @myshixun, "Myshixun"
  # @st 0 实践任务 1 选择题任务
  # begin表示用户从实训tpm列表点击进入
  def show
    # 该参数是为了判断是否需要加载loading
    @is_subject = params[:is_subject]
    redirect_to "/tasks/#{@game.identifier}"
    return

    # 验证版本库
    gitUrl = gitlab_url @myshixun
    gitUrl = Base64.urlsafe_encode64(gitUrl)
    shixun_tomcat = Redmine::Configuration['shixun_tomcat']
    params = {:tpiID => "#{@myshixun.id}", :tpiGitURL  => "#{gitUrl}"}
    # 监测版本库HEAD是否存在,不存在则取最新的HEAD
    uri = "#{shixun_tomcat}/bridge/game/check"
    res = uri_exec uri, params
    if (res && res['code'] != 0)
      logger.error("Verify the repository exception")
    end
    # end
    @is_subject = params[:is_subject]
    # 防止页面ajax数据还没获取就关闭
    @game.update_attribute(:status, 0) if @game.status == 1
    @game_challenge = @game.challenge
    @position = @game_challenge.position
    @challenges = Challenge.where(:shixun_id => @myshixun.shixun_id).includes(:games).where("games.user_id = #{@myshixun.user_id}")
    @shixun = @myshixun.shixun
    # 判断tpm是否修改了
    @tpm_modified = repository_is_modified(@myshixun, @shixun.try(:gpid))
    unless (@shixun.modify_time.blank? || @myshixun.modify_time.blank? || @shixun.reset_time.blank? || @myshixun.reset_time.blank?)
      @tpm_script_modified = (@shixun.reset_time > @myshixun.reset_time  ? true : false)
    end
    if (@game_challenge.modify_time.present? || @game.modify_time.present?)
      @tpm_cases_modified = (@game_challenge.modify_time != @game.modify_time ? true : false)
    end
    # end
    @praise_count = PraiseTread.where(:praise_tread_object_id => @game_challenge.id, :praise_tread_object_type => "Challenge", :praise_or_tread => 1).count
    @tread_count  = PraiseTread.where(:praise_tread_object_id => @game_challenge.id, :praise_tread_object_type => "Challenge", :praise_or_tread => 0).count
    # st:判断是选择类型还是实训类型
    @st = @game_challenge.st
    @had_done = @game.had_done
    @praise = PraiseTread.where("praise_tread_object_id=? and praise_tread_object_type=? and praise_or_tread=? and user_id=?", @game_challenge.id, @game_challenge.class.to_s, 1, User.current.id).first
    @tread = PraiseTread.where("praise_tread_object_id=? and praise_tread_object_type=? and praise_or_tread=? and user_id=?", @game_challenge.id, @game_challenge.class.to_s, 0, User.current.id).first
    @rev = @rev.nil? ? "master" : @rev
    @type = @_params['type']
    challenge_path = @game_challenge.path
    @discusses_count = @shixun.discusses.count
    @arr_path = challenge_path.present? ? challenge_path.split(";") : []
    # 默认打开文件
    logger.info("repository id is #{@repository.try(:id)}, repository's shixun_id =#{@repository.try(:myshixun_id)} shixun_id =#{@repository.try(:shixun_id)}, project_id => #{@repository.try(:project_id)}")
    # 验证challenge文件名的合法性
    # 获取文件content内容,如果内容不存在则说明是目录,否则则认为是文件
    if (@g.files(@myshixun.gpid, @path, @rev).try(:message).present? && !@path.present? && @_params['type'] != "root" )
      @path = @arr_path.reject(&:blank?)[0].try(:strip) # 多文件(以';'形式隔开),默认打开第一个文件
      file_content = @g.files(@myshixun.gpid, @path, @rev).content
      if file_content.blank?
        # gitlab缺陷:forked完成,短暂时间内取不了内容的,所以做一个小轮询,间隔0.1秒
        # 超过2秒则失败,需通过页面刷新
        for i in 0..20 do
          sleep(0.1)
          file_content = @g.files(@myshixun.gpid, @path, @rev).content
          unless file_content.blank?
            logger.info("start: file_content is####{file_content.first(6)}")
            break
          end
        end
      end
      @content = tran_base64_decode64(file_content)
    end

    if @content.nil? || @_params['type'] == "root"
      @entries = @repository.entries(@path, @rev)
    end
    # 页面前后端分离数据转换
    # test_sets = @game_challenge.test_sets
    max_query_index = @game.outputs.first.try(:query_index)
    if max_query_index.present?
      test_sets = TestSet.find_by_sql("SELECT o.actual_output, o.result, o.test_set_position, o.query_index,t.is_public,t.input, t.output, g.id as game_id, c.id as challenge_id FROM outputs o,games g ,challenges c,test_sets t where
                                  g.id=#{@game.id} and o.query_index=#{max_query_index} and g.id = o.game_id and c.id= g.challenge_id and t.challenge_id = c.id and t.position =o.test_set_position order by o.query_index
                                ")
    else
      test_sets = TestSet.find_by_sql("SELECT t.is_public,t.input, t.output,t.position FROM games g ,challenges c,test_sets t where
                                  g.id=#{@game.id} and c.id= g.challenge_id and t.challenge_id = c.id
                                ")
    end
    unless test_sets.blank?
      @test_sets = test_set_static_data(test_sets)
    end

    @test_sets_count = test_sets.count
    @test_sets_hidden_count = test_sets.blank? ? 0 :test_sets.select{|test_set| test_set.is_public == false}.count
    @test_sets_public_count = @test_sets_count - @test_sets_hidden_count
    had_test = Output.where(:game_id => @game.id, :query_index => (@game.query_index - 1))
    @had_test_count = had_test.count
    @had_passed_testsests_error_count = had_test.blank? ? 0 : had_test.select{|had_test| had_test.result == false}.count
    @had_passed_testsests_error_count = @had_test_count - @had_passed_testsests_error_count
    @had_passed_testsests_hidden_count = had_test.blank? ? 0 : had_test.select{|had_test| had_test.result == true && had_test.is_public == false}.count
    @had_passed_testsests_public_count = had_test.blank? ? 0 : had_test.select{|had_test| had_test.result == true && had_test.is_public == true}.count
    @mirror_name = @myshixun.mirror_name
    @final_score = ((@shixun.status <= 1)  ? 0 : @game.final_score.to_i)
    if @myshixun.shixun.status <= 1 || (@game.final_score != 0 && @game.answer_open > 0)
      @gold = 0
    else
      if @game.answer_open > 0 && @game.final_score ==0
        @gold = -@game_challenge.score.to_i
      else
        @gold =  @game.final_score.to_i
      end
    end
    #@gold = @myshixun.shixun.status <= 1 ? 0 : ((@game.answer_open? && @game.final_score == 0 && @game.status == 2) ? -@game_challenge.score.to_i : @game.final_score.to_i)
    @had_done = @game.had_done
    @language = @game_challenge.shixun.language
    @mirror_name = @myshixun.mirror_name
    error_position = had_test.blank? ? nil : had_test.select{|had_test| had_test.result == false}.last
    logger.info("latest output id is #{error_position.id unless error_position.blank?}")
    @latest_output = error_position.try(:out_put).gsub(/\n/, '<br/>').gsub(/\t/, '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;').to_json unless error_position.try(:out_put).blank?
    logger.info(@latest_output)
    @power = (User.current.manager_of_shixun?(@shixun) || (User.current.try(:professional_certification) && User.current.user_extensions.try(:identity) == 0) || @game.test_sets_view ) ? true : false
    @record = EvaluateRecord.where(:game_id => @game.id).first.try(:consume_time)
    respond_to do |format|
      format.html
      format.js
    end
  rescue Exception => e
    logger.error("game error##############{e.message}")
    flash[:error] = e.message
  end

  def get_repository_contents
    @rev = @rev.nil? ? "master" : @rev
    @path = params[:path].try(:strip) # 多文件(以';'形式隔开),默认打开第一个文件
    file_content = @g.files(@myshixun.gpid, @path, @rev).content
    @content = tran_base64_decode64(file_content)
  end

  # 代码预览
  def entry
    # entry_and_raw(false)
    @arr_path = @game.challenge.path.split(";")
    file_content = @g.files(@myshixun.gpid, @path, @rev).content
    @content =tran_base64_decode64(file_content)
    # @content = @repository.cat(@path, @rev)
  end

  def file_edit
    # entry_and_raw(false)
    # @content = @repository.cat(@path, @rev).strip
    # # respond_to do |format|
    # #   format.js
    # end
  end

  def sync_modify_time
    @game.update_column(:modify_time, @game.challenge.try(:modify_time))
    # return {:status => 1, :message => "success"}
    render :json => {:status => 1, :message => "success"}
  end

  def file_update
   # render :json => {:success => "success", :resubmit => '11111'}
    logger.info("file_update start#1**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
    ActiveRecord::Base.transaction do
      if params[:evaluate].present?
        # 创建评测记录
        record = EvaluateRecord.create!(:user_id => User.current.id, :shixun_id => @myshixun.shixun.id, :game_id => @game.id)
        logger.info("file_update start#2**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
        # @myshixun.student_works.update_all(:update_time => Time.now) if !@myshixun.student_works.blank?

        student_work_time = format("%.3f",  (Time.now.to_f - record.created_at.to_f)).to_f
        record.update_attributes!(:student_work => student_work_time)
      end
      logger.info("file_update start#3**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
      @g = Gitlab.client
      last_content = @g.files(@myshixun.gpid, @path, "master").try(:content)
      logger.info("file_update start#4**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
      last_content = tran_base64_decode64(last_content)
      content =  if (@myshixun.mirror_name.include?('Python2.7') || @myshixun.mirror_name.include?('Python3.6') || @myshixun.mirror_name.include?('MachineLearning')) && params[:content].present?
                   params[:content].gsub(/\t/, '    ')
                 else
                   params[:content]
                 end
      logger.info("file_update start#5**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
      if content != last_content
        code_file = @g.edit_file(@myshixun.gpid, User.current.login, :content => content, :file_path => @path, :branch_name => @rev, :commit_message => "shixun exec")
      end
      if record.present?
        consume_time = format("%.3f",  (Time.now.to_f - record.created_at.to_f)).to_f
        record.update_attributes!(:file_update => consume_time)
      end
      logger.info("file_update start#6**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
      # status为2说明是重新评测
      if @game.status == 2
        code = CODES.sample(8).join
        resubmit = "#{code}_#{@myshixun.id}"
      end
      if content != last_content && code_file.blank?
        raise("update file failed")
      else
        render :json => {:success => "success", :resubmit => resubmit}
      end
    end
  rescue Exception => e
    render :json => {:success => "fail", :contents => "实训云平台繁忙(繁忙等级:81),请稍后刷新并重试", :position => @game.challenge.position, :had_done => @game.had_done}
  end

  # json调用,显示左边的隐藏具体详情@game 字段 msg
  # 刷新右边的输出结果 @game out_put
  def outputs_show
    @output = Output.find(params[:game_output_id])
    respond_to do |format|
      format.js
    end
  end

  # 获取评测的等待的时间
  # res['waitNum'] 评测等待人数
  # res['waitingTime'] 评测等待时间
  # res['ableToCreate']  0 表示在等待中 1 表示可执行 -1 表示超过最大等待人数
  def get_waiting_time
    shixun_tomcat = Redmine::Configuration['shixun_tomcat']
    uri = "#{shixun_tomcat}/bridge/game/getWaitingTime"
    params = {:tpiID => "#{@myshixun.id}", :first => @_params[:first].to_i}
    res = uri_exec uri, params
    logger.info("############ res: #{res}")
    if (res && res['code'] != 0)
      @message = "实训云平台繁忙(繁忙等级:94)"
      raise("实训云平台繁忙(繁忙等级:94)")
    end
    logger.info("########### get_waiting_time: #{params}")
    logger.info("########### ableToCreate : #{res['ableToCreate']}")

    render :json => {:result => "success", :ableToCreate => res['ableToCreate'], :waitNum => res['waitNum'], :waitingTime => res['waitingTime'], :position => @game.challenge.position}
    #render :json => {:result => "success", :ableToCreate => 1, :waitNum => 10, :waitingTime => 1324 }
  rescue Exception => e
    render :json => {:result => "fail", :contents => '实训云平台繁忙(繁忙等级:94),请稍后刷新并重试', :position => @game.challenge.position}
  end

  # status 0: 未提交测评或者提交测评失败后报错;1:中间状态还没返回值;2:返回值并成功
  # resubmit 唯一随机码,为了区分每一次重新评测结果
  def game_build
    #render :json => {:result => "success", :ableToCreate => 1, :waitNum => 13, :port => 41222 }
    # 更新时间是为了TPM端显示的更新,退出实训及访问实训的时候会更新
    logger.info("game_build start#1**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
    @myshixun.update_column(:updated_at, Time.now)
    game_challenge = @game.challenge
    shixun = @myshixun.shixun
    gitUrl = gitlab_url @myshixun
    gitUrl = Base64.urlsafe_encode64(gitUrl)
    taskId = @game.id
    #code = CODES.sample(8).join
    # status为2说明是重新评测
    if @game.status == 2
      resubmit = @_params[:resubmit]
    else
      # 重新评测不影响已通关的实训状态
      if @_params[:first].to_i == 1
        @game.update_attributes!(:status => 1)
      end
    end
    shixun_tomcat = Redmine::Configuration['shixun_tomcat']
    step = game_challenge.try(:position)
    logger.info("game_build start#2**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
    testSet = []
    game_challenge.test_sets.each do |test_set|
      input = test_set.input.nil? ? "" : test_set.input.gsub("\r\n", "\n")
      output = test_set.output.nil? ? "" : test_set.output.gsub("\r\n", "\n")
      test_cases = {:input => input, :output => output}
      testSet << test_cases
    end
    logger.info("game_build start#3**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
    testCases = Base64.urlsafe_encode64(testSet.to_json) unless testSet.blank?
    mirror_repository = shixun.mirror_repositories.where(:main_type => 1).first
    resource_limit = "echo 'ulimit -f #{mirror_repository.resource_limit}' >> /root/.bashrc  ; source /root/.bashrc\n"
    tpmScript = shixun.evaluate_script.nil? ? "" : Base64.urlsafe_encode64((resource_limit + shixun.evaluate_script).gsub("\r\n", "\n"))
    # 注意:这个地方的参数写的时候不能换行
    params = {:tpiID => "#{@myshixun.id}", :tpiGitURL  => "#{gitUrl}", :buildID => "#{taskId}",:instanceChallenge  => "#{step}",
              :testCases => "#{testCases}", :resubmit => "#{resubmit}", :times => @_params[:first].to_i, :podType => shixun.webssh,
              :containers => "#{Base64.urlsafe_encode64(container_limit(shixun.mirror_repositories))}", :tpmScript => "#{tpmScript}",
              :timeLimit => "#{shixun.main_mirror.try(:time_limit)}"}
    # 评测有文件输出的需要特殊传字段 path:表示文件存储的位置
    params['file'] = Base64.urlsafe_encode64({:path => "#{game_challenge.picture_path}"}.to_json) if game_challenge.picture_path.present?
    # needPortMapping: web类型需要pod端口映射
    params[:needPortMapping] = 8080 if @myshixun.mirror_name.include?("Web")
    # uri = URI("#{shixun_tomcat}/bridge/game/gameEvaluate")
    logger.info("game_build start#4**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
    uri = "#{shixun_tomcat}/bridge/game/gameEvaluate"
    res = uri_exec uri, params
    if (res && res['code'] != 0)
      @message = "实训云平台繁忙(繁忙等级:86)"
      raise("实训云平台繁忙(繁忙等级:86)")
    end
    logger.info("game_build start#5****** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
    render :json => {:result => "success", :resubmit => resubmit, :ableToCreate => res['ableToCreate'], :waitNum => res['waitNum'], :waitingTime => res['waitingTime'], :position => @game.challenge.position, :port => res['port'], :had_done => @game.had_done }
    logger.info("game_build start#6****** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
  rescue Exception => e
    if resubmit.nil?
      @game.update_attributes!(:status => 0)
    end
    logger.error("###################" + e.message)
    render :json => {:result => 'fail',  :contents =>"实训云平台繁忙(繁忙等级:86),请稍后刷新并重试", :position => game_challenge.position, :had_done => @game.had_done}
  end


  # @myshixun -status 1:完成实训
  # 全部通关奖励1000分
  # retry_status 评测的唯一标识,重新评测对以前已产生的结果不造成影响
  # params[:resubmit] 不为空表示已通过该关后重新评测, 重新评测必须是通过该关后才能执行
  # @had_done 1 通关所有关
  # port: PHP/Web会有端口号,其他语言返回-1
  # params[:time_out] 超时
  def game_status
    logger.info("game_status start#1**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
    if (params[:time_out] == "false") && ((params[:resubmit].blank? && @game.status != 2 && @game.status != 0) || (params[:resubmit].present? && (params[:resubmit] != @game.resubmit_identifier)))
      render :json => {:status => 1}
      return
    end
    game_challenge = @game.challenge
    had_done = @game.had_done
    resubmit_identifier = @game.resubmit_identifier
    shixun = @myshixun.shixun
    port = params[:port]
    score = 0
    user_gold = 0 #用户奖励金币
    tag_count = 0
    logger.info("##### resubmit_identifier is #{resubmit_identifier}")
    logger.info("game_status start#2**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
    if params[:resubmit].blank?   # 非重新评测
      # 通过当前一关
      if @game.status == 2
        if !@game.answer_open && shixun.status > 1
          score = game_challenge.score
          user_gold = game_challenge.score
          tag_count = game_challenge.challenge_tags.count
        elsif shixun.status > 1 && @game.answer_open
          score = -game_challenge.score.to_i
          tag_count = 0
        else
          score = "+0"
          tag_count = 0
        end
      end
      game_status = @game.status
    else     # 重新评测
      if params[:resubmit] == resubmit_identifier     # 本次重新评测结果已经返回并存入数据库
        game_status = (@game.retry_status == 2 ? 2 : 0)    # retry_status 2:成功 1: 失败
        if game_status == 2 && had_done == 1  # 重新评测如果评测成功
          had_done =1
        else
          had_done = 0
        end
      else
        # game_status 在前端有行为判断,2表示通关;0表示失败;1表示评测中的中间状态
        game_status = 1
        had_done = 0
      end
    end
    logger.info("game_status start#3**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
    max_query_index = @game.outputs.first.try(:query_index)
    if max_query_index.present?
      test_sets = TestSet.find_by_sql("SELECT o.actual_output, o.result, o.test_set_position, o.query_index,t.is_public,t.input, t.output, g.id as game_id, c.id as challenge_id FROM outputs o,games g ,challenges c,test_sets t where
                                  g.id=#{@game.id} and o.query_index=#{max_query_index} and g.id = o.game_id and c.id= g.challenge_id and t.challenge_id = c.id and t.position =o.test_set_position order by o.query_index
                                ")
    else
      test_sets = TestSet.find_by_sql("SELECT t.is_public,t.input, t.output,t.position FROM games g ,challenges c,test_sets t where
                                  g.id=#{@game.id} and c.id= g.challenge_id and t.challenge_id = c.id
                                ")
    end
    logger.info("game_status start#4**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
    unless test_sets.blank?
      total_test_sets = test_set_static_data(test_sets)
    end
    logger.info("#################################{@public_test_sets}")
    @test_sets_count = test_sets.count
    @test_sets_hidden_count = test_sets.blank? ? 0 :test_sets.select{|test_set| test_set.is_public == false}.count
    @test_sets_public_count = @test_sets_count - @test_sets_hidden_count
    had_test = Output.where(:game_id => @game.id, :query_index => (@game.query_index - 1))
    @had_test_count = had_test.count
    @had_passed_testsests_error_count = had_test.blank? ? 0 : had_test.select{|had_test| had_test.result == false}.count
    @had_passed_testsests_error_count = @had_test_count - @had_passed_testsests_error_count
    @had_passed_testsests_hidden_count = had_test.blank? ? 0 : had_test.select{|had_test| had_test.result == true && had_test.is_public == false}.count
    @had_passed_testsests_public_count = had_test.blank? ? 0 : had_test.select{|had_test| had_test.result == true && had_test.is_public == true}.count
    @final_score = (( shixun.try(:status).to_i <= 1) ? 0 : @game.try(:final_score).to_i)
    picture = (@game.picture_path.nil? ? 0 : @game.id)
    if @myshixun.shixun.try(:status) <= 1 || (@game.try(:final_score).to_i != 0 && @game.answer_open?)
      @gold = 0
    else
      if @game.answer_open? && @game.try(:final_score).to_i ==0
        @gold = -game_challenge.try(:score).to_i
      else
        @gold =  @game.try(:final_score).to_i
      end
    end
    #@gold = @myshixun.shixun.status <= 1 ? 0 : (@game.answer_open? && @game.final_score.to_i == 0 && @game.status == 2 ? -game_challenge.score.to_i : @game.final_score.to_i)
    error_position = had_test.blank? ? nil : had_test.select{|had_test| had_test.result == false}.last
    @latest_output = error_position.try(:out_put).gsub(/\n/, '<br/>').gsub(/\t/, '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;') unless error_position.try(:out_put).blank?
    logger.info("@compile_success###################{@compile_success}")
    @language = game_challenge.shixun.language
    @mirror_name = @myshixun.mirror_name
    power = (User.current.manager_of_shixun?(shixun) || (User.current.try(:professional_certification) && User.current.user_extensions.try(:identity) == 0)) ? true : false
    logger.info("game_status start#5**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
    # 更新用户时间
    if game_status == 0 || game_status == 2
      record = EvaluateRecord.where(:game_id => @game.id).first
      if record
        front_js = format("%.3f",  (Time.now.to_f - record.try(:updated_at).to_f)).to_f
        consume_time = format("%.3f", (Time.now - record.created_at)).to_f
        record.update_attributes(:consume_time => consume_time, :front_js => front_js)
      end
    end
    # 记录前端总耗时
    record = EvaluateRecord.where(:game_id => @game.id).first.try(:consume_time)
    logger.info("game_status start#6**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
    render :json => {test_sets: total_test_sets,
                     test_sets_count: @test_sets_count,
                     test_sets_hidden_count: @test_sets_hidden_count,
                     test_sets_public_count: @test_sets_public_count,
                     had_test_count: @had_test_count,
                     had_passed_testsests_error_count: @had_passed_testsests_error_count,
                     had_passed_testsests_hidden_count: @had_passed_testsests_hidden_count,
                     had_passed_testsests_public_count: @had_passed_testsests_public_count,
                     final_score: @final_score,
                     gold: @gold,
                     latest_output: @latest_output,
                     status: game_status,
                     had_done: had_done,
                     language: @language,
                     score: score,
                     user_gold: user_gold,
                     tag_count: tag_count,
                     position: game_challenge.position,
                     port: port,
                     power: power,
                     record:record,
                     mirror_name:@mirror_name,
                     picture:picture
    }
  end

  # 选择题评测(选择题不需要重新评测)
  # score 获得金币数 tag_count 技能数 right用户是否全对 answer_right全部选择题的正确性
  def evaluating_choice
    @game_challenge = @game.challenge
    @challenges = Challenge.where(:shixun_id => @myshixun.shixun_id)
    @shixun = @myshixun.shixun
    score = 0
    tag_count = 0
    @right = true
    answer_right = []
    @game_challenge.challenge_chooses.each_with_index do |choose, index|
      correct = (params[:answer][index] == choose.standard_answer) ? true : false
      Output.create(:game_id => @game.id, :test_set_position => choose.position, :actual_output =>  params[:answer][index], :result => correct, :query_index => @game.query_index)
      if @shixun.status > 1 && !@game.answer_open
        if correct
          score += choose.score
          tag_count += choose.challenge_tags.count
        end
      elsif @shixun.status > 1 && @game.answer_open
        score -= choose.score
      end
      unless correct
        @right = false
      end
      answer_right << correct
    end
    @had_done = @game.had_done
    if @right && @game.status != 2
      @game.update_attributes(:status => 2, :end_time => Time.now)
      # 选择题最后一关,更新status
      if @had_done
        @myshixun.update_attribute(:status, 1)
      end
      if @shixun.status > 1 && !@game.answer_open
        reward_grade(@game.user, @game.id, 'Game', @game_challenge.choose_score)
        reward_experience(@game.user, @game.id, 'Game', @game_challenge.choose_score)
        @game.update_attribute(:final_score,  @game_challenge.choose_score)
      end
    end
    respond_to do |format|
      format.js{redirect_to myshixun_game_path(@game, :myshixun_id => @myshixun, :choose => @right)}
    end
  end


  def change_status
    @game.update_attribute(:status, 0)
    outputs = @game.outputs
    if outputs.count == 0
      outputs = ""
    else
      outputs = outputs.map{|result| [result.code, result.id]}
    end
    render :json => {status: @game.status, output: "服务器网络异常", results: outputs, had_done: 0}
  end

  # 获取等待的任务数
  # 如果没有等待任务页面上将不显示
  # msg: -1 不存在等待的任务
  # 如果该方法异常则直接返回0,跳过等待
  def waiting_info
    begin
      shixun_tomcat = Redmine::Configuration['shixun_tomcat']
      params = {:buildID => "#{@game.id}"}
      uri = URI("#{shixun_tomcat}/jenkins-exec/api/getWaitingTime")
      res = uri_exec uri, params
      if (res && res['code'] != 0)
        raise("获取等待任务数异常")
      end
      task_count = res['msg'].to_i
      task_count > 0 ? task_count : 0
      render :json => {task_count: task_count}
    rescue
      render :json => {task_count: 0}
    end
  end

  # 自动推送下一个任务
  # 从waiting_time发的请求则有type
  def next_step
    #unless show_next_stage?(@game, @myshixun.shixun.try(:status))
    #  render_403
    #end

    next_game = @game.next_game
    next_game.update_attributes(:status => 0, :open_time => Time.now) if next_game.status == 3
    respond_to do |format|
      format.js{ redirect_to myshixun_game_path(next_game, :myshixun_id => @myshixun)}
      format.html{redirect_to myshixun_game_path(next_game, :myshixun_id => @myshixun)}
    end
  end

  def prev_step
    prev_game = @game.prev_game
    respond_to do |format|
      format.js{ redirect_to myshixun_game_path(prev_game, :myshixun_id => @myshixun)}
      format.html{ redirect_to myshixun_game_path(prev_game, :myshixun_id => @myshixun)}
    end
  end

  # 获取答案,第一次查看需扣掉该关卡的积分
  # 如果已看过,下次可以免费查看
  # viewed 1: 直接查看 2:弹框提示将要扣除积分,确定后显示内容 3:弹框提示分数不够
  def answer
    challenge = @game.challenge
    @challenge_score = challenge.score.to_i
    @answer = ""
    # 已经开启过
    @score = User.current.grade.to_i - @challenge_score
    if(params[:choose] == "true")
      challenge.challenge_chooses.each_with_index do |choose, index|
        @answer += "第"+ ((index + 1).to_s) +"题:<br />"
        @answer += (choose.answer.blank? ? choose.standard_answer : choose.answer)
        @answer += "<br /><br /><br />"
      end
    else
      @answer = challenge.answer
    end

    if challenge.shixun.status < 2 || User.current.manager_of_shixun?(challenge.shixun) || @game.answer_open || (challenge.st != 0 && @game.status == 2)
      @viewed = 1
    else
      if @score >= 0
        @viewed = 2
      else
        @viewed = 3
      end
    end
    respond_to do |format|
      format.js
      format.html
    end
  end

  # web渲染
  def web_display
    path = @game.challenge.path.strip
    port = (50000 + @game.myshixun_id).to_s
    # 测试
    #path = "src/step1/Helloworld.php"
    #port = (50000+4116).to_s
    @url = "http://106.75.96.108:" + port + '/' + path

    respond_to do |format|
      format.html{render :layout => false}
    end
  end

  def minus_score
    @game_challenge = @game.challenge
    @position = @game_challenge.position
    user = User.current
    challenge_score = @game_challenge.score.to_i
    @answer = ""
    if @game.challenge.st == 0
      @answer = @game_challenge.answer
    else
      @game_challenge.challenge_chooses.each_with_index do |choose, index|
        @answer += "第"+ ((index + 1).to_s) +"题:<br />"
        @answer += (choose.answer.blank? ? choose.standard_answer : choose.answer)
        @answer += "<br /><br /><br />"
      end
    end
    unless @game.answer_open
      # 最终得分可能是负分
      final_score = @game.final_score - challenge_score
      @game.update_attributes!(:answer_open => true, :final_score => final_score)
      # 积分消耗情况统计
      reward_grade(user, @game.id, 'Answer', -challenge_score)
      @grades = final_score
    end
  end

  def refresh_game_list
    myshixun_id = params[:myshixun_id]
    @myshixun = Myshixun.find_by_identifier(myshixun_id)
    # @challenges = Challenge.where(:shixun_id => @myshixun.shixun_id)
    @challenges = Challenge.where(:shixun_id => @myshixun.shixun_id).includes(:games).where("games.user_id = #{@myshixun.user_id}")

    respond_to do |format|
      format.js
    end
  end

  def check_test_sets
    user_grade = User.current.grade
    @minus_grade = @game.challenge.score * 5
    if user_grade >= @minus_grade
      User.current.update_attribute(:grade, user_grade - @minus_grade)
      @game.update_attribute(:test_sets_view, true)
      # 扣分记录
      Grade.create(:user_id => User.current.id, :container_id => @game.id, :score => -@minus_grade, :container_type => "testSet")
      respond_to do |format|
        format.js{redirect_to myshixun_game_path(@game, :myshixun_id => @myshixun, :test_sets_view => true)}
      end
    else
      respond_to do |format|
        format.js
      end
    end
  end

  def reset_original_code
    @g = Gitlab.client
    begin
      @shixun = @myshixun.shixun
      @path = params[:path].try(:strip)
      game_code = GameCode.where(:game_id => @game.id, :path => @path).first
      GameCode.create(:game_id => @game.id, :path => @path) if game_code.blank?
      content = game_code.try(:original_code)
      @arr_path = @game.challenge.path.split(";")
      @rev = @rev.nil? ? "master" : @rev
      content = @g.files(@shixun.gpid, @path, @rev).try(:content)
      content = tran_base64_decode64(content)
      update_gitlab_file(content, @path, @rev, "file reset")
      file_content = @g.files(@myshixun.gpid, @path, @rev).content
      @content = tran_base64_decode64(file_content)
      if @content.nil?
        raise("初始代码为空,代码重置失败")
      end
    rescue Exception => e
      @error_messages = e.message
    end
      respond_to do |format|
        format.js
      end
    end

  def system_update
    @myshixun.update_attribute(:system_tip, true)
    render :json => {:status => 1, :message => "success"}
  end

  def reset_new_code
    begin
      @shixun = @myshixun.shixun
      @g = Gitlab.client
      @arr_path = params[:path]
      @path = @arr_path[0].try(:strip)
      @rev = @rev.nil? ? "master" : @rev
      message = "file reset"
      @arr_path.each do |path|
        game_code = GameCode.where(:game_id => @game.id, :path => path).first
      content = game_code.try(:new_code)
      if content.nil?
        raise("示例代码为空,代码重置失败")
      end
        update_gitlab_file(content, path, @rev, message)
      end
      file_content = @g.files(@myshixun.gpid, @path, @rev).content
      @content = tran_base64_decode64(file_content)
      if @content.nil?
        raise("示例代码为空,代码重置失败")
        # @entries = @repository.entries(@path, @rev)
      end
      respond_to do |format|
        format.js
      end
    rescue Exception => e
      @error_messages = e.message
    end
  end

  private
  def update_gitlab_file content, path, rev, message
    code_file = @g.edit_file(@myshixun.gpid, User.current.login, :content => content, :file_path => path, :branch_name => rev, :commit_message => "#{message}")
    if code_file.nil?
      raise("网络异常,文件更新失败")
    end
  end

  def test_set_static_data test_sets
    test_result = []
    unless test_sets.blank?
      test_sets.each do |test_set|
        actual_output = test_set.attributes.count > 4 ? test_set.try(:actual_output) : nil
        result = test_set.attributes.count > 4 ? test_set.try(:result) : nil
        #actual_output = Base64.encode64(actual_output)
        compile_success =  (actual_output.blank? || actual_output.downcase.match(/error/).present?) ? 0 : 1
        public_result = {:is_public => (test_set.is_public ? 1 : 0), :result => result, :input => test_set.input,
                         :actual_output => actual_output, :output => test_set.output, :compile_success => compile_success}
        test_result << public_result.to_json
      end
    end
    test_result = test_result.blank? ? test_result : test_result.join(",")
    return test_result.gsub(/<\/script>/, '<//script>')
  end

  def entry_and_raw(is_raw)
    @entry = @repository.entry(@path, @rev)
    (show_error_not_found; return) unless @entry

    # If the entry is a dir, show the browser
    (show; return) if @entry.is_dir?

    @content = @repository.cat(@path, @rev)
    (show_error_not_found; return) unless @content
    if is_raw || (@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) || !is_entry_text_data?(@content, @path)
      # Force the download
      send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) }
      send_type = Redmine::MimeType.of(@path)
      send_opt[:type] = send_type.to_s if send_type
      send_opt[:disposition] = (Redmine::MimeType.is_type?('image', @path) && !is_raw ? 'inline' : 'attachment')
      send_data @content, send_opt
    else
      # Prevent empty lines when displaying a file with Windows style eol
      # TODO: UTF-16
      # Is this needs? AttachmentsController reads file simply.
      @content.gsub!("\r\n", "\n")
      @changeset = @repository.find_changeset_by_name(@rev)
    end
  end

  def is_entry_text_data?(ent, path)
    # UTF-16 contains "\x00".
    # It is very strict that file contains less than 30% of ascii symbols
    # in non Western Europe.
    return true if Redmine::MimeType.is_type?('text', path)
    # Ruby 1.8.6 has a bug of integer divisions.
    # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
    return false if ent.is_binary_data?
    true
  end

  def find_repository
    @repository = @myshixun.repository
    render_404 if @myshixun.gpid.nil?
    @path = params[:path].is_a?(Array) ? params[:path].join('/') : params[:path].to_s
    @g = Gitlab.client
    @g_project = @g.project(@myshixun.gpid)
    @g_default_branch = @g_project.default_branch
    # gitlab端获取默认分支
    @rev = params[:rev].blank? ? @g_default_branch : params[:rev].to_s.strip
  rescue ActiveRecord::RecordNotFound
    render_404
  end

  def allowd_manager
    render_403 unless (User.current.manager_of_myshixun?(@myshixun) || User.current.admin? || User.current.id == @myshixun.shixun.try(:user_id))
  end

  # 判断成员是否允许查看
  def allowd_view
    if @myshixun.shixun.try(:status) == 2 && @game.status == 3 && User.current.id != @myshixun.shixun.try(:user_id)
      render_403
    end
    # render_403 if (@game.status == 3 && User.current.id != @myshixun.shixun.try(:user_id))
  end

  def find__shixun_language
    language = @myshixun.shixun.try(:language)
    @language = language_switch(language)
  end

  # Find myshixun of id params[:id]
  def find_myshixun
    myshixun_id = params[:myshixun_id] || (params[:game] && params[:game][:myshixun_id])
    @myshixun = Myshixun.find_by_identifier(myshixun_id)
    if @myshixun.nil?
      render_404
      return
    end
  rescue ActiveRecord::RecordNotFound
    render_404
  end

  def find_game
    # myshixun_id = params[:myshixun_id]
    @game = Game.find_by_identifier(params[:id])
    if @game.nil?
      render_404
      return
    end
    @myshixun = @game.myshixun
  rescue ActiveRecord::RecordNotFound
    render_404
  end
end