class Workpattern::Day

Attributes

first_working_minute[RW]
hours_per_day[RW]
last_working_minute[RW]
pattern[RW]

Public Class Methods

new(hours_per_day = HOURS_IN_DAY, type = WORK_TYPE) click to toggle source
# File lib/workpattern/day.rb, line 7
def initialize(hours_per_day = HOURS_IN_DAY, type = WORK_TYPE)
  @hours_per_day = hours_per_day
  @pattern = initial_day(type)
  set_first_and_last_minutes
end

Public Instance Methods

calc(a_date, a_duration) click to toggle source
# File lib/workpattern/day.rb, line 39
def calc(a_date, a_duration)
  if a_duration == 0
    return a_date, a_duration, SAME_DAY
  else
    return a_duration > 0 ? add(a_date, a_duration) : subtract(a_date, a_duration)
  end
end
resting?(hour, minute) click to toggle source
# File lib/workpattern/day.rb, line 35
def resting?(hour, minute)
  !working?(hour,minute)
end
set_resting(start_time, finish_time) click to toggle source
# File lib/workpattern/day.rb, line 13
def set_resting(start_time, finish_time)
  mask = resting_mask(start_time, finish_time)
  @pattern = @pattern & mask
  set_first_and_last_minutes
end
set_working(from_time, to_time) click to toggle source
# File lib/workpattern/day.rb, line 19
def set_working(from_time, to_time)
  @pattern = @pattern | working_mask(from_time, to_time)
  set_first_and_last_minutes
end
working?(hour, minute) click to toggle source
# File lib/workpattern/day.rb, line 29
def working?(hour, minute)
  mask = (2**((hour * 60) + minute))
  result = mask & @pattern
  mask == result
end
working_minutes(from_time = FIRST_TIME_IN_DAY, to_time = LAST_TIME_IN_DAY) click to toggle source
# File lib/workpattern/day.rb, line 24
def working_minutes(from_time = FIRST_TIME_IN_DAY, to_time = LAST_TIME_IN_DAY)
  section = @pattern & working_mask(from_time, to_time)
  section.to_s(2).count('1') 
end

Private Instance Methods

add(a_date, a_duration) click to toggle source
# File lib/workpattern/day.rb, line 49
def add(a_date, a_duration)
  minutes_left = working_minutes(a_date)
  if a_duration > minutes_left
    return [a_date, a_duration - minutes_left, NEXT_DAY]
  elsif a_duration < minutes_left
    return add_minutes(a_date, a_duration)
  else
    if working?(LAST_TIME_IN_DAY.hour, LAST_TIME_IN_DAY.min)
            return [a_date, 0, NEXT_DAY]
    else
      return_date = Time.gm(a_date.year, a_date.month, a_date.day, @last_working_minute.hour, @last_working_minute.min) + 60
            return [ return_date, 0, SAME_DAY]
    end
  end       
end
add_minutes(a_date, a_duration) click to toggle source
# File lib/workpattern/day.rb, line 65
def add_minutes(a_date, a_duration)
  elapsed_date = a_date + (a_duration * 60) - 60

  if working_minutes(a_date, elapsed_date) == a_duration
    return [elapsed_date += 60, 0, SAME_DAY]
  else
    begin
      elapsed_date += 60
    end while working_minutes(a_date, elapsed_date) != a_duration
          return [elapsed_date += 60, 0, SAME_DAY]
  end
end
first_minute() click to toggle source
# File lib/workpattern/day.rb, line 189
def first_minute
  if working?(FIRST_TIME_IN_DAY.hour, FIRST_TIME_IN_DAY.min)
    return FIRST_TIME_IN_DAY
  end

  top = minutes_in_time(LAST_TIME_IN_DAY)
  bottom = minutes_in_time(FIRST_TIME_IN_DAY)
  mark = top / 2

  not_done = true
  while not_done
  
    minutes = working_minutes(minutes_to_time(bottom), minutes_to_time(mark))
    if minutes > 1
      top = mark
            mark = mark - ((top - bottom) / 2)
    elsif minutes == 0
      bottom = mark
            mark = mark + (( top - bottom) / 2)
    elsif minutes == 1 && is_resting(mark)
      top = mark
      mark = mark - ((top - bottom) / 2)
    else
      not_done = false
    end  
    
    if mark == 1 && top == 1
      mark = 0
    end
  end
  
  minutes_to_time(mark)
