– # Copyright © 2011 Michael Berkovich # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # “Software”), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++

namespace :platform do

desc "Initializes all of the tables with default data"
task :init => :environment do
  raise "This action is prohibited in this environment" if ['production', 'stage', 'staging'].include?(Rails.env) and env('force') != 'true'
  Tr8n::Config.reset_all!
  Platform::Config.reset_all!
end

task :rollup_metrics => :environment do
  # for debugging purposes

# Platform::RollupLog.delete_all # Platform::ApplicationMetric.delete_all # Platform::ApplicationUsageMetric.delete_all

  # when we bootstrap the process, we should havesome set date/time from where to start
  default_start_time = Time.parse("07/10/2011 12:00:00")

  if Platform::RollupLog.first == nil
    # running the rollup for the first time
    interval = interval_time_for(default_start_time)
  else
    last_rollup = Platform::RollupLog.last
    interval = interval_time_for(last_rollup.interval - 15.minutes) # always do the last interval and the current interval
  end

  rollup_interval(interval)
end

task :rollup_daily_metrics => :environment do
  start_date = ENV['since'] || Date.today.to_s
  start_date = Date.parse(start_date)
  end_date = Date.today

  while start_date <= end_date do
    log_msg("Rolling up daily metrics for #{start_date}...")

    Platform::Application.all.each do |app|
      Platform::DailyApplicationMetric.calculate_metric(app, start_date - 1.day)
      Platform::WeeklyApplicationMetric.calculate_metric(app, start_date - 1.week)
      Platform::MonthlyApplicationMetric.calculate_metric(app, start_date - 1.month)
      Platform::TotalApplicationMetric.calculate_metric(app, start_date)
    end

    start_date += 1.day
  end

  log_msg("Done.")
end

private

def rollup_interval(interval)
  interval_start = interval
  interval_end = interval_start + Platform::ApplicationUsageMetric.interval_duration

  log_msg("Rolling up interval: #{interval_start} - #{interval_end}...")

  rollup_log = Platform::RollupLog.create(:interval => interval, :started_at => Time.now)  

  # figure out which apps to calculates stats for. there is no point for having empty records.
  app_ids = Platform::Application.connection.select_values("select distinct application_id from platform_application_users where created_at >= '#{interval_start}' and created_at < '#{interval_end}'")
  app_ids += Platform::Application.connection.select_values("select distinct application_id from platform_application_logs where created_at >= '#{interval_start}' and created_at < '#{interval_end}'")

  log_msg("No applications to rollup") if app_ids.empty?

  # for each application
  app_ids.uniq.each do |app_id|
    app = Platform::Application.find_by_id(app_id)
    next unless app

    # process application metrics
    Platform::ApplicationMetric.calculate_metric(app, interval)

    # process application usage metrics - in 15 min chunks only - since it is summable
    Platform::ApplicationUsageMetric.calculate_metric(app, interval)
  end

  rollup_log.update_attributes(:finished_at => Time.now)

  now = Time.now
  if now >= interval_start && now < interval_end
    log_msg("Rolled up current interval. Going to sleep...")
  else  
    rollup_interval(interval + 15.minutes)
  end
end

def interval_time_for(time)
  Time.parse("#{time.year}-#{time.month}-#{time.day} #{time.hour}:#{((time.min / 15) * 15) }")
end

def log_msg(msg)
  pp "#{Time.now.strftime('%m/%d/%Y %H:%M:%S')}: #{msg}"    
end

end