require File.join(File.dirname(__FILE__), "..", "models", "build.rb")

Buildwise::App.controllers :builds do


  post '/begin' do
    logger.info("Start a new build")        
    content_type :text
    options = YAML.load(params[:options]) rescue {}
    options = {} unless options.class == Hash
    logger.debug "#{Time.now}| Start build options: #{options.inspect} | #{}"


    project_name = params[:project_name] || (options && options[:project_name])
    @project = Project.retrieve_by_identifier(project_name).first || Project.retrieve_by_name(project_name).first 
    
    if @project.nil?
      most_recent_active_build = Build.where("status = ?", 'building').last
      if most_recent_active_build

        @project = most_recent_active_build.project
      elsif Project.count == 1
        logger.info("only one project #{Project.first.identifier}, please update the project identifier in your Rakefile next time")
        @project = Project.first
      else      
        current_build_project_id_file = "#{BUILDWISE_HOME}/work/current_build_project_id"
        if File.exist?(current_build_project_id_file)
          current_proj_id = File.read(current_build_project_id_file).strip rescue nil          
          @project = Project.retrieve_by_identifier(current_proj_id).first
        end

        if @project.nil? 
          return "Invalid for project: #{project_name} for options: #{params[:options].inspect}"
        end
      end
    end

    the_build = @project.last_build
    raise "[buildwise_app.rb] the build is not created" if the_build.nil?
    the_build.test_syntax_framework = options[:test_syntax_framework] || options[:test_framework] || "RSpec"
    the_build.save

    logger.info("Last Build: #{@project.last_build.id} | Found build: #{the_build.id} | #{the_build.status} | currently building: #{@project.is_building?} | #{the_build.test_syntax_framework} | #{@project.is_building?}")
    logger.debug("Settings :working_dir => #{options[:working_dir]}, :ui_test_dir => #{options[:ui_test_dir]}")

    if @project.is_building?
      the_build.acceptance_test_options = params[:options]
      if options[:ui_test_dir] && options[:ui_test_dir].class == Array && options[:ui_test_dir].first.to_s =~ /^\// && File.exist?(options[:ui_test_dir].first)

        ui_test_dir = options[:ui_test_dir].first

      else

        if the_build.test_syntax_framework == "Cucumber"
          ui_test_dir = File.expand_path(File.join(options[:working_dir], options[:ui_test_dir]))
        else
          if options[:ui_test_dir]
            ui_test_dir = options[:ui_test_dir].collect { |x| File.expand_path(File.join(options[:working_dir], x)) }
          else
            ui_test_dir = @project.ui_test_dir
          end
          ui_test_dir = ui_test_dir[0] if ui_test_dir.is_a?(Array)
        end

      end




    


      if (options[:distributed] || options[:parallel]) && the_build.test_files.size == 0
      
        the_build.is_parallel = true
        
        ui_test_dir = ui_test_dir[0] if ui_test_dir.is_a? Array
        start_time = Time.now
        logger.info("create functional UI tests in database from: #{ui_test_dir} |  currently #{the_build.test_files.size} tests")
        puts("\n\n\n\n***\n\n create functional UI tests in database from: #{ui_test_dir} in framework: #{the_build.test_syntax_framework} |  currently #{the_build.test_files.size} tests ")
        