end
initial_day(type = WORK_TYPE) click to toggle source
# File lib/workpattern/day.rb, line 107
def initial_day(type = WORK_TYPE)

  pattern = 2**((60 * @hours_per_day) + 1)

  if type == WORK_TYPE
    pattern = pattern - 1
  end
  
  pattern
end
is_resting(minutes) click to toggle source
# File lib/workpattern/day.rb, line 227
def is_resting(minutes)
  a_time =(minutes_to_time(minutes))
  resting?(a_time.hour, a_time.min)
end
last_minute() click to toggle source
# File lib/workpattern/day.rb, line 145
def last_minute
  if working?(LAST_TIME_IN_DAY.hour, LAST_TIME_IN_DAY.min)
    return LAST_TIME_IN_DAY
  end

  top = minutes_in_time(LAST_TIME_IN_DAY)
  bottom = minutes_in_time(FIRST_TIME_IN_DAY)
  mark = top / 2

  not_done = true
  while not_done
  
    minutes = working_minutes(minutes_to_time(mark), minutes_to_time(top))

    if minutes > 1
            bottom = mark
            mark = mark + ((top - bottom) / 2)

    elsif minutes == 0
      top = mark
            mark = mark - (( top - bottom) / 2)

    elsif minutes == 1 && is_resting(mark)
      bottom = mark
            mark = mark + ((top - bottom) / 2)

    else
            not_done = false
    
    end

    if mark == bottom #& last_mark != mark
            mark = mark + 1
    end  

    if mark == 1 && top == 1 
      mark = 0
    end

  end
  minutes_to_time(mark)

end
minutes_in_time(a_time) click to toggle source
# File lib/workpattern/day.rb, line 141
def minutes_in_time(a_time)
  (a_time.hour * 60) + a_time.min
end
minutes_to_time(minutes) click to toggle source
# File lib/workpattern/day.rb, line 223
def minutes_to_time(minutes)
  Time.gm(1963,6,10,minutes / 60, minutes - (minutes / 60 * 60))
end
resting_mask(start_time, finish_time) click to toggle source
# File lib/workpattern/day.rb, line 129
def resting_mask(start_time, finish_time)

  start = minutes_in_time(start_time)
  finish_clock = Clock.new(finish_time.hour, finish_time.min + 1) 

  mask = initial_day(REST_TYPE)
  if minutes_in_time(finish_time) != LAST_TIME_IN_DAY.minutes
    mask = mask | working_mask(finish_clock,LAST_TIME_IN_DAY)
  end       
  mask | ((2**start) - 1)
end
set_first_and_last_minutes() click to toggle source
# File lib/workpattern/day.rb, line 232
def set_first_and_last_minutes
  if working_minutes == 0
    @first_working_minute = nil
    @last_working_minute = nil
  else      
          @first_working_minute = first_minute
          @last_working_minute = last_minute
  end       
end
subtract(a_date, a_duration) click to toggle source
# File lib/workpattern/day.rb, line 78
def subtract(a_date, a_duration)
  minutes_left = working_minutes(FIRST_TIME_IN_DAY,a_date - 60)
  abs_duration = a_duration.abs
  if abs_duration > minutes_left
    return [a_date, a_duration + minutes_left, PREVIOUS_DAY]
  elsif abs_duration < minutes_left
    return subtract_minutes(a_date, abs_duration)
  else
    return [Time.gm(a_date.year,a_date.month,a_date.day,@first_working_minute.hour,@first_working_minute.min), 0, SAME_DAY]
  end       
end
subtract_minutes(a_date, abs_duration) click to toggle source
# File lib/workpattern/day.rb, line 90
def subtract_minutes(a_date, abs_duration)
  elapsed_date = a_date - (abs_duration * 60)
  if working_minutes(elapsed_date, a_date - 60) == abs_duration
    return [elapsed_date, 0, SAME_DAY]
  else
    a_date -= 60
    begin
      elapsed_date -= 60
    end while working_minutes(elapsed_date, a_date) != abs_duration
          return [elapsed_date, 0, SAME_DAY]
  end
end
working_day() click to toggle source
# File lib/workpattern/day.rb, line 103
def working_day
  2**((60 * @hours_per_day) +1) - 1
end
working_mask(start_time, finish_time) click to toggle source
# File lib/workpattern/day.rb, line 118
def working_mask(start_time, finish_time)

  start = minutes_in_time(start_time) 
  finish = minutes_in_time(finish_time) 

  mask = initial_day

  mask = mask - ((2**start) - 1)
  mask & ((2**(finish + 1)) -1)
end