require 'tmpdir'

class TestdataImporter
  
  attr :log_msg

  def initialize(problem)
    @problem = problem
  end

  def import_from_file(tempfile, 
                       time_limit, 
                       memory_limit,
                       checker_name='text',
                       import_to_db=false)

    dirname = extract(tempfile)
    return false if not dirname
    if not import_to_db
      @log_msg = GraderScript.call_import_problem(@problem.name,
                                                  dirname,
                                                  time_limit,
                                                  memory_limit,
                                                  checker_name)
    else
      # Import test data to test pairs.

      @problem.test_pairs.clear
      if import_test_pairs(dirname)
        test_pair_count = TestPair.count :conditions => "problem_id = #{@problem.id}"
        @log_msg = "Importing test pair successful. (#{test_pair_count} test pairs imported)"
      else
        @log_msg = "Importing test pair failed. (0 test pairs imported)"
      end
    end

    @log_msg << import_problem_description(dirname)
    @log_msg << import_problem_pdf(dirname)
    @log_msg << import_full_score(dirname)

    return true
  end

  protected

  def self.long_ext(filename)
    i = filename.index('.')
    len = filename.length
    return filename.slice(i..len)
  end

  def extract(tempfile)
    testdata_filename = save_testdata_file(tempfile)
    ext = TestdataImporter.long_ext(tempfile.original_filename)

    extract_dir = File.join(GraderScript.raw_dir, @problem.name)
    if File.exists? extract_dir
      backup_count = 0
      begin
        backup_count += 1
        backup_dirname = "#{extract_dir}.backup.#{backup_count}"
      end while File.exists? backup_dirname
      File.rename(extract_dir, backup_dirname)
    end
    Dir.mkdir extract_dir

    if ext=='.tar.gz' or ext=='.tgz'
      cmd = "tar -zxvf #{testdata_filename} -C #{extract_dir}"
    elsif ext=='.tar'
      cmd = "tar -xvf #{testdata_filename} -C #{extract_dir}"
    elsif ext=='.zip'
      cmd = "unzip -o #{testdata_filename} -d #{extract_dir}"
    else
      return nil
    end

    system(cmd)

    files = Dir["#{extract_dir}/**/*1*.in"]
    return nil if files.length==0

    File.delete(testdata_filename)

    return File.dirname(files[0])
  end

  def save_testdata_file(tempfile)
    ext = TestdataImporter.long_ext(tempfile.original_filename)
    testdata_filename = File.join(Dir.tmpdir,"#{@problem.name}#{ext}")

    return nil if tempfile==""
    
    if tempfile.instance_of?(Tempfile)
      tempfile.close
      FileUtils.move(tempfile.path,testdata_filename)
    else
      File.open(testdata_filename, "wb") do |f| 
        f.write(tempfile.read) 
      end
    end

    return testdata_filename
  end

  def import_test_pairs(dirname)
    test_num = 1
    while FileTest.exists? "#{dirname}/#{test_num}.in"
      in_filename = "#{dirname}/#{test_num}.in"
      sol_filename = "#{dirname}/#{test_num}.sol"

      break if not FileTest.exists? sol_filename

      test_pair = TestPair.new(:input => open(in_filename).read,
                               :solution => open(sol_filename).read,
                               :problem => @problem)
      break if not test_pair.save

      test_num += 1
    end
    return test_num > 1
  end

  def import_problem_description(dirname)
    html_files = Dir["#{dirname}/*.html"]
    markdown_files = Dir["#{dirname}/*.md"] + Dir["#{dirname}/*.markdown"]
    if (html_files.length != 0) or (markdown_files.length != 0)
      description = @problem.description || Description.new

      if html_files.length != 0
        filename = html_files[0]
        description.markdowned = false
      else
        filename = markdown_files[0]
        description.markdowned = true
      end

      description.body = open(filename).read
      description.save
      @problem.description = description
      @problem.save
      return "\nProblem description imported from #{filename}."
    else
      return ''
    end
  end

  def import_problem_pdf(dirname)
    pdf_files = Dir["#{dirname}/*.pdf"]
    puts "CHECKING... #{dirname}"
    if pdf_files.length != 0
      puts "HAS PDF FILE"
      filename = pdf_files[0]

      @problem.save if not @problem.id
      out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
      if not FileTest.exists? out_dirname
        Dir.mkdir out_dirname
      end

      out_filename = "#{out_dirname}/#{@problem.name}.pdf"

      if FileTest.exists? out_filename
        File.delete out_filename
      end

      File.rename(filename, out_filename)
      @problem.description_filename = "#{@problem.name}.pdf"
      @problem.save
      return "\nProblem pdf imported from #{filename}."
    else
      return ""
    end
  end

  #just set the full score to the total number of test case
  #it is not perfect but works on most normal use case
  def import_full_score(dirname)
    num = 0
    loop do 
      num += 1
      in_file = Dir["#{dirname}/#{num}*.in"]
      break if in_file.length == 0
    end
    full_score = (num - 1) * 10 
    @problem.full_score = full_score
    @problem.save
    return "\nFull score is set to #{full_score}."
  end

end
