<commit_before># == Schema Information
#
# Table name: content_nodes
#
#  id            :integer          not null, primary key
#  title         :string
#  slug          :string
#  subtitle      :string
#  headnote      :text
#  public        :boolean          default(TRUE), not null
#  casebook_id   :integer
#  ordinals      :integer          default([]), not null, is an Array
#  copy_of_id    :integer
#  is_alias      :boolean
#  resource_type :string
#  resource_id   :integer
#  created_at    :datetime         not null
#  updated_at    :datetime         not null
#

# Abstract class for anything that is a child node in a table of contents:
# Sections, Resources inherit from this
# - belongs to a root Casebook
# - has ordinals which are not empty
# - can be relocated in the table of contents, pushing siblings aside
# - inherits the collaborators of its Casebook
class Content::Child < Content::Node
  default_scope {where.not(casebook_id: nil)}

  validates_length_of :ordinals, minimum: 1
  validates_uniqueness_of :ordinals, scope: :casebook_id, if: :casebook_id?, message: 'are not unique'

  before_validation :move_siblings, if: :ordinals_changed?
  after_update :move_children, if: :saved_change_to_ordinals?
  after_save :reflow_casebook, if: :saved_change_to_ordinals?
  after_destroy :reflow_casebook

  belongs_to :casebook, class_name: 'Content::Casebook', inverse_of: :contents, required: true, touch: true

  has_many :collaborators, class_name: 'Content::Collaborator', primary_key: :casebook_id, foreign_key: :content_id
  include Content::Concerns::HasCollaborators

  def section
    if ordinals.length == 1
      casebook
    else
      casebook.contents.where(['ordinals = ARRAY[?]', ordinals[0..-2]])
      .first
    end
  end

  def ordinal_string
    ordinals.join I18n.t('content.show.ordinals-separator', '.')
  end

  # has a user-readable id consisting of ordinals, e.g.:
  # 2.1.3-further-considerations
  def to_param
    "#{ordinals.join '.'}-#{slug}"
  end

  private

  # moves siblings and niblings before validation
  def move_siblings
    siblings = get_siblings
    increment_siblings(siblings)
    logger.debug casebook.contents.reload.map &:ordinal_string
  end

  # if the Node at a has been reordered to before b, determine where a's children are now
  def reorder_index a, b
    if a.length < b.length
      if a.last <= b[a.length-1]
        a.length - 1
      end
    elsif a.length > b.length
      nil
    else
      a.zip(b).find_index {|ab| ab[0] < (ab[1] || 0)}
    end
  end

  # moves children and descendants after update
  def move_children
    adjusted_prior_ordinals = ordinals_before_last_save #ordinals_before_last_save is a built in method
    if (idx = reorder_index ordinals, adjusted_prior_ordinals)
      adjusted_prior_ordinals[idx] += 1# children have been incremented
    else
      ordinals_before_last_save # children are the same
    end
    casebook.contents
    .where(['ordinals[1:?] = ARRAY[?]', adjusted_prior_ordinals.length, adjusted_prior_ordinals]) # our descendants
    .update_all ['ordinals = ARRAY[?] || ordinals[?:array_length(ordinals, 1)]', ordinals, adjusted_prior_ordinals.length + 1]
    logger.debug casebook.contents.reload.map &:ordinal_string
  end

  def reflow_casebook
    casebook.reflow_contents
  end

  def get_siblings
    content = get_content
    content.where(['ordinals[?] >= ?', ordinals.length, ordinals.last])<commit_msg>Move method.<commit_after># == Schema Information
#
# Table name: content_nodes
#
#  id            :integer          not null, primary key
#  title         :string
#  slug          :string
#  subtitle      :string
#  headnote      :text
#  public        :boolean          default(TRUE), not null
#  casebook_id   :integer
#  ordinals      :integer          default([]), not null, is an Array
#  copy_of_id    :integer
#  is_alias      :boolean
#  resource_type :string
#  resource_id   :integer
#  created_at    :datetime         not null
#  updated_at    :datetime         not null
#

# Abstract class for anything that is a child node in a table of contents:
# Sections, Resources inherit from this
# - belongs to a root Casebook
# - has ordinals which are not empty
# - can be relocated in the table of contents, pushing siblings aside
# - inherits the collaborators of its Casebook
class Content::Child < Content::Node
  default_scope {where.not(casebook_id: nil)}

  validates_length_of :ordinals, minimum: 1
  validates_uniqueness_of :ordinals, scope: :casebook_id, if: :casebook_id?, message: 'are not unique'

  before_validation :move_siblings, if: :ordinals_changed?
  after_update :move_children, if: :saved_change_to_ordinals?
  after_save :reflow_casebook, if: :saved_change_to_ordinals?
  after_destroy :reflow_casebook

  belongs_to :casebook, class_name: 'Content::Casebook', inverse_of: :contents, required: true, touch: true

  has_many :collaborators, class_name: 'Content::Collaborator', primary_key: :casebook_id, foreign_key: :content_id
  include Content::Concerns::HasCollaborators

  def section
    if ordinals.length == 1
      casebook
    else
      casebook.contents.where(['ordinals = ARRAY[?]', ordinals[0..-2]])
      .first
    end
  end

  def ordinal_string
    ordinals.join I18n.t('content.show.ordinals-separator', '.')
  end

  # has a user-readable id consisting of ordinals, e.g.:
  # 2.1.3-further-considerations
  def to_param
    "#{ordinals.join '.'}-#{slug}"
  end

  private

  # moves siblings and niblings before validation
  def move_siblings
    siblings = get_siblings
    increment_siblings(siblings)
    logger.debug casebook.contents.reload.map &:ordinal_string
  end

  # moves children and descendants after update
  def move_children
    adjusted_prior_ordinals = ordinals_before_last_save #ordinals_before_last_save is a built in method
    if (idx = reorder_index ordinals, adjusted_prior_ordinals)
      adjusted_prior_ordinals[idx] += 1# children have been incremented
    else
      ordinals_before_last_save # children are the same
    end
    casebook.contents
    .where(['ordinals[1:?] = ARRAY[?]', adjusted_prior_ordinals.length, adjusted_prior_ordinals]) # our descendants
    .update_all ['ordinals = ARRAY[?] || ordinals[?:array_length(ordinals, 1)]', ordinals, adjusted_prior_ordinals.length + 1]
    logger.debug casebook.contents.reload.map &:ordinal_string
  end

  # if the Node at a has been reordered to before b, determine where a's children are now
  def reorder_index a, b
    if a.length < b.length
      if a.last <= b[a.length-1]
        a.length - 1
      end
    elsif a.length > b.length
      nil
    else
      a.zip(b).find_index {|ab| ab[0] < (ab[1] || 0)}
    end
  end

  def reflow_casebook
    casebook.reflow_contents
  end

  def get_siblings
    content = get_content
    content.where(['ordinals[?] >= ?', ordinals.length, ordinals.last])
{'fraction_non_alphanumeric': 0.09320924821870001, 'fraction_numerical': 0.005234840773593137, 'mean_word_length': 3.4402840542285347, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 7, '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': '4596307', 'n_tokens_mistral': 2254, 'n_tokens_neox': 2187, 'n_words': 612}