=begin
        test_file_names = []
        if Dir.exist?(ui_test_dir) 
          Dir.entries(ui_test_dir).each do |file_name|
            next if file_name == "." || file_name == ".."
        
            if the_build.test_syntax_framework =~ /mocha/i
              next unless file_name =~ /\.js$/                        
            elsif the_build.test_syntax_framework =~ /cucumber/i 
              next unless file_name =~ /\.feature$/         
            elsif the_build.test_syntax_framework =~ /gauge/i 
              next unless file_name =~ /\.spec$/       
            elsif the_build.test_syntax_framework =~ /unittest/i 
              next unless file_name =~ /\.py$/                                                
            elsif the_build.test_syntax_framework =~ /playwrighttest/i 
              next unless file_name =~ /\.ts$/                     
            else
              next unless file_name =~ /_spec\.rb$/ || file_name =~ /_test\.rb$/
            end
          
            next if options[:excluded] && options[:excluded].include?(file_name)
            next if options[:except] && options[:except].include?(file_name)
          
            test_file_names << file_name
          end
        end
        
        if options[:only] && options[:only].size > 0
          test_file_names.select!{|x| options[:only].include?(x) }
        end
        

        loop_times = 1 
        if @project.config && @project.config.is_load_testing && @project.config.load_max_iteration_count > 1
          loop_times = @project.config.load_max_iteration_count.to_i
        end
        
        is_load_testing = @project.config && @project.config.is_load_testing

        TestFile.transaction do    
          loop_times.times do 
            test_file_names.each do |file_name|
              test_file = TestFile.new(:filename => file_name, :created_at => Time.now, :build_id => the_build.id)
              if is_load_testing 

                test_file.priority = rand(loop_times * test_file_names.size) + 1
              else              

                begin
                  test_file.determine_priority
                rescue => dpe            
                  logger.warn("[#{Time.now - start_time}] Error occurred on determine priority: #{dpe}, #{dpe.backtrace}")
                end
              end
              test_file.save
            end
          end
        end
      
        the_build.test_files.reload        
        logger.info("[#{Time.now - start_time}] #{the_build.test_files.size} tests created for distributed build")
      end

      ui_test_dir = ui_test_dir[0] if ui_test_dir.is_a?(Array)
      begin
        the_build.acceptance_test_context_to_file_lookups = YAML.dump(the_build.build_context_to_file_lookups(ui_test_dir))
      rescue => e
        logger.warn("Failed to parse lookups for ui_test_dir: #{ui_test_dir}: #{e}")
      end

