class GenerateSlugsRunner < JobRunner

  register_for_job_type('generate_slugs_job',
                        {:create_permissions => :administer_system,
                         :cancel_permissions => :administer_system,
                         :allow_reregister => true})

  def generate_slug_for(thing)
    slug = nil
    elapsed = Benchmark.measure do
      json_like_hash = thing.values

      # Repository always uses repo_code for slug
      if thing.class == Repository
        slug = SlugHelpers.clean_slug(json_like_hash[:repo_code])
      else
        slug = AppConfig[:auto_generate_slugs_with_id] ?
          SlugHelpers.id_based_slug_for(json_like_hash, thing.class) :
          SlugHelpers.name_based_slug_for(json_like_hash, thing.class)
      end
    end
    # silencing this for unit tests. Perhaps a more general solution for
    # turning on benchmarking by environment would be better
    unless [:unit_test].include? ASpaceEnvironment.environment
      puts "#{('Processed ' + slug).strip}: [#{thing.class}, #{thing[:id]}]\n#{elapsed}\n"
    end
    slug.parameterize
  end

  def run
    begin
      # SETUP
      @job.write_output("Resetting autogenerated slugs")
      @job.write_output("================================")
      SlugHelpers.job_running(status: true)
      SlugHelpers.reset_autogenerated_slugs

      # REPOSITORIES
      @job.write_output("Generating slugs for Repositories")
      @job.write_output("================================")

      Repository.each do |r|
        r[:slug] = "" if r[:slug].nil?

        next if !r[:slug].empty? && r[:is_slug_auto] == 0
        begin
          @job.write_output("Generating slug for repository id: #{r[:id]}")
          slug = generate_slug_for(r)

          if slug && !slug.empty?
            @job.write_output(" -> Slug for repository id: #{r[:id]} => #{slug}")
            r.update(:is_slug_auto => 1, :slug => slug)
          end

        rescue => e
          @job.write_output(" -> Error generating slug for id: #{r[:id]} => #{e.message}")
        end
      end

      # RESOURCES
      @job.write_output("Generating slugs for Resources")
      @job.write_output("================================")

      Resource.any_repo.order(:id).paged_each do |r|
        r[:slug] = "" if r[:slug].nil?

        next if !r[:slug].empty? && r[:is_slug_auto] == 0
        begin
          @job.write_output("Generating slug for resource id: #{r[:id]}")
          slug = generate_slug_for(r)

          if slug && !slug.empty?
            @job.write_output(" -> Slug for resource id: #{r[:id]} => #{slug}")
            r.update(:is_slug_auto => 1, :slug => slug)
          else
            @job.write_output(" -> Generated empty slug for: #{r[:id]}")
          end

        rescue => e
          @job.write_output(" -> Error generating slug for id: #{r[:id]} => #{e.message}")
        end
      end

      # ACCESSIONS
      @job.write_output("Generating slugs for Accessions")
      @job.write_output("================================")

      Accession.any_repo.order(:id).paged_each do |r|
        r[:slug] = "" if r[:slug].nil?

        next if !r[:slug].empty? && r[:is_slug_auto] == 0
        begin
          @job.write_output("Generating slug for accession id: #{r[:id]}")
          slug = generate_slug_for(r)

          if slug && !slug.empty?
            @job.write_output(" -> Slug for accession id: #{r[:id]} => #{slug}")
            r.update(:is_slug_auto => 1, :slug => slug)
          else
            @job.write_output(" -> Generated empty slug for: #{r[:id]}")
          end

        rescue => e
          @job.write_output(" -> Error generating slug for id: #{r[:id]} => #{e.message}")
        end
      end

      # DIGITAL OBJECTS
      @job.write_output("Generating slugs for Digital Objects")
      @job.write_output("================================")

      DigitalObject.any_repo.order(:id).paged_each do |r|
        r[:slug] = "" if r[:slug].nil?

        next if !r[:slug].empty? && r[:is_slug_auto] == 0
        begin
          @job.write_output("Generating slug for digital_object id: #{r[:id]}")
          slug = generate_slug_for(r)

          if slug && !slug.empty?
            @job.write_output(" -> Slug for digital_object id: #{r[:id]} => #{slug}")
            r.update(:is_slug_auto => 1, :slug => slug)
          else
            @job.write_output(" -> Generated empty slug for: #{r[:id]}")
          end

        rescue => e
          @job.write_output(" -> Error generating slug for id: #{r[:id]} => #{e.message}")
        end
      end

      # CLASSIFICATIONS
      @job.write_output("Generating slugs for Classifications")
      @job.write_output("================================")

      Classification.any_repo.order(:id).paged_each do |r|
        r[:slug] = "" if r[:slug].nil?

        next if !r[:slug].empty? && r[:is_slug_auto] == 0
        begin
          @job.write_output("Generating slug for classification id: #{r[:id]}")
          slug = generate_slug_for(r)

          if slug && !slug.empty?
            @job.write_output(" -> Slug for classification id: #{r[:id]} => #{slug}")
            r.update(:is_slug_auto => 1, :slug => slug)
          else
            @job.write_output(" -> Generated empty slug for: #{r[:id]}")
          end

        rescue => e
          @job.write_output(" -> Error generating slug for id: #{r[:id]} => #{e.message}")
        end
      end

      # CLASSIFICATION TERMS
      @job.write_output("Generating slugs for Classification Terms")
      @job.write_output("================================")

      ClassificationTerm.any_repo.order(:id).paged_each do |r|
        r[:slug] = "" if r[:slug].nil?

        next if !r[:slug].empty? && r[:is_slug_auto] == 0
        begin
          @job.write_output("Generating slug for classification_term id: #{r[:id]}")
          slug = generate_slug_for(r)

          if slug && !slug.empty?
            @job.write_output(" -> Slug for classification_term id: #{r[:id]} => #{slug}")
            r.update(:is_slug_auto => 1, :slug => slug)
          else
            @job.write_output(" -> Generated empty slug for: #{r[:id]}")
          end

        rescue => e
          @job.write_output(" -> Error generating slug for id: #{r[:id]} => #{e.message}")
        end
      end

      # AGENT - CORPORATE
      @job.write_output("Generating slugs for Agents (Corporate Entities)")
      @job.write_output("================================")

      AgentCorporateEntity.order(:id).paged_each do |r|
        r[:slug] = "" if r[:slug].nil?

        next if !r[:slug].empty? && r[:is_slug_auto] == 0
        begin
          @job.write_output("Generating slug for agent_corporate_entity id: #{r[:id]}")
          if AppConfig[:auto_generate_slugs_with_id]
            authority_id = NameAuthorityId.find(:name_corporate_entity_id => r.id)
            if !authority_id.nil?
              cleaned_slug = SlugHelpers.clean_slug(authority_id.values[:authority_id])
              slug = SlugHelpers.run_dedupe_slug(cleaned_slug)
            else
              slug = ''
            end
          else
            agent_name = NameCorporateEntity.find(:agent_corporate_entity_id => r.id)
            slug = generate_slug_for(agent_name)
          end

          if slug && !slug.empty?
            @job.write_output(" -> Slug for agent_corporate_entity id: #{r[:id]} => #{slug}")
            r.update(:is_slug_auto => 1, :slug => slug)
          else
            @job.write_output(" -> Generated empty slug for: #{r[:id]}")
          end

        rescue => e
          @job.write_output(" -> Error generating slug for id: #{r[:id]} => #{e.message}")
        end
      end

      # AGENT - FAMILY
      @job.write_output("Generating slugs for Agents (Family)")
      @job.write_output("================================")

      AgentFamily.order(:id).paged_each do |r|
        r[:slug] = "" if r[:slug].nil?
        next if !r[:slug].empty? && r[:is_slug_auto] == 0
        begin
          @job.write_output("Generating slug for agent_family id: #{r[:id]}")
          if AppConfig[:auto_generate_slugs_with_id]
            authority_id = NameAuthorityId.find(:name_family_id => r.id)
            if !authority_id.nil?
              cleaned_slug = SlugHelpers.clean_slug(authority_id.values[:authority_id])
              slug = SlugHelpers.run_dedupe_slug(cleaned_slug)
            else
              slug = ''
            end
          else
            agent_name = NameFamily.find(:agent_family_id => r.id)
            slug = generate_slug_for(agent_name)
          end

          if slug && !slug.empty?
            @job.write_output(" -> Slug for agent_family id: #{r[:id]} => #{slug}")
            r.update(:is_slug_auto => 1, :slug => slug)
          else
            @job.write_output(" -> Generated empty slug for: #{r[:id]}")
          end

        rescue => e
          @job.write_output(" -> Error generating slug for id: #{r[:id]} => #{e.message}")
        end
      end

      # AGENT - Person
      @job.write_output("Generating slugs for Agents (Person)")
      @job.write_output("================================")

      AgentPerson.order(:id).paged_each do |r|
        r[:slug] = "" if r[:slug].nil?

        next if !r[:slug].empty? && r[:is_slug_auto] == 0
        begin
          @job.write_output("Generating slug for agent_person id: #{r[:id]}")
          if AppConfig[:auto_generate_slugs_with_id]
            authority_id = NameAuthorityId.find(:name_person_id => r.id)
            if !authority_id.nil?
              cleaned_slug = SlugHelpers.clean_slug(authority_id.values[:authority_id])
              slug = SlugHelpers.run_dedupe_slug(cleaned_slug)
            else
              slug = ''
            end
          else
            agent_name = NamePerson.find(:agent_person_id => r.id)
            slug = generate_slug_for(agent_name)
          end

          if slug && !slug.empty?
            @job.write_output(" -> Slug for agent_person id: #{r[:id]} => #{slug}")
            r.update(:is_slug_auto => 1, :slug => slug)
          else
            @job.write_output(" -> Generated empty slug for: #{r[:id]}")
          end

        rescue => e
          @job.write_output(" -> Error generating slug for id: #{r[:id]} => #{e.message}")
        end
      end

      # AGENT - Software
      @job.write_output("Generating slugs for Agents (Software)")
      @job.write_output("================================")

      AgentSoftware.order(:id).paged_each do |r|
        r[:slug] = "" if r[:slug].nil?

        next if !r[:slug].empty? && r[:is_slug_auto] == 0
        begin
          @job.write_output("Generating slug for agent_software id: #{r[:id]}")
          if AppConfig[:auto_generate_slugs_with_id]
            authority_id = NameAuthorityId.find(:name_software_id => r.id)
            if !authority_id.nil?
              cleaned_slug = SlugHelpers.clean_slug(authority_id.values[:authority_id])
              slug = SlugHelpers.run_dedupe_slug(cleaned_slug)
            else
              slug = ''
            end
          else
            agent_name = NameSoftware.find(:agent_software_id => r.id)
            slug = generate_slug_for(agent_name)
          end

          if slug && !slug.empty?
            @job.write_output(" -> Slug for agent_software id: #{r[:id]} => #{slug}")
            r.update(:is_slug_auto => 1, :slug => slug)
          else
            @job.write_output(" -> Generated empty slug for: #{r[:id]}")
          end

        rescue => e
          @job.write_output(" -> Error generating slug for id: #{r[:id]} => #{e.message}")
        end
      end

      # SUBJECT
      @job.write_output("Generating slugs for Subjects")
      @job.write_output("================================")

      Subject.order(:id).paged_each do |r|
        r[:slug] = "" if r[:slug].nil?

        next if !r[:slug].empty? && r[:is_slug_auto] == 0
        begin
          @job.write_output("Generating slug for subject id: #{r[:id]}")
          slug = generate_slug_for(r)

          if slug && !slug.empty?
            @job.write_output(" -> Slug for subject id: #{r[:id]} => #{slug}")
            r.update(:is_slug_auto => 1, :slug => slug)
          else
            @job.write_output(" -> Generated empty slug for: #{r[:id]}")
          end

        rescue => e
          @job.write_output(" -> Error generating slug for id: #{r[:id]} => #{e.message}")
        end
      end

      # Archival Object
      @job.write_output("Generating slugs for Archival Objects")
      @job.write_output("================================")

      ArchivalObject.any_repo.order(:id).paged_each do |r|
        r[:slug] = "" if r[:slug].nil?

        next if !r[:slug].empty? && r[:is_slug_auto] == 0
        begin
          @job.write_output("Generating slug for archival_object id: #{r[:id]}")
          slug = generate_slug_for(r)

          if slug && !slug.empty?
            @job.write_output(" -> Slug for archival_object id: #{r[:id]} => #{slug}")
            r.update(:is_slug_auto => 1, :slug => slug)
          else
            @job.write_output(" -> Generated empty slug for: #{r[:id]}")
          end

        rescue => e
          @job.write_output(" -> Error generating slug for id: #{r[:id]} => #{e.message}")
        end
      end

      # Digital Object Component
      @job.write_output("Generating slugs for Digital Object Components")
      @job.write_output("================================")

      DigitalObjectComponent.any_repo.order(:id).paged_each do |r|
        r[:slug] = "" if r[:slug].nil?

        next if !r[:slug].empty? && r[:is_slug_auto] == 0
        begin
          @job.write_output("Generating slug for digital_object_component id: #{r[:id]}")
          slug = generate_slug_for(r)

          if slug && !slug.empty?
            @job.write_output(" -> Slug for digital_object_component id: #{r[:id]} => #{slug}")
            r.update(:is_slug_auto => 1, :slug => slug)
          else
            @job.write_output(" -> Generated empty slug for: #{r[:id]}")
          end

        rescue => e
          @job.write_output(" -> Error generating slug for id: #{r[:id]} => #{e.message}")
        end
      end

      SlugHelpers.job_running(status: false)
      self.success!
    rescue
      terminal_error = $!
    end

    if terminal_error
      @job.write_output(terminal_error.message)
      @job.write_output(terminal_error.backtrace)

      raise terminal_error
    end
  end
end
