mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 17:21:38 -05:00
130 lines
3.5 KiB
Ruby
130 lines
3.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class Visits::Group
|
|
def initialize(time_threshold_minutes: 30, merge_threshold_minutes: 15)
|
|
@time_threshold_minutes = time_threshold_minutes
|
|
@merge_threshold_minutes = merge_threshold_minutes
|
|
@visits = []
|
|
@current_visit = nil
|
|
end
|
|
|
|
def call(points)
|
|
process_points(points.sort_by(&:timestamp))
|
|
finalize_current_visit
|
|
merge_visits
|
|
convert_to_hash
|
|
end
|
|
|
|
private
|
|
|
|
def process_points(sorted_points)
|
|
sorted_points.each { process_point(_1) }
|
|
end
|
|
|
|
def process_point(point)
|
|
point_time = point.timestamp
|
|
log_point_processing(point_time)
|
|
|
|
@current_visit.nil? ? start_new_visit(point_time, point) : handle_existing_visit(point_time, point)
|
|
end
|
|
|
|
def start_new_visit(point_time, point)
|
|
log_new_visit(point_time)
|
|
|
|
@current_visit = VisitDraft.new(point_time)
|
|
@current_visit.add_point(point)
|
|
end
|
|
|
|
def handle_existing_visit(point_time, point)
|
|
time_difference = calculate_time_difference(point_time)
|
|
log_time_difference(time_difference)
|
|
|
|
if time_difference <= @time_threshold_minutes
|
|
@current_visit.add_point(point)
|
|
else
|
|
finalize_current_visit
|
|
start_new_visit(point_time, point)
|
|
end
|
|
end
|
|
|
|
def calculate_time_difference(point_time)
|
|
(point_time - @current_visit.end_time) / 60.0
|
|
end
|
|
|
|
def finalize_current_visit
|
|
return if @current_visit.nil?
|
|
|
|
if @current_visit.valid?
|
|
log_valid_visit
|
|
@visits << @current_visit
|
|
else
|
|
log_invalid_visit
|
|
end
|
|
|
|
@current_visit = nil
|
|
end
|
|
|
|
def merge_visits
|
|
merged_visits = []
|
|
previous_visit = nil
|
|
|
|
@visits.each do |visit|
|
|
if previous_visit.nil?
|
|
previous_visit = visit
|
|
else
|
|
time_difference = (visit.start_time - previous_visit.end_time) / 60.0
|
|
|
|
if time_difference <= @merge_threshold_minutes
|
|
merge_visit(previous_visit, visit)
|
|
else
|
|
merged_visits << previous_visit
|
|
previous_visit = visit
|
|
end
|
|
end
|
|
end
|
|
|
|
merged_visits << previous_visit if previous_visit
|
|
@visits = merged_visits.sort_by(&:start_time)
|
|
end
|
|
|
|
def merge_visit(previous_visit, current_visit)
|
|
previous_visit.points.concat(current_visit.points)
|
|
previous_visit.end_time = current_visit.end_time
|
|
end
|
|
|
|
def convert_to_hash
|
|
@visits.each_with_object({}) do |visit, hash|
|
|
hash[format_time_range(visit)] = visit.points
|
|
end
|
|
end
|
|
|
|
def format_time_range(visit)
|
|
start_time = format_time(visit.start_time)
|
|
end_time = format_time(visit.end_time)
|
|
"#{start_time} - #{end_time}"
|
|
end
|
|
|
|
def format_time(timestamp)
|
|
Time.zone.at(timestamp).strftime('%Y-%m-%d %H:%M')
|
|
end
|
|
|
|
def log_point_processing(point_time)
|
|
Rails.logger.info("Processing point at #{format_time(point_time)}")
|
|
end
|
|
|
|
def log_new_visit(point_time)
|
|
Rails.logger.info("Starting new visit at #{format_time(point_time)}")
|
|
end
|
|
|
|
def log_time_difference(time_difference)
|
|
Rails.logger.info("Time difference: #{time_difference.round} minutes")
|
|
end
|
|
|
|
def log_valid_visit
|
|
Rails.logger.info("Ending visit from #{format_time(@current_visit.start_time)} to #{format_time(@current_visit.end_time)}, duration: #{@current_visit.duration_in_minutes} minutes, points: #{@current_visit.points.size}") # rubocop:disable Layout/LineLength
|
|
end
|
|
|
|
def log_invalid_visit
|
|
Rails.logger.info("Discarding visit from #{format_time(@current_visit.start_time)} to #{format_time(@current_visit.end_time)} (invalid, points: #{@current_visit.points.size}, duration: #{@current_visit.duration_in_minutes} minutes)") # rubocop:disable Layout/LineLength
|
|
end
|
|
end
|