# encoding=utf-8
class GamesService
  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)

  # 关卡详情
  def show_game params, current_user
    game = Game.min.find_by_identifier(params[:identifier])
    Rails.logger.info("game id is #{game.try(:id)}, current_user id is #{current_user.try(:id)}")
    if game.blank? || current_user.blank?
      return{:status => 404}
    end
    # 防止评测中途ajax被取消;3改成0是为了处理首次进入下一关的问题
    game.update_attribute(:status, 0) if game.status == 1
    game.update_attributes(:status => 0, :open_time => Time.now) if game.status == 3 # Redo:后续可以去掉,只是为了兼顾其它模块的耗时统计

    myshixun = Myshixun.min.find(game.myshixun_id)
    shixun = Shixun.min.find(myshixun.shixun_id)
    unless ((myshixun.user_id == current_user.id || current_user.business? || current_user.id == shixun.try(:user_id) ||
        current_user.is_certification_teacher) && (shixun.operable?)) || current_user.admin?
      Rails.logger.info("######403???")
      return{:status => 403}
    end
    game_challenge = Challenge.min.find(game.challenge_id)

    has_answer = game_challenge.answer.blank? ? false : true
    game_challenge.answer = nil
    if game_challenge.st == 1
      game_challenge.score = game_challenge.choose_score.to_i
    end
    # st:判断是选择类型还是实训类型
    st = game_challenge.st
    game_count = myshixun.games.count
    discusses_count = (current_user.admin? ? shixun.discusses.count :
                          shixun.discusses.where("hidden = false or user_id = :user_id", user_id: current_user.id).count)
    mirror_name = myshixun.mirror_name
    user = myshixun.owner
    username = user.show_name
    image_url = url_to_avatar(user)
    user_url = "/users/#{user.login}"
    is_teacher = (user.user_extensions.identity == 0)
    tpm_identifier = shixun.try(:identifier)
    # 实训超时设置
    time_limit = shixun.exec_time

    # 高性能取上一关、下一关
    prev_game = Game.prev_identifier(shixun.id, game.myshixun_id, game_challenge.position)
    next_game = if shixun.vnc || current_user.is_certification_teacher || shixun_manager(shixun, current_user) || game.status || shixun.task_pass
                  Game.next_game(shixun.id, game.myshixun_id, game_challenge.position).try(:identifier)
                end

    # 该参数是为了判断是否需要加载loading
    @is_subject = params[:is_subject]

    # 关卡点赞数, praise_or_tread = 1则表示赞过
    praise_count = PraiseTread.where(:praise_tread_object_id => game_challenge.id, :praise_tread_object_type => "Challenge", :praise_or_tread => 1).count
    user_praise = PraiseTread.where(:praise_tread_object_id => game_challenge.id, :praise_tread_object_type => "Challenge", :user_id => current_user.id, :praise_or_tread => 1).present? ? true : false

    # 实训的最大评测次数,这个值是为了优化查询,每次只取最新的最新一次评测的结果集
    max_query_index = game.query_index - 1
    # 判断实训是否全部通关
    had_done = game.had_done
    # 统计时间
    record = EvaluateRecord.where(:game_id => game.id).first.try(:consume_time)
    # 实训制作者当前拥有的金币
    grade = myshixun.owner.try(:grade)

    # power判断用户是否有权限查看隐藏测试集(TPM管理员;平台认证的老师;花费金币查看者) -1 表示不能解锁 0 表示需要付费解锁 1表示可以看
    # myshixun_manager
    myshixun_manager = shixun_manager(shixun, current_user) || (current_user.is_certification_teacher)
    power = (myshixun_manager || game.test_sets_view ) ? 1 : (shixun.test_set_permission ? 0 : -1)

    # 选择题和编程题公共部分
    container = {:st => st, :discusses_count => discusses_count, :game_count => game_count, :myshixun => myshixun.try(:attributes),
                 :challenge => game_challenge.try(:attributes), :game => game.try(:attributes), :shixun => shixun.try(:attributes),
                 :record => record, :grade => grade, :prev_game => prev_game, :next_game => next_game, :username => username,
                 :image_url => image_url, :user_url => user_url, :praise_count => praise_count, :user_praise => user_praise, :time_limit => time_limit,
                 :tomcat_url  => Redmine::Configuration['tomcat_php'], :is_teacher => is_teacher, :power => power, :myshixun_manager => myshixun_manager}
    if shixun.vnc
      begin
        shixun_tomcat = Redmine::Configuration['shixun_tomcat']
        service_host = Redmine::Configuration['vnc_url']
        uri = "#{shixun_tomcat}/bridge/vnc/getvnc"
        params = {tpiID: myshixun.id, :containers => "#{Base64.urlsafe_encode64(container_limit(shixun.mirror_repositories))}"}
        res = uri_exec uri, params
        if res && res['code'].to_i != 0
          raise("实训云平台繁忙(繁忙等级:99)")
        end
        url = "https://#{res['port']}.#{service_host}/vnc_lite.html?password=headless"
        Rails.logger.info("66666666sssssss#{url}")
        container = container.merge(:vnc_url => url)
        Rails.logger.info("777777666sssssss#{container}")
      rescue Exception => e
        Rails.logger.error(e.message)
      end
    end

    if st == 0 && shixun.status == 2 && myshixun_manager
      zip_path = Gitlab.endpoint.to_s + "/projects/" + myshixun.gpid.to_s + "/repository/archive?&private_token=" + Gitlab.private_token.to_s
      container = container.merge(:zip_path => zip_path)
    end

    # 区分选择题和编程题,st:0编程题;
    if st == 0
      gitUrl = gitlab_url myshixun
      gitUrl = Base64.urlsafe_encode64(gitUrl)
      shixun_tomcat = Redmine::Configuration['shixun_tomcat']
      params = {:tpiID => "#{myshixun.id}", :tpiGitURL  => "#{gitUrl}"}

      # 判断tpm是否修改了
      tpm_modified = repository_is_modified(myshixun, shixun.try(:gpid)) # 判断TPM和TPI的版本库是否被改了
      tpm_cases_modified = (game_challenge.modify_time != game.modify_time ? true : false)  # modify_time 决定TPM测试集是否有更新
      # tpm_script_modified = (shixun.reset_time > myshixun.reset_time  ? true : false) # 新结构脚本是实时传送的,所以不会影响

      # 区分评测过未评测过,未评测过按需求取数据
      sql =
          if max_query_index > 0
            "SELECT
              b.code, b.actual_output, b.out_put, b.result, b.compile_success, a.is_public, a.input, a.output
            FROM
              (SELECT position, input, output, challenge_id, is_public FROM test_sets where challenge_id=#{game_challenge.id}) a
            LEFT JOIN
              (SELECT
                 result, test_set_position, g.challenge_id, o.actual_output, o.out_put, o.compile_success, o.code
               FROM
                 outputs o left join games g on g.id=o.game_id
               WHERE
                 game_id=#{game.id} and query_index = #{max_query_index}
              ) b
            ON
              b.challenge_id  = a.challenge_id and b.test_set_position = a.position"
          else
            # 这个地方如果加字段的话一定注意test_set_static_data方法,因为这个地方的字段数在下面有判断
            "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
      qurey_test_sets = TestSet.find_by_sql(sql)

      # 测试集统计及处理
      unless qurey_test_sets.blank?
        check_power = (power == 1 || game.test_sets_view)
        test_sets = test_set_static_data(qurey_test_sets, check_power)
      end
      test_sets_count = qurey_test_sets.size
      had_test = Output.where(:game_id => game.id, :query_index => max_query_index)
      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

      error_position = had_test.blank? ? nil : had_test.select{|had_test| had_test.result == false}.last
      Rails.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\;") unless error_position.try(:out_put).blank?
      Rails.logger.warn(latest_output)

      output_hash = {:test_sets => test_sets}.merge(:had_test_count => had_test_count, :test_sets_count => test_sets_count,
                                                    :had_passed_testsests_error_count => had_passed_testsests_error_count)
      multi_webssh = shixun.webssh == 2 && shixun.multi_webssh
      result = {:tpm_modified => tpm_modified, :tpm_cases_modified => tpm_cases_modified, :hide_code => shixun.hide_code, :forbid_copy => shixun.forbid_copy,
                :output_sets => output_hash, :latest_output => latest_output, :mirror_name => mirror_name, :multi_webssh => multi_webssh,
                :has_answer => has_answer}.merge(container)
    else # 选择题类型的
      # 该方法多个地方调用,比如show、评测
      # 最后一个字段true表示只显示数据,false表示可能有添加数据
      result_container = choose_container(game_challenge, game, max_query_index, true)
      return result_container.merge(container)
    end
  end

  # output为testset的实际输出
  # out_put为顶端结果显示输出 power 查看测试集的权限
  def test_set_static_data test_sets, power
    test_result = []
    unless test_sets.blank?
      test_sets.each do |test_set|
        # 第一次刷新或者没有评测的的时候test_set只需取四个字段,所以取了count
        actual_output = test_set.attributes.count > 4 ? test_set.try(:actual_output) : nil
        result = test_set.attributes.count > 4 ? test_set.try(:result) : nil
        compile_success = test_set.attributes.count > 4 ? test_set.try(:compile_success) : nil
        status = test_set.attributes.count > 4 ? test_set.try(:code) : nil
        #actual_output = Base64.encode64(actual_output)

        actual_output = (compile_success.to_s == "0" && status.to_s == "-1" ? "编译失败,请在测试结果中查看具体的错误信息" : actual_output)

        public_result = {:is_public => (test_set.is_public ? 1 : 0), :result => result,
                         :actual_output => actual_output, :compile_success => compile_success}
        # 测试集公开的话才返回input结果
        (test_set.is_public || power) && public_result.merge!({:input => test_set.input, :output => test_set.output})
        Rails.logger.info("#######################test_set: #{public_result}")
        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

  #  获取TPI关卡内容
  def challenges params
    result = []
    myshixun = Myshixun.find(Game.where(:identifier => params[:identifier]).pluck(:myshixun_id).first)
    shixun = Shixun.select([:id, :status]).find(myshixun.shixun_id)
    games = myshixun.games.includes(:challenge).reorder("challenges.position")
    games.each do |game|
      game_status = game.try(:status)
      challenge = game.challenge
      if challenge.st == 0 # 实战类型
        if game_status == 2  # 通关了则取实际得分,没通关则取总分
          gold = (shixun.status <= 1) ? 0 : game.final_score.to_i
          # 只要过关了,查看了答案经验值就是0,金币是负数
          experience = (shixun.status <= 1 || game.final_score.to_i < 0) ? 0 : challenge.score.to_i
          challenge_tags_count = (shixun.status <= 1) ? 0 : challenge.challenge_tags.count
        else
          gold = challenge.score.to_i
          experience = gold
          challenge_tags_count = challenge.challenge_tags.count
        end
      else
        if game_status == 2
          gold = (shixun.status <= 1) ? 0 : game.final_score.to_i
          experience = (shixun.status <= 1 || game.final_score.to_i < 0) ? 0 : challenge.choose_score.to_i
          challenge_tags_count = (shixun.status <= 1 || game.final_score.to_i <= 0) ? 0 : challenge.choose_tags_num
        else
          # 选择题只有在全对的时候才会获取final score总分,错任何一个题final_score就为0
          gold = challenge.choose_score.to_i
          experience = challenge.choose_score.to_i
          challenge_tags_count = challenge.choose_tags_num
        end
      end
      result << {:position => challenge.position, :subject => challenge.subject, :tag_count => challenge_tags_count, :gold => gold,
                 :experience => experience, :status => game.status, :star => game.star, :identifier => game.identifier}
    end
    result
  end

  # 评论打星星
  def star params, current_user
    game = Game.find_by_identifier(params[:identifier])
    shixun = Shixun.select([:id, :status]).find(params[:shixun_id])
    # 如果已经评星,则不能重复评
    grade = Grade.where(:user_id => current_user.id, :container_id => game.id, :container_type => 'Star').first
    if grade.present?
      return{:reward_code => -1}
    else
      game.update_column(:star, params[:star].to_i)
      # 随机生成10-100金币
      code = rand(10..100)
      # 积分消耗情况记录;加积分之针对已发布的实训
      if shixun.status >= 2
        reward_grade(current_user, game.id, 'Star', code)
        return{:reward_code => code}
      else
        return{:reward_code => 0}
      end
    end
  end

  # TPI版本库文件目录结构
  def entries params
    g = Gitlab.client
    gpid = params[:gpid]
    path = params[:path].try(:strip)
    rev = params[:rev] ? params[:rev] : "master"
    result = []
    trees = g.trees(gpid, path: path, rev: rev)
    trees.each do |tree|
      # 去掉第一行的"/"
      new_path = File.join(path,tree.name).reverse.chomp("/").reverse
      result << {:name => tree.name, :path => new_path, :kind => tree.type == 'tree' ? 'dir' : 'file'}
    end

    return result
  end

  def answer params, current_user
    game_base params[:identifier]
    challenge = Challenge.select([:answer, :id, :score, :st]).find(@game.challenge_id)
    is_teacher = (current_user.user_extensions.identity == 0)
    is_certification_teacher = current_user.is_certification_teacher
    # 这几种情况可以直接查看答案的:实训未发布;当前用户为实训管理员;已经查看过答案;平台认证的老师;
    if (@shixun.status < 2 || shixun_manager(@shixun, current_user) || @game.answer_open == 1 || is_certification_teacher)
      Rails.logger.info("answer#{params[:identifier]}#### user is #{current_user.id}, status is #{@shixun.status}, manager is #{shixun_manager(@shixun, current_user)}, open #{@game.answer_open}, cer #{is_certification_teacher}")
      if challenge.st == 0
        result = challenge.try(:answer)
      else
        result = []
        challenge.challenge_chooses.each do |choose|
          result << {:position => choose.position, :answer => (choose.answer.blank? ? choose.standard_answer : choose.answer)}
        end
      end
      return {:view_answer => true, :answer => result}
    else
      return {:is_teacher => is_teacher, :view_answer => false}
      # view_answer = false
    end
  end

  # 查看答案需要扣取金币
  # 必须保证用户的金币数大于关卡的金币数
  def answer_grade params, current_user
    game_base params[:identifier]
    challenge = Challenge.select([:answer, :id, :score, :st]).find(@game.challenge_id)
    challenge_score = challenge.try(:score)
    final_score = @game.final_score
    if current_user.grade.to_i - challenge_score > 0
      if @game.answer_open == 0 # 如果这是第一次查看答案
        if challenge.st == 0
          final_score = final_score - challenge_score
          # 积分消耗情况记录
          reward_grade(current_user, @game.id, 'Answer', -challenge_score)
        else
          final_score = final_score - challenge.choose_score.to_i
          # 之所以不用final_score是因为过关后查看答案的final_score为0,但是记录需要记录扣除的分数
          reward_grade(current_user, @game.id, 'Answer', -challenge.choose_score.to_i)
        end
        @game.update_attributes!(:answer_open => true, :final_score => final_score)
      end
    else
      # 金币不足
      raise("0")
    end
    if challenge.st == 0
      answer = challenge.try(:answer)
    else
      answer = []
      challenge.challenge_chooses.each do |choose|
        answer << {:position => choose.position, :answer => (choose.answer.blank? ? choose.standard_answer : choose.answer)}
      end
    end

    return {:answer => answer, :final_score => final_score, :grade => @myshixun.owner.try(:grade)}
  end

  # 查看隐藏测试集
  def check_test_sets params, current_user
    game = Game.select([:id, :challenge_id, :test_sets_view]).find_by_identifier(params[:identifier])
    if game.test_sets_view == true
      return {:status => -1, :message => "已解锁,请误重复操作!"}
    end
    challenge = Challenge.select([:id, :score]).find(game.challenge_id)
    user_grade = current_user.grade
    minus_grade = challenge.score * 5
    max_query_index = game.query_index - 1
    # 区分评测过未评测过,未评测过按需求取数据
    if max_query_index > 0
      qurey_test_sets = TestSet.find_by_sql("SELECT o.code, o.actual_output, o.out_put, o.result, o.compile_success, 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
      qurey_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
    test_sets = test_set_static_data(qurey_test_sets, true)
    if user_grade >= minus_grade
      current_user.update_attribute(:grade, user_grade - minus_grade)
      game.update_attribute(:test_sets_view, true)
      # 扣分记录
      gardes = Grade.create(:user_id => current_user.id, :container_id => game.id, :score => -minus_grade, :container_type => "testSet")
      gardes.attributes.merge!({test_sets: test_sets})
    else
      return {:status => -1, :message => "本操作需要扣除#{ minus_grade }金币,您的金币不够了"}
    end
  end

  # 文件更新;数据评测记录
  # 生成重新评测认证码
  # content_modified:0 表示文件没有更新;content_modified:1 表示文件有更新
  def file_update params, current_user
    game_base params[:identifier]
    path = params[:path].strip unless params[:path].blank?
    rev = params[:rev] ? params[:rev] : "master"
    content_modified = 0
    ActiveRecord::Base.transaction do

      # params[:evaluate] 实训评测时更新必须给的参数,需要依据该参数做性能统计,其它类型的更新可以跳过
      # 自动保存的时候evaluate为0;点评测的时候为1
      if params[:evaluate] == 1
        sec_key = generates_identifier(EvaluateRecord, 10)
        record = EvaluateRecord.create!(:user_id => current_user.id, :shixun_id => @myshixun.shixun.id,
                                        :game_id => @game.id, :identifier => sec_key)
        Rails.logger.warn("##game is is #{@game.id}, record id is #{record.id}, time is**** #{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

      @g = Gitlab.client
      last_content = @g.files(@myshixun.gpid, path, "master").try(:content)

      last_content = tran_base64_decode64(last_content)
      content =  if @myshixun.mirror_name.select{|a| a.include?("MachineLearning") || a.include?("Python")}.present? && params[:content].present?
                   params[:content].gsub(/\t/, '    ')
                 else
                   params[:content]
                 end
      if content != last_content
        content_modified = 1
        code_file = @g.edit_file(@myshixun.gpid, current_user.login, :content => content, :file_path => path, :branch_name => "master",
                                 :commit_message => (params[:evaluate] == 1 ? "commit by author" : "auto commit" ))
      end
      # REDO:是否有读写分离的问题
      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

      # 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
        return {:success => "success", :resubmit => resubmit ,:content_modified => content_modified, sec_key: record.try(:identifier)}
      end
    end
  rescue Exception => e
    Rails.logger.error("file update failed #{e.message}")
    return {:status => -1, :success => "fail", :message => "实训云平台繁忙(繁忙等级:81),请稍后刷新并重试", :position => @game.challenge.position, :had_done => @game.had_done}
  end

  # 恢复初始代码
  # 注意path为当前打开文件的path
  def reset_original_code params, current_user
    g = Gitlab.client
    path = params[:path]
    begin
      file_base params[:identifier]
      shixun = Shixun.select(:gpid).find(@myshixun.shixun_id)
      content = g.files(shixun.gpid, path, "master").try(:content)
      content = tran_base64_decode64(content)
      g.edit_file(@myshixun.gpid, current_user.login, :content => content, :file_path => path, :branch_name => "master",
                  :commit_message => "reset_original_code")
      if content.nil?
        raise("初始代码为空,代码重置失败")
      end
      return content
    rescue Exception => e
      raise("#{e.message}")
    end
  end

  def reset_passed_code params, current_user
    g = Gitlab.client
    path = params[:path]
    game= Game.select([:id, :myshixun_id]).where(:identifier => params[:identifier]).first
    myshixun = Myshixun.find(game.myshixun_id)
    game_code = GameCode.where(:game_id => game.try(:id), :path => path).first
    if game_code.present?
      content = game_code.try(:new_code)
      content =  if myshixun.mirror_name.select{|a| a.include?("MachineLearning") || a.include?("Python")}.present? && content.present?
                   content.gsub(/\t/, '    ')
                 else
                   content
                 end
      g.edit_file(myshixun.try(:gpid), current_user.login, :content => content, :file_path => path, :branch_name => "master", :commit_message => "game passed reset")
      return content
    else
      return {:status => -1, :message => "重置失败,代码为空"}
    end
  end

  # 获取版本库文件内容
  # 通过版本库的默认分支可以判断版本库是否正常
  # 注:如果本身path传错,内容肯定也为空;fork成功后,可能短时间内也获取不到版本库内容
  # status =0 表示获取默认打开的内容,1表示右侧目录结构中获取的内容
  def rep_content params, current_user
    file_base params[:identifier]
    # current_user: fork不应该是用当前用户去fork
    current_user = @myshixun.owner
    g = Gitlab.client
    gpid = @myshixun.try(:gpid)
    path = @game.challenge.try(:path).split(";")[0].strip()
    path = params[:path] ? params[:path] : path
    shixun_gpid = params[:shixun_gpid]
    status = params[:status]
    path = path.try(:strip)
    rev = params[:rev] ? params[:rev] : "master"
    Rails.logger.warn("path is #{path}")
    content = g.files(gpid, path, rev).try(:content)

    if content.blank?
      # 监测版本库HEAD是否存在,不存在则取最新的HEAD
      gitUrl = gitlab_url @myshixun
      gitUrl = Base64.urlsafe_encode64(gitUrl)
      shixun_tomcat = Redmine::Configuration['shixun_tomcat']
      rep_params = {:tpiID => "#{@myshixun.id}", :tpiGitURL  => "#{gitUrl}"}
      # 监测版本库HEAD是否存在,不存在则取最新的HEAD
      uri = "#{shixun_tomcat}/bridge/game/check"
      res = uri_exec uri, rep_params
      # res值:0 表示正常;-1表示有错误;-2表示代码版本库没了
      if (status == 0 && res && res['code'] == -2 && params[:retry].to_i == 1)
        # 没有版本库则删除现有的版本库关联,重新fork一个版本库
        g = Gitlab.client
        if current_user.gid.nil?
          s = Trustie::Gitlab::Sync.new
          s.sync_user(current_user)
        end
        gpid = sync_gitlab_rep @myshixun, shixun_gpid, current_user.try(:gid)
        content = g.files(gpid, path, rev).content
      else
        if (res && res['code'] != 0)
          Rails.logger.error("get rep_content failed: bridge return !0")
          # raise(status)
          return nil
        end
      end


      # gitlab缺陷:forked完成,短暂时间内取不了内容的,所以做一个小轮询,间隔0.2秒
      # 超过3秒则失败,需通过页面刷新
      # for i in 0..15 do
      #   sleep(0.2)
      #   content = g.files(gpid, path, rev).content
      #   break if content.present?
      # end
    end

    content = tran_base64_decode64(content) if content.present?
    return content
  end


  # 编程题评测
  def game_build params
    # 三类实训只取基础部分数据
    game = Game.select([:myshixun_id, :status, :challenge_id, :id, :evaluate_count]).find_by_identifier(params[:identifier])
    myshixun = Myshixun.select([:updated_at, :gpid, :id, :shixun_id]).find(game.myshixun_id)
    shixun = Shixun.select([:id, :evaluate_script, :webssh, :exec_time, :sigle_training, :identifier, :status]).find(myshixun.shixun_id)
    game_challenge = Challenge.select([:id, :position, :picture_path]).find(game.challenge_id)

    # 更新评测次数
    game.update_column(:evaluate_count, (game.evaluate_count.to_i + 1))
    # 清空代码评测信息
    msg = game.run_code_message
    msg.update_attributes(:status => 0, :message => nil) if msg.present?
    # 更新时间是为了TPM端显示的更新,退出实训及访问实训的时候会更新
    myshixun.update_column(:updated_at, Time.now)

    gitUrl = gitlab_url myshixun
    gitUrl = Base64.urlsafe_encode64(gitUrl)
    taskId = game.id
    shixun_tomcat = Redmine::Configuration['shixun_tomcat']
    step = game_challenge.try(:position)
    mirror_repository_limit = shixun.mirror_repositories.where(:main_type => 1).select(:resource_limit).try(:first).try(:resource_limit)
    # mirror表中很很大的脚本字段,所以单独查询一个字段效果更好
    resource_limit = "echo 'ulimit -f #{mirror_repository_limit}' >> /root/.bashrc  ; source /root/.bashrc\n"
    tpmScript = shixun.evaluate_script.nil? ? "" : Base64.urlsafe_encode64((resource_limit + shixun.evaluate_script).gsub("\r\n", "\n"))

    # status为2已经通过关,是重新评测
    if game.status == 2
      resubmit = params[:resubmit]
    else
      # 重新评测不影响已通关的实训状态;first为第一次评测,通过前端JS轮询获取
      game.update_attributes!(:status => 1) if params[:first].to_i == 1
    end

    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

    testCases = Base64.urlsafe_encode64(testSet.to_json) unless testSet.blank?


    # 注意:这个地方的参数写的时候不能换行
    content_modified = params[:content_modified] # 决定文件内容是否有修改,有修改如果中间成pull没有更新,则轮询等待更新
    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.exec_time}", :content_modified => content_modified, :persistenceName => shixun.identifier,
              :isPublished => (shixun.status < 2 ? 0 : 1), :sec_key => params[:sec_key]}

    # 评测有文件输出的需要特殊传字段 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")

    # 中间层交互
    if shixun.sigle_training
      uri = "#{shixun_tomcat}/bridge/game/persistence/gameEvaluate"
    else
      uri = "#{shixun_tomcat}/bridge/game/gameEvaluate"
    end

    res = interface_post uri, params, 502
    # 单评测类型(比较快的类型,实时返回结果,即不用中间层再回调trainint_task_status)
    if res['syncResult'].present?
      sigle_trainint_data res, myshixun, game
    end
    # ----单测模式end

    return {: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}
  rescue Exception => e
    Rails.logger.error("评测出错,详情:" + e.message)
    return {:result => 'fail',  :contents =>"实训云平台繁忙(繁忙等级:502),请稍后刷新并重试", :position => game_challenge.position, :had_done => game.had_done}
  end

  # 单评测类型(比较快的类型,实时返回结果,即不用中间层再回调trainint_task_status)
  def sigle_trainint_data res, myshixun, game
    begin
      t1 = Time.now
      jsonTestDetails = JSON.parse(res['syncResult']['jsonTestDetails'])
      Rails.logger.info("res is #{res} ### jsonTestDetails is #{jsonTestDetails}")
      timeCost = JSON.parse(res['syncResult']['timeCost'])
      brige_end_time = Time.parse(timeCost['evaluateEnd']) if  timeCost['evaluateEnd'].present?
      return_back_time = format("%.3f",  ( t1.to_f - brige_end_time.to_f)).to_f
      status = jsonTestDetails['status']
      game_id = jsonTestDetails['buildID']
      Rails.logger.info("sigle training_task_status start#1**#{game_id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
      resubmit = jsonTestDetails['resubmit']
      outPut = tran_base64_decode64(jsonTestDetails['outPut'])
      jenkins_testsets = jsonTestDetails['msg']
      compile_success  = jsonTestDetails['compileSuccess']
      Rails.logger.info(outPut)
      challenge = game.challenge
      if challenge.picture_path.present?
        pics = res[:tpiRepoPath]
        game.update_column(:picture_path, pics)
      end
      Rails.logger.info("training_task_status start#2**#{game_id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
      unless jenkins_testsets.blank?
        jenkins_testsets.each do |j_test_set|
          Rails.logger.info("j_test_set: ############## #{j_test_set}")
          actual_output = tran_base64_decode64(j_test_set['output'])
          Rails.logger.info "actual_output:################################################# #{actual_output}"
          Output.create!(:code => status, :game_id => game_id, :out_put => outPut, :test_set_position => j_test_set['caseId'],
                         :actual_output => actual_output, :result => j_test_set['passed'].to_i, :query_index => game.query_index,
                         :compile_success => compile_success.to_i)
        end
      end
      Rails.logger.info("#############status: #{status}")
      record = EvaluateRecord.where(:game_id => game_id).first
      Rails.logger.info("training_task_status start#3**#{game_id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")

      # status:0表示评测成功
      if status == "0"
        if !resubmit.blank?
          game.update_attributes!(:retry_status => 2, :resubmit_identifier => resubmit)
          #if game.had_done == 1
          challenge.path.split(";").each do |path|
            game_passed_code(game.id, path.try(:strip), myshixun.try(:gpid), 1)
          end
          #end
        else
          game.update_attributes!(:status => 2, :end_time => Time.now, :accuracy => format("%.4f", 1.0 / game.query_index))
          myshixun.update_attributes!(:status => 1) if game.had_done == 1
          challenge.path.split(";").each do |path|
            game_passed_code(game.id, path, myshixun.try(:gpid), 1)
          end
          if !game.answer_open && (challenge.shixun.try(:status) > 1) # 如果没有查看答案,则获得该关卡得分
            reward_grade(game.user, game.id, 'Game', challenge.score)
            reward_experience(game.user, game.id, 'Game', challenge.score)
            game.update_attributes!(:final_score => challenge.score)
          end

          # 更新实训关联的作品分数
          update_myshixun_work_score myshixun
        end
        # 如果过关了,下一关的状态是3(为开启),则需要把状态改成1(已开启)
        # next_game = game.next_game
        next_game = Game.next_game(myshixun.shixun_id, game.myshixun_id, challenge.position)
        next_game.update_column(:status, 0) if next_game.present? && next_game.status == 3
      else  # status == "-1" 表示返回结果错误
        if !resubmit.blank?
          game.update_attributes!(:retry_status => 1, :resubmit_identifier => resubmit)
        else
          game.update_attributes!(:status => 0)
        end
      end
      test_cases_time = format("%.3f",  (Time.now.to_f - t1.to_f)).to_f
      if record.present?
        consume_time = format("%.3f",  (Time.now - record.created_at)).to_f
        record.update_attributes!(:consume_time => consume_time, :git_pull => timeCost['pull'] ,
                                  :create_pod => timeCost['createPod'], :pod_execute => timeCost['execute'], :test_cases => test_cases_time,
                                  :brige => timeCost['evaluateAllTime'], :return_back => return_back_time)
      end
    end
  end

  # 选择题评测
  def choose_build params
    # 三类实训只取基础部分数据
    game = Game.select([:myshixun_id, :status, :challenge_id, :id, :answer_open, :final_score, :identifier,
                        :evaluate_count]).find_by_identifier(params[:identifier])
    # 更新评测次数
    game.update_column(:evaluate_count, (game.evaluate_count.to_i + 1))
    game.challenge.shixun.increment!(:evaluate_count)

    # 选择题如果通关了,则不让再评测
    if game.status == 2
      return {:message => "您已通过该关卡"}
    end

    myshixun = Myshixun.select([:updated_at, :gpid, :id, :shixun_id, :status, :user_id]).find(game.myshixun_id)
    shixun = Shixun.select([:id, :evaluate_script, :webssh, :status]).find(myshixun.shixun_id)
    game_challenge = Challenge.select([:id, :position]).find(game.challenge_id)
    user_answer = params[:answer]
    challenge_chooses_count = user_answer.length

    choose_correct_num = 0
    score = 0
    total_score = 0
    had_passed = true
    test_sets = []
    str = ""
    game_challenge.challenge_chooses.includes(:challenge_tags).each_with_index do |choose, index|
      user_answer_tran = user_answer[index].size > 1 ? user_answer[index].split("").sort.join("") :  user_answer[index]
      standard_answer_tran = choose.standard_answer.size > 1 ? choose.standard_answer.split("").sort.join("") :  choose.standard_answer
      correct = (user_answer_tran == standard_answer_tran) ? true : false
      if str.present?
        str += ","
      end
      str += "('#{game.id}', '#{choose.position}', '#{user_answer_tran}', '#{correct ? 1 : 0}', '#{game.query_index}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')"
      # Output.create(:game_id => @game.id, :test_set_position => choose.position, :actual_output =>  params[:answer][index], :result => correct, :query_index => @game.query_index)
      # 只要有一题错误就不能通关
      had_passed = false if !correct
      choose_correct_num += 1 if correct

      # 全部通关的时候,需要对所得的总分记录
      # 总分的记录应该是根据每一题累加,如果该题正确,则加分
      score += choose.score if correct

      standard_answer = correct ? standard_answer_tran : -1
      sin_test_set = {:result => correct, :actual_output => user_answer_tran, :standard_answer => standard_answer, :position => choose.position}
      test_sets << sin_test_set
    end

    # 批量插入评测结果
    Rails.logger.warn("sql str is #{str}")
    sql = "INSERT INTO outputs (game_id, test_set_position, actual_output, result, query_index, created_at, updated_at) VALUES" + str
    ActiveRecord::Base.connection.execute sql


    # 没通关或者查看了答案通关的时候经验为0
    # 通关但是查看了答案,评测的时候金币显示0(避免用户以为重复扣除),但是在关卡列表中金币显示负数
    experience = 0
    final_score = 0
    # 如果本次答题全部正确,并且之前没有通关,则进行相应的奖励,每关只要有错题,则不进行任何奖励
    # 注:扣除分数是在查看答案的时候扣除的
    if had_passed && !game.had_passed?
      game.update_attributes(:status => 2, :end_time => Time.now)
      # TPM实训已发布并且没有查看答案
      if shixun.is_published? && game.answer_open == 0
        # 查看答案的时候处理final_scor和扣分记录
        experience = score
        reward_grade(myshixun.owner, game.id, 'Game', score)
        game.update_attribute(:final_score, score)
        final_score = score
        reward_experience(myshixun.owner, game.id, 'Game', score)
      end
    end

    had_done = game.had_done
    myshixun.update_attribute(:status, 1) if had_done == 1

    grade = myshixun.owner.try(:grade)

    # 更新实训关联的作品分数
    update_myshixun_work_score myshixun

    # 高性能取上一关、下一关
    prev_game = Game.prev_identifier(shixun.id, game.myshixun_id, game_challenge.position)
    next_game = Game.next_game(shixun.id, game.myshixun_id, game_challenge.position)
    # 如果过关了,下一关的状态是3(为开启),则需要把状态改成1(已开启)
    next_game.update_column(:status, 0) if next_game.present? && next_game.status == 3

    return {:grade => grade, :gold => final_score, :experience => experience, :had_submmit => true,
            :challenge_chooses_count => challenge_chooses_count, :choose_correct_num => choose_correct_num,
            :test_sets => test_sets, :prev_game => prev_game, :next_game => next_game.try(:identifier)}
  end

  # 实训选择题需要局部刷新或者显示的部分
  def choose_container game_challenge, game, max_query_index, just_show
    # category 1: 单选题,其它的多选题(目前只有两种)
    challenge_chooses = game_challenge.challenge_chooses.includes(:challenge_questions)
    test_sets = []
    choose_test_cases = []
    chooses = []

    # 选择题测试集统计
    challenge_chooses_count = challenge_chooses.count
    choose_correct_num = game.choose_correct_num
    game_outputs = game.outputs.where(:query_index => max_query_index)

    # 判断用户是否有提交
    had_submmit = game_outputs.blank? ? false : true

    # 判断选择题是否写了标准答案
    has_answer = []
    challenge_chooses.each do |choose|
      challenge_question = []
      output = game_outputs.select{|game_output| game_output.test_set_position == choose.position}[0] unless game_outputs.blank?

      category = choose.category
      subject = choose.subject
      choose.challenge_questions.each do |question|
        position = question.position
        option_name = question.option_name
        challenge_question << {:positon =>  position, :option_name => option_name}
      end
      # actual_output为空表示暂时没有评测答题,不云讯查看
      actual_output = output.try(:actual_output).try(:strip)
      has_answer << choose.answer  if choose.answer.present?
      # 标准答案处理,错误的不让用户查看,用-1替代
      standard_answer = (actual_output.blank? || !output.try(:result)) ? -1 : choose.standard_answer
      result = output.try(:result)
      sin_test_set = {:result => result, :actual_output => actual_output, :standard_answer => standard_answer, :position => choose.position}

      sin_choose = {:category => category, :subject => subject, :challenge_question => challenge_question}
      chooses << sin_choose
      test_sets << sin_test_set
    end
    has_answer = has_answer.present?
    choose_test_cases = {:had_submmit => had_submmit, :challenge_chooses_count => challenge_chooses_count, :choose_correct_num => choose_correct_num, :test_sets => test_sets}
    return {:choose => chooses, :choose_test_cases => choose_test_cases, :has_answer => has_answer}
  end

  # 轮询获取状态
  # resubmit是在file_update中生成的,从game_build中传入的
  def game_status params, current_user
    Rails.logger.info("sec_key is #{params[:sec_key]}**1")
    game = Game.find_by_identifier(params[:identifier])
    resubmit_identifier = game.resubmit_identifier
    # 如果没有超时并且正在评测中
    # 判断评测中的状态有两种:1、如果之前没有通关的,只需判断status为1即可;如果通过关,则判断game的resubmit_identifier是否更新
    if (params[:time_out] == "false") && ((params[:resubmit].blank? && game.status==1) || (params[:resubmit].present? && (params[:resubmit] != resubmit_identifier)))
      # 代码评测的信息
      running_code_status = game.run_code_message.try(:status)
      running_code_message = game.run_code_message.try(:message)
      return {:running_code_status => running_code_status, :running_code_message => running_code_message}
    end

    Rails.logger.info("sec_key is #{params[:sec_key]}**2")
    Rails.logger.info("##### resubmit_identifier is #{resubmit_identifier}")
    port = params[:port]
    score = 0
    experience = 0
    game_status = game.status
    had_done = game.had_done
    game_challenge = Challenge.select([:id, :score, :position, :shixun_id, :web_route]).find(game.challenge_id)
    shixun = Shixun.select([:id, :status, :user_id, :test_set_permission]).find(game_challenge.shixun_id)

    if params[:resubmit].blank?   # 非重新评测
      if game_status == 2  # 通关
        if shixun.status > 1
          score = game.final_score  # 查看答案的时候有对最终获得金币进行处理
          experience = game.answer_open > 0 ? 0 : game_challenge.score.to_i
        else
          score = 0
          experience = 0
        end
      end
    else     # 重新评测
      # 如果满足前面的条件,进入此处只可能是结果已返回并存入了数据库
      if params[:resubmit] == resubmit_identifier     # 本次重新评测结果已经返回并存入数据库
        game_status = (game.retry_status == 2 ? 2 : 0) # retry_status是判断重新评测的通关情况。2表示通关
      end
    end

    Rails.logger.info("sec_key is #{params[:sec_key]}**3")
    # 实训的最大评测次数,这个值是为了优化查询,每次只取最新的最新一次评测的结果集
    max_query_index = game.query_index - 1
    # 区分评测过未评测过,未评测过按需求取数据
    if max_query_index > 0
      qurey_test_sets = TestSet.find_by_sql("SELECT o.code, o.actual_output,o.result, o.compile_success, 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
      qurey_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


    # 能进入到此处,肯定是已经返回了结果,也就是说outputs中肯定有了数据
    Rails.logger.info("sec_key is #{params[:sec_key]}**4")
    test_sets_count = qurey_test_sets.size
    # had_test = Output.where(:game_id => game.id, :query_index => max_query_index)
    # had_test_count = had_test.count
    had_passed_testsests_error_count = max_query_index > 0 ? qurey_test_sets.select{|qurey_test_set| qurey_test_set.result == false}.count : 0
    had_passed_testsests_error_count = test_sets_count - had_passed_testsests_error_count

    had_test = Output.where(:game_id => game.id, :query_index => max_query_index)
    error_position = had_test.blank? ? nil : had_test.select{|had_test| had_test.result == false}.last

    Rails.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\;") if error_position.try(:out_put).present?
    Rails.logger.warn("last_output is #{latest_output}")

    # power判断用户是否有权限查看隐藏测试集(TPM管理员;平台认证的老师;花费金币查看者)
    power = (shixun_manager(shixun, current_user) || (current_user.is_certification_teacher)) ? 1 : (shixun.test_set_permission ? 0 : -1)
    # 测试集统计及处理
    unless qurey_test_sets.blank?
      check_power = (power == 1 || game.test_sets_view)
      test_sets = test_set_static_data(qurey_test_sets, check_power)
    end
    # 处理生成图片类型文件
    picture = (game.picture_path.nil? ? 0 : game.id)
    # 针对web类型的实训
    web_route = game_challenge.try(:web_route)
    mirror_name = shixun.mirror_name

    Rails.logger.info("sec_key is #{params[:sec_key]}**5")
    # 轮询结束,更新评测耗时
    e_record = EvaluateRecord.where(:identifier => params[:sec_key]).first
    if game_status == 0 || game_status == 2
      if e_record
        front_js = format("%.3f",  (Time.now.to_f - e_record.try(:updated_at).to_f)).to_f
        consume_time = format("%.3f", (Time.now - e_record.created_at)).to_f
        e_record.update_attributes(:consume_time => consume_time, :front_js => front_js)
      end
    end

    Rails.logger.warn("##game is is #{game.id}, record id is #{e_record.id}, time is**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
    # 记录前端总耗时
    record = e_record.try(:consume_time)

    # 实训制作者当前拥有的金币
    grade = User.where(:id => game.user_id).pluck(:grade).first

    Rails.logger.info("sec_key is #{params[:sec_key]}**6")
    # 高性能取上一关、下一关
    prev_game = Game.prev_identifier(shixun.id, game.myshixun_id, game_challenge.position)
    next_game = Game.next_game(shixun.id, game.myshixun_id, game_challenge.position).try(:identifier)

    output_hash = {:test_sets => test_sets, :had_test_count => test_sets_count, :test_sets_count => test_sets_count, :had_passed_testsests_error_count => had_passed_testsests_error_count}

    Rails.logger.info("sec_key is #{params[:sec_key]}**7")
    return {:grade => grade, :gold => score, :experience => experience, :status => game_status, :had_done => had_done,
            :position => game_challenge.position, :port => port, :power => power, :record => record,
            :mirror_name => mirror_name, :picture => picture, :web_route => web_route, :latest_output => latest_output,
            :star => game.star, :next_game => next_game, :prev_game => prev_game}.merge(output_hash)
  end

  # 记录实训花费的时间,前端是通过ent_time - open_time,所以最终只更新open_time即可
  # 总花费的时间是花费的总时间加上开启的时间(open_time)
  # 注意:endtime和当前时间没关系,非时间差值,必须和opentime结合使用才有意义
  def cost_time params
    game = Game.select([:id, :cost_time, :identifier]).find_by_identifier(params[:identifier])
    cost_time = params[:time].to_i
    game.update_attribute(:cost_time, cost_time)
    return{ :game => game}
  end

  def sync_modify_time params
    game = Game.select([:id, :modify_time, :challenge_id]).find_by_identifier(params[:identifier])
    modify_time = Challenge.where(:id => game.challenge_id).pluck(:modify_time).first
    game.update_column(:modify_time, modify_time)
    return {:status => 1, :message => "success"}
  end

  # tpi弹框状态更新;true则不再显示;false每次刷新显示
  def system_update params
    myshixun = Myshixun.find(params[:myshixun_id])
    myshixun.update_attribute(:system_tip, true)
    return {:status => 1, :message => "success"}
  end

  # For admin
  # 强制重置实训
  def reset_my_game params, current_user
    unless current_user.admin?
      return {:status => 403, :message => "unauthorized"}
    end
    myshixun = Myshixun.find(Game.where(:identifier => params[:identifier]).pluck(:myshixun_id).first)
    shixun = myshixun.shixun
    ActiveRecord::Base.transaction do
      begin
        g = Gitlab.client
        shixun_tomcat = Redmine::Configuration['shixun_tomcat']
        challenges = shixun.challenges
        # 删除选择题用户记录
        unless challenges.blank?
          challenges.each do |challenge|
            if challenge.st != 0
              challenge.challenge_chooses.each do |choose|
                user_output = choose.choose_outputs
                unless user_output.blank?
                  user_output.delete
                end
              end
            end
          end
        end
        #end
        myshixun_job = Base64.urlsafe_encode64("myshixun_#{myshixun.id}")
        StudentWork.where(:myshixun_id => myshixun.id).update_all(:myshixun_id => 0, :work_status => 0, :work_score => nil, :final_score => nil,
                                                                  :cost_time => 0, :update_time => nil, :compelete_status => 0, :commit_time => nil)
        # myshixun.destroy
        myshixun.delete
        # 主从复制出现脏读的情况
        if myshixun.gpid
          g.delete_project(myshixun.gpid)
        end
      rescue Exception => e
        Rails.logger.error("myshixun reset failed #{e}")
        raise ActiveRecord::Rollback
      end
    end
    # 主从复制出现脏读的情况
    sleep(1)
    return {:status => 1, :message => "sucess", :url => "/shixuns/#{shixun.identifier}"}
  end

  def close_webssh params, current_user
    myshixun_id = Game.where(:identifier => params[:identifier]).pluck(:myshixun_id).first
    digest = params[:identifier]+Redmine::Configuration['bridge_secret_key']
    digest_key = Digest::SHA1.hexdigest("#{digest}")
    begin
      shixun_tomcat = Redmine::Configuration['shixun_tomcat']
      uri = "#{shixun_tomcat}/bridge/webssh/delete"
      Rails.logger.info("#{current_user} => cloese_webssh digest is #{digest}")
      params = {:tpiID => myshixun_id, :digestKey => digest_key, :identifier => params[:identifier]}
      res = uri_exec uri, params
      if res && res['code'].to_i != 0
        raise("实训云平台繁忙(繁忙等级:110)")
      end
      return {:status => 1, :message => "webssh closed"}
    rescue Exception => e
      Rails.logger.error(e)
      return {:status => 0, :message => "authentication failed"}
    end
  end

  # return: 头像,姓名,用户主页链接,学校, 点赞数, 等级(通关数)
  def get_passed_user params
    page = params[:page].to_i
    offset = page * 15
    file_base params[:identifier]
    games = @game.challenge.games.where(:status => 2).includes(user: [:myshixuns, user_extensions: :school]).order("cost_time desc").offset(offset).limit(15)
    users = format_answer_list games
    {user_answer_list: users}
  end

  def get_passed_code params
    file_base params[:identifier]
    codes = @game.game_codes.select([:new_code, :path]).where("new_code is not null")
    code_list = []
    codes.each do |code|
      code_list << {path: code.path, code: code.new_code}
    end
    {code_list: code_list}
  end


  def shixun_manager shixun, user_current
    member = shixun.shixun_members.where(:role => [1,2], :user_id => user_current.id)
    (!member.blank? || user_current.admin?) ? true : false
  end

  # 实训一些基础查询
  def game_base identifier
    @game = Game.select([:myshixun_id, :status, :final_score, :answer_open, :challenge_id, :id]).find_by_identifier(identifier)
    @myshixun = Myshixun.select([:id, :shixun_id, :gpid, :user_id]).find(@game.myshixun_id)
    @shixun = Shixun.select([:status, :id]).find(@myshixun.shixun_id)
  end

  # 与文件代码相关的一些通用查询
  def file_base identifier
    @game = Game.select([:myshixun_id, :challenge_id, :id]).find_by_identifier(identifier)
    @myshixun = Myshixun.select([:shixun_id, :gpid, :id, :user_id]).find(@game.myshixun_id)
  end

  private
  DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z)
  # 随机生成字符
  def generates_identifier(container, num)
    code = DCODES.sample(num).join
    while container.exists?(identifier: code) do
      code = DCODES.sample(num).join
    end
    code
  end

  def format_answer_list games
    user_info = []
    games.each do |game|
      user = game.user
      votes = game.game_codes.first.votes
      passed_count = user.myshixuns.where(:status => 1).count
      user_info << {
          user_id: user.id,
          name: user.show_name,
          game_id: game.id,
          image_url: url_to_avatar(user),
          school_name: user.school_name,
          votes: votes,
          passed_count: passed_count
      }
    end
    user_info
  end
end