=end
        
        determine_test_files(the_build, ui_test_dir, the_build.test_syntax_framework, options)
        logger.info(" ^^1>  Prepare test files took: #{Time.now - start_time} seconds")

        sub_start_time = Time.now
        determine_test_files_priority(the_build, 5.minute.ago)        
        logger.info(" ^^2>  Determine dynamic  priority took: #{Time.now - sub_start_time} seconds")

        sub_start_time = Time.now
        determine_acceptance_test_context_to_file_lookups(the_build, ui_test_dir)        
        logger.info(" ^^3>  Save context look up: #{Time.now - sub_start_time} seconds")

        logger.info(" ^^$> Prepare test files and determines priority total took: #{Time.now - start_time} seconds")
      
        the_build.save
      end
    end

    logger.info("Returning new build: #{the_build.id.inspect}")
    delete_cache_projects

    return the_build.id.to_s
  end



  post "/:id/finish" do
    logger.info("{Master} Calling /builds/finish build #{params[:id]}")
    @build = find_build(params[:id])
    if @build && @build.test_files.size > 0
      logger.info("{Master} the build already has test files => #{@build.test_files.size}")
      Buildwise::App.cache.delete("/projects/#{@build.project.identifier}/report?&".to_sym) if @build.project
      return "OK|Already Saved"
    else
      stage = params[:stage] # NOTES not used
      logger.debug("Calling build finish: #{@build.test_files.size} | reparse test results") if @build

    end

    delete_cache_projects    
  end



  get "/:id/changed_files" do
    @build = Build.find_by_id(params[:id])
    return if @build.nil?
    @build.last_commit_changed_files
  end



  get "/:id/failures" do
    @build = Build.find_by_id(params[:id])
    return if @build.nil?

    failed_test_files = @build.test_files.collect { |x| x if x.failed? }
    failed_test_files.compact.collect { |x| x.filename }
  end



  get "/:id/export_ui_test_results" do
    content_type "text/csv"
    @build = Build.find_by_id(params[:id])

    if RUBY_VERSION =~ /^1\.8/
      require 'fastercsv'
      csv = FasterCSV
    else
      require 'csv'
      csv = CSV
    end
    
    csv_string = csv.generate do |csv|

      csv << ["Test File", "Test Case", "Result", "Duration", "Notes"]

      @build.test_files.each do |test_file, fidx|
        test_file.test_cases.each_with_index do |test_case, idx|
          test_name = test_case.name
          if RACK_ENV == "showcase"
            test_name = "Test Case ##{test_case.id} : hidden in ShowCase mode"
          end    
          test_duration= (test_case.duration + test_file.average_test_case_hook_time).round(2)
          test_ok = test_case.successful
          csv << [File.basename(test_file.filename), test_name, test_ok ? "OK" : "Failure", test_duration, ""]
        end
      end
    end

    tmp_dir = File.join(BUILDWISE_ROOT, "tmp")
    FileUtils.mkdir_p(tmp_dir) unless File.exist?(tmp_dir)
    tmp_test_result_file = File.join(tmp_dir, "test_results.csv")
    fio = File.open(tmp_test_result_file, "w")
    fio.write(csv_string)
    fio.close
    send_file tmp_test_result_file, :filename => "test_results.csv"
  end

  


  get "/:id/export_test_results_excel" do
    @build = Build.find_by_id(params[:id])
    begin
      require 'spreadsheet'
      book = Spreadsheet.open File.join(BUILDWISE_ROOT, 'config', 'test_report_template.xls')
      sheet = book.worksheet 0
      display_company = settings.company_name || "My Company"
      sheet.row(3).replace [display_company, nil, nil, nil, nil, "Date:", @build.start_time.localtime.strftime("%Y-%m-%d %H:%M")]

      num_cases = 0
      num_failed = 0
      total_duration = 0.0

      fmt_red = Spreadsheet::Format.new :color => 'red', :align => :justify
      fmt_green = Spreadsheet::Format.new :color => 'green', :align => :center, :horizontal_align => :center

      if @build.test_files.any?
        @build.test_files.reverse.each { |test_file|
          test_file.test_cases.reverse.each_with_index do |test_case, idx|
            result_display = test_case.successful ? "        P" : "  F"
            the_duration = test_case.duration +  test_file.average_test_case_hook_time
            display_duration = (the_duration * 100).to_i / 100.0
            test_case_name = test_case.name
            if RACK_ENV == "showcase"
              test_case_name = "Test Case ##{test_case.id} : hidden in ShowCase mode"
            end            
            new_row = sheet.insert_row 11, [test_file.filename, test_case_name, nil, nil, nil, nil, result_display, display_duration]
            num_cases += 1
            if test_case.successful
              sheet.row(11).set_format 6, fmt_green
            else
              num_failed += 1
            end
            total_duration += the_duration
          end
        }
      end

      display_total_duration = total_duration.to_i
      sheet.row(6).replace ["Total Test Cases:", num_cases, nil, "Failed:", num_failed, nil, "Duration:", "#{display_total_duration} secs"]


      if num_failed <= 0
        sheet.row(6).set_format 4, fmt_green
      end

      tmp_dir = File.join(BUILDWISE_ROOT, "tmp")
      FileUtils.mkdir_p(tmp_dir) unless File.exist?(tmp_dir)
      report_file_name = "test_report_" + Time.now.strftime("%Y%m%d%H%M%S") + ".xls"
      report_file_path = File.join(tmp_dir, report_file_name)
      book.write(report_file_path)
      send_file report_file_path, :filename => "test_report.xls"

    rescue => e
      logger.warn("failed to export excel #{e}")
    end
  end



  get "/:id/test_files/:name" do
    @build = Build.find_by_id(params[:id])
    logger.debug(" >> Getting test file: #{@build.artifacts_dir} + #{params[:name]}")    
    ui_tests_dir = File.join(@build.artifacts_dir, "ui-tests")
    @scripts = highlight_test_file_under_ui_tests_folder(ui_tests_dir, params[:name])
    return @scripts
  end

  get "/:id/artifact/:path" do
    return "" if !params[:id] && !params[:path]
    @build = Build.find_by_id(params[:id])
    path = @build.artifact(params[:path])

    if File.directory? path
      if File.exist?(File.join(path, 'index.html'))
        return File.read(File.join(path, 'index.html'))
      else

        return "this should be an index of #{params[:path]}"
      end
    elsif File.exist? path
      send_file(path, :type => get_mime_type(path), :disposition => 'inline', :stream => false)
    else
      return "Not found: #{path}"
    end

  end


  get "/:id/envs" do
    @build = Build.find_by_id(params[:id])
    return "" if @build.nil? || @build.project.nil?
    redirect "/projects/#{@build.project.id}/envs"
  end



  post "/:id/cancel_assignment" do
    return "" if !params[:id]
    @build = Build.find_by_id(params[:id])
    test_file = params[:test_file]
    agent_ip_address = params[:ip_address]
    logger.info("|#{agent_ip_address}| #{params[:id]} Request to cancel test #{test_file}")
    @build.cancel_assignment(test_file, agent_ip_address)
    return "OK"
  end



  post "/:id/summary" do
    return "" if !params[:id]
    @build = Build.find_by_id(params[:id])
    @build.update_column(:summary, params[:summary])
    delete_cache_projects
    return "OK"
  end




  get "/:id/status" do
    @build = Build.find_by_id(params[:id])
    return @build.status
  end









  get "/:id/ui_test_status", :cache => true  do
    
    expires 5
    cache_key { request.path_info + '?' + params.slice(':id').to_param }
    
    @build = Build.find_by_id(params[:id])
    logger.info("Check ui_test_status for #{params[:id]}, but not exists") if @build.nil?
  
    ui_testing_status = "Pending"
    if @build.nil?
      ui_testing_status =  "Error"
    elsif @build.status == "cancelled" # the build has been cancelled, mark as done so that agent can move on to next build (not Pending)
      ui_testing_status = "Cancelled"
    else
      @build.refresh_ui_test_status
      ui_testing_status = @build.ui_test_status
      ui_testing_status = "Pending" if ui_testing_status.blank?
    end
    logger.info("Check ui_test_status for build  #{params[:id]} => |#{ui_testing_status}|")
    return ui_testing_status
  end
  



  post "/:id/skip" do
    @build = find_build(params[:id])
    authenticate_admin_or_project_builder!(@project)
    @build.status = "OK"
    @build.successful = true
    @build.finish_time = Time.now
    @build.duration = (@build.finish_time - @build.start_time) rescue nil
    @build.save
    redirect "/"
  end

  get "/:id/complete-build", :provides => [:js] do
    @build = find_build(params[:id])
    authenticate_admin_or_project_builder!(@project)
    @build.refresh_ui_test_status

    @build.status = "complete"
    @build.successful = @build.ui_test_status == "OK"

    @build.finish_time = Time.now
    @build.duration = (@build.finish_time - @build.start_time) rescue nil
    @build.save
    
    render "/builds/complete.js".to_sym, :layout => false        
  end
  


  get "/:id/refresh_ui_test_status", :provides => [:js] do
    @build = find_build(params[:id])
    @build.refresh_ui_test_status
    
    detect_hanging_test_execution(@build)
    
    render "/builds/refresh_ui_test_status.js".to_sym, :layout => false
  end





  get '/:id', :cache => (defined?(RACK_ENV) && RACK_ENV == "production" && ::BuildWise::ENABLE_CACHE) do
    @build = find_build(params[:id])    
    return if @build.nil?

    @session_test_execution_enabled = session["server_test_execution_enabled_#{@build.id}"].to_s == "true" rescue false

    the_cache_key = request.path_info + "?"
    if params.slice('step')
      the_cache_key += (params.slice('step').to_param  + "&")
    end
    if params.slice('sort')
      the_cache_key += (params.slice('sort').to_param +  "&" + params.slice('sort_direction').to_param)
    end    
    if @build.finish_time
      the_cache_key += ("&finish_time=" + @build.finish_time.to_i.to_s)
    end    
    cache_key { the_cache_key.to_param }

    if @build.incomplete?
      expires 3  # expire cached version when building in progress
    else
      expires 30 # cache longer for completed builds
    end

    if params[:step] && params[:step].to_i > 0
      @step = BuildStepExecution.where(:build_id => @build.id, :id =>  params[:step]).first
    end
  
    build_test_files = TestFile.includes(:test_cases).where(:build_id => @build.id)

    if params[:sort]
      sort_column = params[:sort]
      if @build.is_parallel
        if @build.incomplete?
          sort_column ||= "assigned_at"
        else
          sort_column ||= "successful"          
        end
      else
        sort_column ||= "id"
      end
                
      @sort_direction = params[:sort_direction] rescue "ASC"
      @sort_direction ||= "ASC"

      build_test_files = build_test_files.order(sort_column + " " + @sort_direction)
      @sorted = true
    else
    

      if @build.incomplete?
        sort_column = @build.is_parallel ? "assigned_at" : "id"
        @sort_direction = "ASC"
        build_test_files = build_test_files.order(sort_column + " " + @sort_direction)
      else

        @sort_direction = "ASC"
        sort_column = "successful"
        second_sort_column = @build.is_parallel ? "assigned_at" : "id"
        build_test_files = build_test_files.order(sort_column + " " + @sort_direction).order(second_sort_column + " " + @sort_direction)
      end
    end

    @sort_direction ||= "ASC"
    @sort_column ||= sort_column

    @build_ui_test_count = build_test_files.each.pluck("num_total").compact.sum      
    @test_files = build_test_files
    @project = @build.project if @build
    @autorefresh =  @build.incomplete?
    unless @autorefresh
      the_history_count = @test_files.count * 3
      if the_history_count > 500 
        the_history_count = 500
      end
      @project_recent_builds = @project.valid_builds(the_history_count)
    else
      @project_recent_builds = []
    end

    if @build.is_parallel
      @build.incomplete? ? distributed_build_in_progress : distributed_build_complete      
    elsif @build.incomplete?  # quick build, running on single machine

      quick_build_in_progress
    end

    if @build.is_parallel && !@build.incomplete?

      @build_false_alarms = @build.false_alarms.to_a  # not returning ActiveRecord association to faster view
    end      
    
    if @step.nil? && params[:step] != "all" && @build.incomplete? && !@build.stage.blank?
      @step = @build.build_step_executions.select{|x| x.task_name == @build.stage}.first
    end
    
    if @build.start_time > Date.yesterday
      begin

        log_dir = File.expand_path(File.join(BUILDWISE_ROOT, "log", "builds"))
        unless File.exist?(log_dir)
          FileUtils.mkdir_p(log_dir)
        end
        if @build.artifacts_dir && !File.exist?(@build.artifacts_dir)
          FileUtils.mkdir_p(@build.artifacts_dir)
        end
        builder_log_file = File.join(log_dir, "build_#{@build.id.to_s.rjust(5, '0')}.log")
        if builder_log_file && @build.artifacts_dir && File.exist?(builder_log_file) && File.exist?(@build.artifacts_dir)
          FileUtils.cp(builder_log_file, @build.artifacts_dir)              
        end
      rescue => ce
        puts "#{Time.now} [Error] Failed to copy builder log to build's artifacts_dir: #{ce}.\n#{ce.backtrace}"    
      end    
    end

    @load_test_timings = {}

    @load_chart_refresh_interval = settings.dynamic_chart_refresh_interval
    if @load_chart_refresh_interval.nil? || @load_chart_refresh_interval.to_i < 1000
      @load_chart_refresh_interval = 5000
    end
    
    if @build.is_load_testing && !@build.incomplete?
      raw_data = LoadTestResult.where(:build_id => @build.id)    

      @build_load_test_results = LoadTestResult.where(:build_id => @build.id).order("start_timestamp ASC")
      @build_load_operation_errors = @build_load_test_results.where("success != ?", true)
      
      @raw_operation_timings = @build_load_test_results.group_by(&:operation)
      @build_operation_timings = []

      error_count = @build_load_test_results.where("success != ?", true).count 
      @build_load_test_error_rate = error_count * 100.0 / @build_load_test_results.count 
        
      @raw_operation_timings.each do |key, val|
        operation_timings = []
        val.each do |rd|
          start_hash = { x: rd.start_timestamp, y: 0}
          data_hash = {x: (rd.start_timestamp + rd.end_timestamp) / 2, y: (rd.duration / 1000.0).round(2) }
          end_hash = { x: rd.end_timestamp, y: 0} 
          operation_timings << start_hash         
          operation_timings << data_hash         
          operation_timings << end_hash         
        end
        
        @load_test_timings[key] = operation_timings
        
        duration_array =  val.collect{|x| (x.duration).round(2)} 
        @build_operation_timings << {:operation => key, :count => val.size,  
                   :average_time => (duration_array.sum / val.count).round(3),   
                   :fastest_time => duration_array.min,
                   :slowest_time => duration_array.max }    
      end        
  
    end
    
    @performance_test_results = PerformanceTestResult.where(:build_id => @build.id)    
    @performance_timings = []
    raw_performance_timings = @performance_test_results.group_by(&:operation)
    raw_performance_timings.each do |key, val|
      duration_array =  val.collect{|x| (x.duration.to_f).round(2)}    
      @performance_timings << {:operation => key, :count => val.size,
                   :average_time => (duration_array.sum / val.count).round(3),   
                   :fastest_time => duration_array.min,
                   :slowest_time => duration_array.max }
    end
                     
    @building_in_progress = BuildRunner.busy? rescue false
    render "builds/show".to_sym
  end



  get '/:id/agent_charts' do
    @build = find_build(params[:id])
    @build_agent_times = @build_agent_count = {}

    @build.test_files.each do |tf|
      agent_name = tf.agent || "unknown"
      if @build_agent_count[agent_name]
          @build_agent_count[agent_name] += 1
          @build_agent_times[agent_name] += tf.duration.round(1) if tf.duration
      else
          @build_agent_count[agent_name] = 1
          @build_agent_times[agent_name] = tf.duration ? tf.duration.round(1) : 0
      end
    end

    @data = @build_agent_times.keys.sort.map{|x| {:name => x, :y => @build_agent_times[x] } }    
    render "/builds/agent_charts.js".to_sym, :layout => false
  end



  get "/:id/allocations", :provides => [:js] do
    @build = Build.where(:id => params[:id]).first







    @allocations = @build.current_agent_allocations
    @allocations.sort!{|a,b| a.assigned_at <=> b.assigned_at }
    render "/builds/allocations.js".to_sym, :layout => false    
  end


  get "/:id/wait", :provides => [:js] do
    logger.info("Delay build completion: #{params[:id]}")    
    @build = find_build(params[:id])
    authenticate_admin_or_project_builder!(@project)
    @build.update_column(:is_waiting_mode, true)
    @build.reload
    
    detect_hanging_test_execution(@build)
    
    render "/builds/wait.js".to_sym, :layout => false        
  end


  get "/:id/unwait", :provides => [:js] do
    logger.info("Let the build continue to finish: #{params[:id]}")    
    @build = find_build(params[:id])
    authenticate_admin_or_project_builder!(@project)
    @build.update_column(:is_waiting_mode, false)
    @build.reload
    render "/builds/unwait.js".to_sym, :layout => false        
  end



  get "/:id/invalidate", :provides => [:js] do
    logger.info("Invalidate build: #{params[:id]}")
    @build = find_build(params[:id])
    authenticate_admin_or_project_builder!(@project)
    @build.update_column(:is_invalid, true)
    @build.reload
    delete_cache_projects
    render "/builds/invalidate.js".to_sym, :layout => false        
  end


  get "/:id/validate", :provides => [:js] do
    logger.info("Validate build: #{params[:id]}")
    @build = find_build(params[:id])
    authenticate_admin_or_project_builder!(@project)
    @build.update_column(:is_invalid, false)
    @build.reload
    delete_cache_projects
    render "/builds/validate.js".to_sym, :layout => false        
  end

  


  get "/:id/delete", :provides => [:js] do
    @build = find_build(params[:id])
    authenticate_admin_or_project_builder!(@project)
    @build.destroy if @build
    delete_cache_projects
    render "/builds/destroy.js".to_sym, :layout => false        
  end




  get '/:id/cancel', :provides => [:js] do    
    @build = find_build(params[:id])
    @is_cancelled = false        
    authenticate_admin_or_project_builder!(@project) if @build     
    
    if @build && (current_user.is_admin? || current_user.id == @build.triggered_by_user_id)
      @build.cancel
      @is_cancelled = true
    else      

    end    
    Buildwise::App.cache.clear
    render "/builds/cancel.js".to_sym, :layout => false            
  end
 
 


  get '/:id/enable_test_execution', :provides => [:js] do    
    @build = find_build(params[:id])
    session["server_test_execution_enabled_#{@build.id}"] = "true";
    render "/builds/enable_test_execution.js".to_sym, :layout => false            
  end

  


  get '/:id/disable_test_execution', :provides => [:js] do    
    @build = find_build(params[:id])
    session["server_test_execution_enabled_#{@build.id}"] = "false";
    render "/builds/disable_test_execution.js".to_sym, :layout => false            
  end
  
  
  post "/:id/cancel-allocation/:test_file_id", :provides => [:js] do
    @build = find_build(params[:id])
    @test_file = TestFile.find(params[:test_file_id])
    if @build && @test_file && @test_file.build.id == @build.id
      @build.unassign_test(@test_file)
    end
    render "/builds/cancel_allocation.js".to_sym, :layout => false            
  end
  

  get "/:id/ui-test-results", :provides => [:js] do
    @build = find_build(params[:id])
    @user = current_user
    if params[:step] && params[:step].to_i > 0
      @step = BuildStepExecution.where(:build_id => @build.id, :id =>  params[:step]).first
    end
  
    build_test_files = TestFile.includes(:test_cases).where(:build_id => @build.id)    
    @build_ui_test_count = build_test_files.each.pluck("num_total").compact.sum  
    
    if @build.is_parallel
      if @build.is_load_testing
        @sort_column = "priority"
        @sort_direction = "DESC"
      else
        @sort_column = "assigned_at"
        @sort_direction = "ASC"        
      end       
    else
      @sort_column = "id"
      @sort_direction = "ASC"
    end
    
    if @build.is_parallel && !@build.is_load_testing
      @test_files = @build.incomplete? ? distributed_build_in_progress : distributed_build_complete
    else
      @test_files = build_test_files.order(@sort_column + " " + @sort_direction)    
    end
    
    @project = @build.project if @build    
    render "/builds/ui_test_results.js".to_sym, :layout => false                  
  end
  
  get "/:id/load-testing-errors", :provides => [:js] do
    @build = find_build(params[:id])
    
    render "/builds/load_testing_errors.js".to_sym, :layout => false            
  end
  
  get "/:id/load-operation-errors", :provides => [:js] do
    @build = find_build(params[:id])
    render "/builds/load_operation_errors.js".to_sym, :layout => false              
  end
  
  get "/:id/deploy", :provides => [:js] do
    authenticate_admin!
    
    @build = find_build(params[:id])
    @project = @build.project
    @ok_to_deploy = false
    if @build.successful? && @project.config.deploy_rake_task &&  !@project.config.deploy_rake_task.blank?
      @ok_to_deploy = true
    end
    render "/builds/deploy.js".to_sym, :layout => false                  
  end
  
  
   post "/:id/confirm-deploy",:provides => [:js] do
     authenticate_admin!
     
    @build = find_build(params[:id])
    @project = @build.project

    @deploy_task = nil
    if @build.successful? && @project.config.deploy_rake_task &&  !@project.config.deploy_rake_task.blank?
      @deploy_task = @project.config.deploy_rake_task
  
      sources_dir = @project.working_dir + "/sources"          
      @deploy_output = execute_rake_task(@deploy_task, sources_dir)  
    
      @deploy_stdout = @deploy_output[:stdout]
      @deploy_stderr = @deploy_output[:stderr]    
    else
      
      @deploy_stderr == "Not run!"
    end
    
    render "/builds/confirm_deploy.js".to_sym, :layout => false                                     
  end
  
  
end