#--
# Copyright (c) 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