<commit_before>module ProtocolsIoHelper
  #=============================================================================
  # Protocols.io limits
  #=============================================================================
  TEXT_MAX_LENGTH = Constants::TEXT_MAX_LENGTH

  PIO_ELEMENT_RESERVED_LENGTH_BIG = TEXT_MAX_LENGTH * 0.015
  PIO_ELEMENT_RESERVED_LENGTH_MEDIUM = TEXT_MAX_LENGTH * 0.01
  PIO_ELEMENT_RESERVED_LENGTH_SMALL = TEXT_MAX_LENGTH * 0.005

  # PROTOCOLS.IO PROTOCOL ATTRIBUTES
  PIO_P_AVAILABLE_LENGTH =
    TEXT_MAX_LENGTH -
    (PIO_ELEMENT_RESERVED_LENGTH_SMALL * 2 +
    PIO_ELEMENT_RESERVED_LENGTH_MEDIUM * 8 +
    PIO_ELEMENT_RESERVED_LENGTH_BIG * 2)
  # -- 2 small = created at , publish date PROTOCOL ATTRIBUTES
  # -- 8 medium = description,tags,before_start,warning,guidelines,
  # manuscript_citation,keywords,vendor_name PROTOCOL ATTRIBUTES
  # -- 2 big = vendor_link, link PROTOCOL ATTRIBUTES

  # PROTOCOLS.IO STEP ATTRIBUTES
  PIO_S_AVAILABLE_LENGTH =
    TEXT_MAX_LENGTH -
    (PIO_ELEMENT_RESERVED_LENGTH_SMALL * 20)
  # -- 20 small = description,expected_result,safety_information
  # software_package version, software_package os_name,
  # software_package os_version,software_package link,
  # software_package repository,software_package developer,software_package name
  # commands os_version,commands os_name, commands name,commands description,
  # sub protocol full name (author), sub protocol name, sub protocol link,
  # dataset link,dataset name, safety_information link,
  # -- 0 medium =
  # -- 0 big =

  PIO_TITLE_TOOLONG_LEN =
    I18n.t('protocols.protocols_io_import.title_too_long').length + 2
  PIO_STEP_TOOLONG_LEN =
    I18n.t('protocols.protocols_io_import.too_long').length
  # The + 2 above (in title) is there because if the length was at the limit,
  # the cutter method had issues, this gives it some space
  def protocolsio_string_to_table_element(description_string)
    string_without_tables = string_html_table_remove(description_string)
    table_regex = %r{<table\b[^>]*>(.*?)<\/table>}m
    tr_regex = %r{<tr\b[^>]*>(.*?)<\/tr>}m
    td_regex = %r{<td\b[^>]*>(.*?)<\/td>}m
    tables = {}
    table_strings = description_string.scan(table_regex)
    table_strings.each_with_index do |table, table_counter|
      tables[table_counter.to_s] = {}
      tr_strings = table[0].scan(tr_regex)
      contents = {}
      contents['data'] = []
      tr_strings.each_with_index do |tr, tr_counter|
        td_strings = tr[0].scan(td_regex)
        contents['data'][tr_counter] = []
        td_strings.each do |td|
          td_stripped = ActionController::Base.helpers.strip_tags(td[0])
          contents['data'][tr_counter].push(td_stripped)
        end
      end
      tables[table_counter.to_s]['contents'] = Base64.encode64(
        contents.to_s.sub('=>', ':')
      )
      tables[table_counter.to_s]['name'] = nil
    end
    # return string_without_tables, tables
    return tables, string_without_tables
  end

  def string_html_table_remove(description_string)
    description_string.remove!("\n", "\t", "\r", "\f")
    table_whole_regex = %r{(<table\b[^>]*>.*?<\/table>)}m
    table_pattern_array = description_string.scan(table_whole_regex)
    string_without_tables = description_string
    table_pattern_array.each do |table_pattern|
      string_without_tables = string_without_tables.gsub(
        table_pattern[0],
        t('protocols.protocols_io_import.comp_append.table_moved').html_safe
      )
    end
    string_without_tables
  end

  def pio_eval_prot_desc(text, attribute_name)
    case attribute_name
    when 'publish_date'
      pio_eval_len(text, ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_SMALL)
    when 'vendor_link', 'link'
      pio_eval_len(text, ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_BIG)
    else
      pio_eval_len(text, ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_MEDIUM)
    end
  end

  def pio_eval_title_len(text)
    if text
      text += ' ' if text.length < Constants::NAME_MIN_LENGTH
      if text.length > Constants::NAME_MAX_LENGTH
        text =
          text[0..(Constants::NAME_MAX_LENGTH - PIO_TITLE_TOOLONG_LEN)] +
          t('protocols.protocols_io_import.title_too_long')
        @toolong = true
      end
      text
    end
  end

  def pio_eval_len(text, reserved)
    if text
      text_end = reserved + @remaining - PIO_STEP_TOOLONG_LEN
      text_end = 2 if text_end < 2
      # Since steps have very low reserved values now (below 100),
      # the above sets their index to 1 if its negative
      # (length of toolong text is about 90 chars, and if remaining is 0,
      # then the negative index just gets set to 1. this is a workaround

      # it would also be possible to not count the length of the "too long" text
      # or setting the import reserved value to 95,but then available characters
      # will be like before (around 7600)
      if text.length - reserved > @remaining
        text =
          close_open_html_tags(
            text[0..text_end] + t('protocols.protocols_io_import.too_long')
          )
        @toolong = true
        @remaining = 0
      elsif (text.length - reserved) > 0
        @remaining -= text.length - reserved
      end
      text
    end
  end

  # Checks so that null values are returned as zero length strings
  # Did this so views arent as ugly (i avoid using if present statements)
  def not_null(attribute)
    if attribute
      attribute
    else
      ''
    end
  end

  def close_open_html_tags(text)
    Nokogiri::HTML::DocumentFragment.parse(text).to_html
  end

  def prepare_for_view(attribute_text, size)
    case size
    when 'small'
      pio_eval_len(
        sanitize_input(string_html_table_remove(not_null(attribute_text))),
        ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_SMALL
      )
    when 'medium'
      pio_eval_len(
        sanitize_input(string_html_table_remove(not_null(attribute_text))),
        ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_MEDIUM
      )
    when 'big'
      pio_eval_len(
        sanitize_input(string_html_table_remove(not_null(attribute_text))),
        ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_BIG
      )
    when 'small-no-table'
      pio_eval_len(
        sanitize_input(not_null(attribute_text)),
        ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_SMALL
      )
    when 'medium-no-table'
      pio_eval_len(
        sanitize_input(not_null(attribute_text)),
        ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_MEDIUM
      )
    when 'big-no-table'
      pio_eval_len(
        sanitize_input(not_null(attribute_text)),
        ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_BIG
      )
    end
  end

  def fill_attributes(attribute_name, attribute_text, step_component_key)
    output_string = ''
    trans_string = ''
    case step_component_key
    when '8'
      trans_string = 'protocols.protocols_io_import.comp_append.soft_packg.'
    when '9'
      trans_string = 'protocols.protocols_io_import.comp_append.dataset.'
    when '15'
      trans_string = 'protocols.protocols_io_import.comp_append.command.'
    when '18'
      trans_string = 'protocols.protocols_io_import.comp_append.sub_protocol.'
    when '19'
      trans_string = 'protocols.protocols_io_import.comp_append.safety_infor.'
    end
    trans_string +=
      if attribute_name != 'os_name' && attribute_name != 'os_version'
        attribute_name
      else
        'os'
      end
    output_string +=
      if attribute_name != 'os_version'
        t(trans_string)
      else
        ' , '
      end
    output_string += prepare_for_view(attribute_text, 'small-no-table')
    output_string
  end

  # pio_stp_x means protocols io step (id of component) parser
  def pio_stp_1(iterating_key) # protocols io description parser
    br = '<br>'
    append =
      if iterating_key.present?
        br +
        prepare_for_view(iterating_key, 'small-no-table') +
        br
      else
        t('protocols.protocols_io_import.comp_append.missing_desc')
      end
    append
  end

  def pio_stp_6(iterating_key) # protocols io section(title) parser
    return pio_eval_title_len(sanitize_input(iterating_key)) if iterating_key.present?
    t('protocols.protocols_io_import.comp_append.missing_step')
  end

  def pio_stp_17(iterating_key) # protocols io expected result parser
    if iterating_key.present?
      append =
        t('protocols.protocols_io_import.comp_append.expected_result') +
        prepare_for_view(iterating_key, 'small-no-table') +
        '<br>'
      return append
    end
    ''
  end

  def pio_stp_8(iterating_key) # protocols io software package parser
    if iterating_key['name'] &&
       iterating_key['developer'] &&
       iterating_key['version'] &&
       iterating_key['link'] &&
       iterating_key['repository'] &&
       iterating_key['os_name'] &&
       iterating_key['os_version']
      append = fill_attributes('name', iterating_key['name'], '8') +
               fill_attributes('developer', iterating_key['developer'], '8') +
               fill_attributes('version', iterating_key['version'], '8') +
               fill_attributes('link', iterating_key['link'], '8') +
               fill_attributes('repository', iterating_key['repository'], '8') +
               fill_attributes('os_name', iterating_key['os_name'], '8') +
               fill_attributes('os_version', iterating_key['os_version'], '8')
      return append
    end
    ''
  end

  def pio_stp_9(iterating_key) # protocols io dataset parser
    if iterating_key['name'].present? &&
       iterating_key['link']
      append = fill_attributes('name', iterating_key['name'], '9') +
               fill_attributes('link', iterating_key['link'], '9')
      return append
    end
    ''
  end

  def pio_stp_15(iterating_key) # protocols io commands parser
    if iterating_key['name'].present? &&
       iterating_key['description'] &&
       iterating_key['os_name'] &&
       iterating_key['os_version']
      append = fill_attributes('name', iterating_key['name'], '15') +
               fill_attributes('description', iterating_key['description'], '15') +
               fill_attributes('os_name', iterating_key['os_name'], '15') +
               fill_attributes('os_version', iterating_key['os_version'], '15')
      return append
    end
    ''
  end

  def pio_stp_18(iterating_key) # protocols io sub protocol parser
    if iterating_key['protocol_name'].present? &&
       iterating_key['full_name'] &&
       iterating_key['link']
      append = fill_attributes('protocol_name', iterating_key['protocol_name'], '18') +
               fill_attributes('full_name', iterating_key['full_name'], '18') +
               fill_attributes('link', iterating_key['link'], '18')
      return append
    end
    ''
  end

  def pio_stp_19(iterating_key) # protocols io safety information parser
    if iterating_key['body'].present? &&
       iterating_key['link']
      append = fill_attributes('body', iterating_key['body'], '19') +
               fill_attributes('link', iterating_key['link'], '19')
      return append
    end
    ''
  end

  def protocols_io_fill_desc(json_hash)
    description_array = %w[
      ( before_start warning guidelines manuscript_citation publish_date
      vendor_name vendor_link keywords tags link created_on )
    ]
    description_string =
      if json_hash['description'].present?
        '<strong>' + t('protocols.protocols_io_import.preview.description') +
          '</strong>' +<commit_msg>Simplified repeating method calls<commit_after>module ProtocolsIoHelper
  #=============================================================================
  # Protocols.io limits
  #=============================================================================
  TEXT_MAX_LENGTH = Constants::TEXT_MAX_LENGTH

  PIO_ELEMENT_RESERVED_LENGTH_BIG = TEXT_MAX_LENGTH * 0.015
  PIO_ELEMENT_RESERVED_LENGTH_MEDIUM = TEXT_MAX_LENGTH * 0.01
  PIO_ELEMENT_RESERVED_LENGTH_SMALL = TEXT_MAX_LENGTH * 0.005

  # PROTOCOLS.IO PROTOCOL ATTRIBUTES
  PIO_P_AVAILABLE_LENGTH =
    TEXT_MAX_LENGTH -
    (PIO_ELEMENT_RESERVED_LENGTH_SMALL * 2 +
    PIO_ELEMENT_RESERVED_LENGTH_MEDIUM * 8 +
    PIO_ELEMENT_RESERVED_LENGTH_BIG * 2)
  # -- 2 small = created at , publish date PROTOCOL ATTRIBUTES
  # -- 8 medium = description,tags,before_start,warning,guidelines,
  # manuscript_citation,keywords,vendor_name PROTOCOL ATTRIBUTES
  # -- 2 big = vendor_link, link PROTOCOL ATTRIBUTES

  # PROTOCOLS.IO STEP ATTRIBUTES
  PIO_S_AVAILABLE_LENGTH =
    TEXT_MAX_LENGTH -
    (PIO_ELEMENT_RESERVED_LENGTH_SMALL * 20)
  # -- 20 small = description,expected_result,safety_information
  # software_package version, software_package os_name,
  # software_package os_version,software_package link,
  # software_package repository,software_package developer,software_package name
  # commands os_version,commands os_name, commands name,commands description,
  # sub protocol full name (author), sub protocol name, sub protocol link,
  # dataset link,dataset name, safety_information link,
  # -- 0 medium =
  # -- 0 big =

  PIO_TITLE_TOOLONG_LEN =
    I18n.t('protocols.protocols_io_import.title_too_long').length + 2
  PIO_STEP_TOOLONG_LEN =
    I18n.t('protocols.protocols_io_import.too_long').length
  # The + 2 above (in title) is there because if the length was at the limit,
  # the cutter method had issues, this gives it some space
  def protocolsio_string_to_table_element(description_string)
    string_without_tables = string_html_table_remove(description_string)
    table_regex = %r{<table\b[^>]*>(.*?)<\/table>}m
    tr_regex = %r{<tr\b[^>]*>(.*?)<\/tr>}m
    td_regex = %r{<td\b[^>]*>(.*?)<\/td>}m
    tables = {}
    table_strings = description_string.scan(table_regex)
    table_strings.each_with_index do |table, table_counter|
      tables[table_counter.to_s] = {}
      tr_strings = table[0].scan(tr_regex)
      contents = {}
      contents['data'] = []
      tr_strings.each_with_index do |tr, tr_counter|
        td_strings = tr[0].scan(td_regex)
        contents['data'][tr_counter] = []
        td_strings.each do |td|
          td_stripped = ActionController::Base.helpers.strip_tags(td[0])
          contents['data'][tr_counter].push(td_stripped)
        end
      end
      tables[table_counter.to_s]['contents'] = Base64.encode64(
        contents.to_s.sub('=>', ':')
      )
      tables[table_counter.to_s]['name'] = nil
    end
    # return string_without_tables, tables
    return tables, string_without_tables
  end

  def string_html_table_remove(description_string)
    description_string.remove!("\n", "\t", "\r", "\f")
    table_whole_regex = %r{(<table\b[^>]*>.*?<\/table>)}m
    table_pattern_array = description_string.scan(table_whole_regex)
    string_without_tables = description_string
    table_pattern_array.each do |table_pattern|
      string_without_tables = string_without_tables.gsub(
        table_pattern[0],
        t('protocols.protocols_io_import.comp_append.table_moved').html_safe
      )
    end
    string_without_tables
  end

  def pio_eval_prot_desc(text, attribute_name)
    case attribute_name
    when 'publish_date'
      pio_eval_len(text, ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_SMALL)
    when 'vendor_link', 'link'
      pio_eval_len(text, ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_BIG)
    else
      pio_eval_len(text, ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_MEDIUM)
    end
  end

  def pio_eval_title_len(text)
    if text
      text += ' ' if text.length < Constants::NAME_MIN_LENGTH
      if text.length > Constants::NAME_MAX_LENGTH
        text =
          text[0..(Constants::NAME_MAX_LENGTH - PIO_TITLE_TOOLONG_LEN)] +
          t('protocols.protocols_io_import.title_too_long')
        @toolong = true
      end
      text
    end
  end

  def pio_eval_len(text, reserved)
    if text
      text_end = reserved + @remaining - PIO_STEP_TOOLONG_LEN
      text_end = 2 if text_end < 2
      # Since steps have very low reserved values now (below 100),
      # the above sets their index to 1 if its negative
      # (length of toolong text is about 90 chars, and if remaining is 0,
      # then the negative index just gets set to 1. this is a workaround

      # it would also be possible to not count the length of the "too long" text
      # or setting the import reserved value to 95,but then available characters
      # will be like before (around 7600)
      if text.length - reserved > @remaining
        text =
          close_open_html_tags(
            text[0..text_end] + t('protocols.protocols_io_import.too_long')
          )
        @toolong = true
        @remaining = 0
      elsif (text.length - reserved) > 0
        @remaining -= text.length - reserved
      end
      text
    end
  end

  # Checks so that null values are returned as zero length strings
  # Did this so views arent as ugly (i avoid using if present statements)
  def not_null(attribute)
    if attribute
      attribute
    else
      ''
    end
  end

  def close_open_html_tags(text)
    Nokogiri::HTML::DocumentFragment.parse(text).to_html
  end

  def prepare_for_view(attribute_text, size)
    case size
    when 'small'
      pio_eval_len(
        sanitize_input(string_html_table_remove(not_null(attribute_text))),
        ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_SMALL
      )
    when 'medium'
      pio_eval_len(
        sanitize_input(string_html_table_remove(not_null(attribute_text))),
        ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_MEDIUM
      )
    when 'big'
      pio_eval_len(
        sanitize_input(string_html_table_remove(not_null(attribute_text))),
        ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_BIG
      )
    when 'small-no-table'
      pio_eval_len(
        sanitize_input(not_null(attribute_text)),
        ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_SMALL
      )
    when 'medium-no-table'
      pio_eval_len(
        sanitize_input(not_null(attribute_text)),
        ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_MEDIUM
      )
    when 'big-no-table'
      pio_eval_len(
        sanitize_input(not_null(attribute_text)),
        ProtocolsIoHelper::PIO_ELEMENT_RESERVED_LENGTH_BIG
      )
    end
  end

  def fill_attributes(attribute_name, attribute_text, step_component_key)
    output_string = ''
    trans_string = ''
    case step_component_key
    when '8'
      trans_string = 'protocols.protocols_io_import.comp_append.soft_packg.'
    when '9'
      trans_string = 'protocols.protocols_io_import.comp_append.dataset.'
    when '15'
      trans_string = 'protocols.protocols_io_import.comp_append.command.'
    when '18'
      trans_string = 'protocols.protocols_io_import.comp_append.sub_protocol.'
    when '19'
      trans_string = 'protocols.protocols_io_import.comp_append.safety_infor.'
    end
    trans_string +=
      if attribute_name != 'os_name' && attribute_name != 'os_version'
        attribute_name
      else
        'os'
      end
    output_string +=
      if attribute_name != 'os_version'
        t(trans_string)
      else
        ' , '
      end
    output_string += prepare_for_view(attribute_text, 'small-no-table')
    output_string
  end

  # pio_stp_x means protocols io step (id of component) parser
  def pio_stp_1(iterating_key) # protocols io description parser
    br = '<br>'
    append =
      if iterating_key.present?
        br +
        prepare_for_view(iterating_key, 'small-no-table') +
        br
      else
        t('protocols.protocols_io_import.comp_append.missing_desc')
      end
    append
  end

  def pio_stp_6(iterating_key) # protocols io section(title) parser
    return pio_eval_title_len(sanitize_input(iterating_key)) if iterating_key.present?
    t('protocols.protocols_io_import.comp_append.missing_step')
  end

  def pio_stp_17(iterating_key) # protocols io expected result parser
    if iterating_key.present?
      append =
        t('protocols.protocols_io_import.comp_append.expected_result') +
        prepare_for_view(iterating_key, 'small-no-table') +
        '<br>'
      return append
    end
    ''
  end

  def pio_stp_8(iterating_key) # protocols io software package parser
    if iterating_key['name'] &&
       iterating_key['developer'] &&
       iterating_key['version'] &&
       iterating_key['link'] &&
       iterating_key['repository'] &&
       iterating_key['os_name'] &&
       iterating_key['os_version']
      append = ''
      parse_elements_array = %w(
        name developer version link repository os_name os_version
      )
      parse_elements_array.each do |element|
        append += fill_attributes(element, iterating_key[element], '8')
      end
      return append
    end
    ''
  end

  def pio_stp_9(iterating_key) # protocols io dataset parser
    if iterating_key['name'].present? &&
       iterating_key['link']
      append = ''
      parse_elements_array = %w(name link)
      parse_elements_array.each do |element|
        append += fill_attributes(element, iterating_key[element], '9')
      end
      return append
    end
    ''
  end

  def pio_stp_15(iterating_key) # protocols io commands parser
    if iterating_key['name'].present? &&
       iterating_key['description'] &&
       iterating_key['os_name'] &&
       iterating_key['os_version']
      append = ''
      parse_elements_array = %w(name description os_name os_version)
      parse_elements_array.each do |element|
        append += fill_attributes(element, iterating_key[element], '15')
      end
      return append
    end
    ''
  end

  def pio_stp_18(iterating_key) # protocols io sub protocol parser
    if iterating_key['protocol_name'].present? &&
       iterating_key['full_name'] &&
       iterating_key['link']
      append = ''
      parse_elements_array = %w(protocol_name full_name link)
      parse_elements_array.each do |element|
        append += fill_attributes(element, iterating_key[element], '18')
      end
      return append
    end
    ''
  end

  def pio_stp_19(iterating_key) # protocols io safety information parser
    if iterating_key['body'].present? &&
       iterating_key['link']
      append = ''
      parse_elements_array = %w(body link)
      parse_elements_array.each do |element|
        append += fill_attributes(element, iterating_key[element], '19')
      end
      return append
    end
    ''
  end

  def protocols_io_fill_desc(json_hash)
    description_array = %w[
      ( before_start warning guidelines manuscript_citation publish_date
      vendor_name vendor_link keywords tags link created_on )
    ]
    description_string =
      if json_hash['description'].present?
        '<strong>' + t('protocols.protocols_io_import.preview.description') +
          '</strong>' +
{'fraction_non_alphanumeric': 0.10841516579329781, 'fraction_numerical': 0.008322691443920912, 'mean_word_length': 3.3265383882644315, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6699424', 'n_tokens_mistral': 7425, 'n_tokens_neox': 7245, 'n_words': 1391}