module Fugit::Nat

def assemble_cron(h)

def assemble_cron(h)
"ac: " + h.inspect
  s = []
  s << h[:sec] if h[:sec]
  s << h[:hms][1].join(',')
  s << h[:hms][0].join(',')
  s << (h[:dom] || '*') << (h[:mon] || '*') << (h[:dow] || '*')
  s << h[:tz] if h[:tz]
  Fugit::Cron.parse(s.join(' '))
end

def do_parse(s, opts={})

def do_parse(s, opts={})
  parse(s, opts) ||
  fail(ArgumentError.new("could not parse a nat #{s.inspect}"))
end

def eone(e); e1 = e[1]; e1 == 1 ? '*' : "*/#{e1}"; end

def eone(e); e1 = e[1]; e1 == 1 ? '*' : "*/#{e1}"; end

def parse(s, opts={})

def parse(s, opts={})
  return s if s.is_a?(Fugit::Cron) || s.is_a?(Fugit::Duration)
  return nil unless s.is_a?(String)
Raabro.pp(Parser.parse(s, debug: 3), colours: true)
 Raabro.pp(Parser.parse(s, debug: 1), colours: true)) rescue nil
  parse_crons(s, Parser.parse(s), opts)
end

def parse_at_elt(e, opts, h)

def parse_at_elt(e, opts, h)
  (h[:hms] ||= []).concat(e[1])
  l = h[:hms].last
  h[:sec] = l.pop if l.size > 2
end

def parse_crons(s, a, opts)

def parse_crons(s, a, opts)
  return nil unless a
  h = a
    .reverse
    .inject({}) { |r, e| send("parse_#{e[0]}_elt", e, opts, r); r }
      #
      # the reverse ensure that in "every day at five", the
      # "at five" is placed before the "every day" so that
      # parse_x_elt calls have the right sequence
  if f = h[:_fail]
    #fail ArgumentError.new(f)
    return nil
  end
  hms = h[:hms]
  hours = (hms || [])
    .uniq
    .inject({}) { |r, hm| (r[hm[1]] ||= []) << hm[0]; r }
    .inject({}) { |r, (m, hs)| (r[hs.sort] ||= []) << m; r }
    .to_a
    .sort_by { |hs, ms| -hs.size }
  if hours.empty?
    hours << (h[:dom] ? [ [ '0' ], [ '0' ] ] : [ [ '*' ], [ '*' ] ])
  end
  crons = hours
    .collect { |hm| assemble_cron(h.merge(hms: hm)) }
  fail ArgumentError.new(
    "multiple crons in #{s.inspect} " +
    "(#{crons.collect(&:original).join(' | ')})"
  ) if opts[:multi] == :fail && crons.size > 1
  if opts[:multi] == true || (opts[:multi] && opts[:multi] != :fail)
    crons
  else
    crons.first
  end
end

def parse_day_of_month_elt(e, opts, h)

def parse_day_of_month_elt(e, opts, h)
  h[:dom] = e[1..-1].join(',')
end

def parse_dow_list_elt(e, opts, h)

def parse_dow_list_elt(e, opts, h)
  h[:hms] ||= [ [ 0, 0 ] ]
  h[:dow] = e[1..-1].collect(&:to_s).sort.join(',')
end

def parse_dow_range_elt(e, opts, h)

def parse_dow_range_elt(e, opts, h)
  h[:hms] ||= [ [ 0, 0 ] ]
  h[:dow] = e[1] == e[2] ? e[1] : "#{e[1]}-#{e[2]}"
end

def parse_interval_elt(e, opts, h)

def parse_interval_elt(e, opts, h)
  e1 = e[1]
  case e[2]
  when 's', 'sec', 'second', 'seconds'
    h[:sec] = eone(e)
  when 'm', 'min', 'mins', 'minute', 'minutes'
    h[:hms] ||= [ [ '*', eone(e) ] ]
  when 'h', 'hour', 'hours'
    hms = h[:hms]
    if hms && hms.size == 1 && hms.first.first == '*'
      hms.first[0] = eone(e)
    elsif ! hms
      h[:hms] = [ [ eone(e), 0 ] ]
    end
  when 'd', 'day', 'days'
    h[:dom] = "*/#{e1}" if e1 > 1
    h[:hms] ||= [ [ 0, 0 ] ]
  when 'w', 'week', 'weeks'
    h[:_fail] = "cannot have crons for \"every #{e1} weeks\"" if e1 > 1
    h[:hms] ||= [ [ 0, 0 ] ]
    h[:dow] ||= 0
  when 'M', 'month', 'months'
    h[:_fail] = "cannot have crons for \"every #{e1} months\"" if e1 > 12
    h[:hms] ||= [ [ 0, 0 ] ]
    h[:dom] = 1
    h[:mon] = eone(e)
  when 'Y', 'y', 'year', 'years'
    h[:_fail] = "cannot have crons for \"every #{e1} years\"" if e1 > 1
    h[:hms] ||= [ [ 0, 0 ] ]
    h[:dom] = 1
    h[:mon] = 1
  end
end

def parse_on_elt(e, opts, h)

def parse_on_elt(e, opts, h)
  e1 = e[1]
  h[:dow] = e1[0]
  h[:hms] = [ e1[1] ]
  l = h[:hms].last
  h[:sec] = l.pop if l.size > 2
end

def parse_tz_elt(e, opts, h)

def parse_tz_elt(e, opts, h)
  h[:tz] = e[1]
end