module StewEucen::Acts::FertileForest::Table::Calculators

This module is for extending into derived class by ActiveRecord.
The caption contains “Instance Methods”, but it means “Class Methods” of each derived class. @private

Public Instance Methods

fill_required_columns_to_append!(node) click to toggle source
# File lib/fertile_forest/modules/calculators.rb, line 26
def fill_required_columns_to_append!(node)
  # calculate depth and queue for appending.
  # If no interval, try to scoot over queue.
  if node.ff_base_id.to_i <= 0
    fill_info = ff_calc_required_columns_for_appending_as_root(node)
  else
    fill_info = ff_calc_required_columns_for_appending_as_internal(node)
  end

  # When fail to calc, can not save.
  # no need to set error message here.
  return false if fill_info.blank?

  # not need to set ff_grove, because posted node has it already.
  node.ff_queue = fill_info[:ff_queue]
  node.ff_depth = fill_info[:ff_depth]

  true
end

Protected Instance Methods

ff_calc_median_queue(wedged_node) click to toggle source
# File lib/fertile_forest/modules/calculators.rb, line 174
def ff_calc_median_queue(wedged_node)
  tail_node = ff_get_previous_node(wedged_node)

  # tail_node never be null, because parent-node exists.
  return nil if tail_node.blank?

  tail_queue = tail_node.ff_queue
  wedged_queue = wedged_node.ff_queue

  return nil if wedged_queue - tail_queue <= 1

  # not need to use (int)
  (tail_queue + wedged_queue) / 2
end
ff_calc_required_columns_for_appending_as_internal(node) click to toggle source

Calculate depth and queue as internal node to append.

(1) has space before base-node, calc median queue.
(2) When no space befre base node, try to evenize.
(3) can not evenize, can not append.

@return [Hash] Calculated queue and depth. @return [false] Can not calculate.

# File lib/fertile_forest/modules/calculators.rb, line 112
def ff_calc_required_columns_for_appending_as_internal(node)
  base_id = node.ff_base_id.to_i
  grove_id = node.ff_grove.to_i

  # get base node by ff_base_id
  # use ff_grove for find, because grove means USER_ID
  base_node = ff_required_columns_scope()
    .ff_usual_conditions_scope(grove_id)
    .where(id: base_id)
    .first

  # When has ff_base_id and the node is nothing, fail to append.
  if base_node.blank?
    # TODO: set errors append.baseNodeIsNull
    return false
  end

  kinship = ff_parse_kinship(node)
  is_sibling = ff_is_bool(kinship)

  # depth is fixed value
  fill_info = {ff_depth: base_node.ff_depth.to_i + (is_sibling ? 0 : 1)}

  # pick up node for wedged node to scoot over. (can be null)
  wedged_node = ff_get_wedged_node(base_node, kinship)

  # When wedged node is nothing, it means last queue.
  # In the case, calc appending queue is "lastQueue + INTERVAL"

  if wedged_node.blank?
    last_queue = ff_get_last_queue(grove_id, 0)
    if last_queue < QUEUE_MAX_VALUE
      if QUEUE_DEFAULT_INTERVAL <= QUEUE_MAX_VALUE - last_queue
        calc_queue = last_queue + QUEUE_DEFAULT_INTERVAL
      else
        calc_queue = QUEUE_MAX_VALUE
      end

      return fill_info.merge({ff_queue: calc_queue})
    end
  else
    #
    # When got wedged node, calc median queue.
    #  (1) get previous node of the wedge node.
    #  (2) calc median queue.
    #
    append_queue = ff_calc_median_queue(wedged_node)

    return fill_info.merge({ff_queue: append_queue}) \
        if append_queue.present?
  end

  # When no space before wedged node, try to scoot over.
  append_queue = ff_evenize_for_appending(base_node, wedged_node)

  return fill_info.merge({ff_queue: append_queue}) \
      if append_queue.present?

  # TODO: set error message append.canNotScootsOver
  false
end
ff_calc_required_columns_for_appending_as_root(node) click to toggle source

Calculate depth and queue as root node to append. @return [Hash] Calculated queue and depth. @return [false] Can not calculate.

# File lib/fertile_forest/modules/calculators.rb, line 60
def ff_calc_required_columns_for_appending_as_root(node)
  # can be null=zero
  posted_grove = node.ff_grove.to_i

  # When append as root, need to post ff_grove.
  if has_grove? && posted_grove <= 0
    # TODO: set error message 'append_empty_column'
    return false
  end

  # depth is fixed value
  fill_info = {ff_depth: ROOT_DEPTH}

  ####################################################################
  #
  # calculate queue
  #

  # get max queue in grove
  last_queue = ff_get_last_queue(posted_grove)  # can be nil

  if last_queue.nil?
    append_queue = 0
  elsif QUEUE_MAX_VALUE <= last_queue
    # Try to scoot over pre-nodes.
    evenize_res = ff_evenize(posted_grove, nil, nil, 1) # 1: append node count

    # When fail to evenize, filled all id.
    if evenize_res.blank?
      # TODO: set error append.canNotScootsOver'
      return false
    end

    append_queue = evenize_res[SPROUT_VACANT_QUEUE_KEY]
  elsif QUEUE_MAX_VALUE - last_queue < QUEUE_DEFAULT_INTERVAL
    append_queue = QUEUE_MAX_VALUE
  else
    append_queue = last_queue + QUEUE_DEFAULT_INTERVAL
  end

  # return value
  fill_info.merge({ff_queue: append_queue})
end
ff_evenize_for_appending(base_node, wedged_node) click to toggle source
# File lib/fertile_forest/modules/calculators.rb, line 189
def ff_evenize_for_appending(base_node, wedged_node)
  append_node_count = 1

  grove_id     = base_node.ff_grove
  base_queue   = base_node.blank?   ? nil : base_node .ff_queue
  wedged_queue = wedged_node.blank? ? nil : wedged_node.ff_queue

  # try to evenize all pre-nodes from this base node.
  evenize_res = ff_evenize(grove_id, base_queue, wedged_queue, append_node_count)
  return evenize_res[SPROUT_VACANT_QUEUE_KEY] if evenize_res.present?

  # try to evenize all pre-nodes from this root node.
  # {
  #     $rootNode = $this->root($baseNode);
  #     $evenizeRes = $this->_evenize($grove, $rootNode, $wedgedQueue, $appendNodeCount);
  #     if (!empty($evenizeRes)) {
  #         return $evenizeRes[self::SPROUT_VACANT_QUEUE_KEY];
  #     }
  # }

  # try to evenize all pre-nodes.
  evenize_res = ff_evenize(grove_id, nil, wedged_queue, append_node_count)
  return evenize_res[SPROUT_VACANT_QUEUE_KEY] if evenize_res.present?

  # try to evenize all post-nodes.
  evenize_res = ff_evenize(grove_id, wedged_queue, nil, append_node_count, true)
  return evenize_res[SPROUT_VACANT_QUEUE_KEY] if evenize_res.present?

  # can not evenize.
  false
end
ff_parse_kinship(node) click to toggle source
# File lib/fertile_forest/modules/calculators.rb, line 46
def ff_parse_kinship(node)
  ff_kinship_key = node.ff_kinship
  if /true|false/i.match(ff_kinship_key)
    ff_kinship_key === 'true'
  else
    ff_kinship_key.to_i
  end
end