require 'rubygems'
require 'active_support/all'
require 'i18n'

class Time
  def self.diff(start_date, end_date, format_string='%y, %M, %w, %d and %h:%m:%s')
    #I18n.load_path += Dir.glob("lib/*.yml")
    start_time = start_date.to_time if start_date.respond_to?(:to_time)
    end_time = end_date.to_time if end_date.respond_to?(:to_time)
    distance_in_seconds = ((end_time - start_time).abs).round

    components = get_time_diff_components(%w(year month week day hour minute second), distance_in_seconds)
    time_diff_components = {:year => components[0], :month => components[1], :week => components[2], :day => components[3], :hour => components[4], :minute => components[5], :second => components[6]}

    formatted_intervals = get_formatted_intervals(format_string)
    components = get_time_diff_components(formatted_intervals, distance_in_seconds)
    formatted_components = create_formatted_component_hash(components, formatted_intervals)
    format_string = remove_format_string_for_zero_components(formatted_components, format_string)
    time_diff_components[:diff] = format_date_time(formatted_components, format_string) unless format_string.nil?
    return time_diff_components
  end

  def self.get_formatted_intervals(format_string)
    intervals = []
    [{'year' => '%y'}, {'month' => '%M'}, {'week' => '%w'}, {'day' => '%d'}].each do |component|
      key = component.keys.first
      value = component.values.first
      intervals << key if format_string.include?(value)
    end
    intervals << 'hour' if format_string.include?('%h') || format_string.include?('%H')
    intervals << 'minute' if format_string.include?('%m') || format_string.include?('%N')
    intervals << 'second' if format_string.include?('%s') || format_string.include?('%S')
    intervals
  end

  def self.create_formatted_component_hash(components, formatted_intervals)
    formatted_components = {}
    index = 0
    components.each do |component|
      formatted_components[:"#{formatted_intervals[index]}"] = component
      index = index + 1
    end
    formatted_components
  end

  def self.get_time_diff_components(intervals, distance_in_seconds)
    components = []
    intervals.each do |interval|
        component = (distance_in_seconds / 1.send(interval)).floor
        distance_in_seconds -= component.send(interval)
        components << component
    end
    components
  end

  def Time.format_date_time(time_diff_components, format_string)
    [{:year => '%y'}, {:month => '%M'}, {:week => '%w'}, {:day => '%d'}, {:hour => '%H'}, {:minute => '%N'}, {:second => '%S'}].each do |component|
      key = component.keys.first
      value = component.values.first
      format_string.gsub!(value, "#{time_diff_components[key]} #{pluralize(key.to_s, time_diff_components[key])}") if time_diff_components[key] 
    end
    [{:hour => '%h'},{:minute => '%m'},{:second => '%s'}].each do |component|
      key = component.keys.first
      value = component.values.first
      format_string.gsub!(value, format_digit(time_diff_components[key]).to_s) if time_diff_components[key]
    end
    format_string
  end

  def Time.pluralize(word, count)
    return count != 1 ? I18n.t(word.pluralize, :default => word.pluralize) : I18n.t(word, :default =>  word)
  end

  def Time.remove_format_string_for_zero_components(time_diff_components, format_string)
    [{:year => '%y'}, {:month => '%M'}, {:week => '%w'}].each do |component|
      key = component.keys.first
      value = component.values.first
      format_string.gsub!("#{value}, ",'') if time_diff_components[key] == 0
    end
    if time_diff_components[:day] == 0
      (format_string.slice(0..1) == '%d')? format_string.gsub!('%d ','') : format_string.gsub!(', %d','')
    end
    format_string.slice!(0..3) if format_string.slice(0..3) == 'and ' 
    format_string
  end

  def Time.format_digit(number)
    return '%02d' % number
  end
end
