// epoch = 0000-01-01 00:00:00 +0000
var time = use('internal/time')

var now           = time.now
var computer_zone = time.computer_zone
var computer_dst  = time.computer_dst

//delete time.now
//delete time.computer_zone
//delete time.computer_dst

time.second   = 1
time.minute   = 60
time.hour     = 3600
time.day      = 86400
time.week     = 604800

time.weekdays = [
  "Sunday", "Monday", "Tuesday",
  "Wednesday", "Thursday", "Friday", "Saturday"
]

time.monthstr = [
  "January", "February", "March", "April", "May", "June",
  "July", "August", "September", "October", "November", "December"
]

time.epoch = 1970

time.hour2minute    = function() { return time.hour / time.minute }
time.day2hour       = function() { return time.day  / time.hour }
time.minute2second  = function() { return time.minute / time.second }
time.week2day       = function() { return time.week / time.day }

time.yearsize = function yearsize(y) {
  if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) return 366
  return 365
}
time.isleap = function(y) { return time.yearsize(y) == 366 }

time.timecode = function(t) {
  var fps = 24
  var s = whole(t)
  var frac = t - s
  return `${s}:${whole(frac * fps)}`
}

time.monthdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

// convert seconds-since-epoch -> broken-down record
function time_record(_num, _zone, _dst) {
  var n = _num
  var z = _zone
  var d = _dst
  if (n == null) n = now()
  if (z == null) z = computer_zone()
  if (d == null) d = computer_dst()

  if (is_object(n)) return n

  var monthdays = array(time.monthdays)
  var rec = {
    second: 0, minute: 0, hour: 0,
    yday: 0, year: 0,
    weekday: 0, month: 0, day: 0,
    zone: z, dst: !!d,
    ce: "AD"
  }

  var offset = z + (d ? 1 : 0)
  n = n + offset * time.hour

  var hms = n % time.day
  var day = floor(n / time.day)
  if (hms < 0) { hms = hms + time.day; day = day - 1 }

  rec.second  = hms % time.minute
  var tmp     = floor(hms / time.minute)
  rec.minute  = tmp % time.minute
  rec.hour    = floor(tmp / time.minute)
  rec.weekday = (day + 4503599627370496 + 2) % 7

  var y = time.epoch
  if (day >= 0) {
    y = time.epoch
    while (day >= time.yearsize(y)) {
      day = day - time.yearsize(y)
      y = y + 1
    }
  } else {
    y = time.epoch
    while (day < 0) {
      y = y - 1
      day = day + time.yearsize(y)
    }
  }
  rec.year  = y
  rec.ce    = (y <= 0) ? "BC" : "AD"
  rec.yday  = day

  if (time.yearsize(y) == 366) monthdays[1] = 29
  var m = 0
  while (day >= monthdays[m]) {
    day = day - monthdays[m]
    m = m + 1
  }
  rec.month = m
  rec.day   = day + 1

  return rec
}

function time_number(_rec) {
  var r = _rec
  if (r == null) r = now()
  if (is_number(r)) return r

  var c      = 0
  var year   = r.year   || 0
  var hour   = r.hour   || 0
  var minute = r.minute || 0
  var second = r.second || 0
  var zone   = r.zone   || 0
  var dst    = r.dst    ? 1 : 0
  var yday   = r.yday   || 0

  var i = 0
  if (year > time.epoch) {
    i = time.epoch
    while (i < year) {
      c = c + time.day * time.yearsize(i)
      i = i + 1
    }
  } else if (year < time.epoch) {
    i = time.epoch - 1
    while (i > year) {
      c = c + time.day * time.yearsize(i)
      i = i - 1
    }
    c = c + (time.yearsize(year) - yday - 1) * time.day
    c = c + (time.day2hour()    - hour   - 1) * time.hour
    c = c + (time.hour2minute() - minute - 1) * time.minute
    c = c + time.minute2second() - second
    c = c + (zone + dst) * time.hour
    return -c
  }

  c = second
  c = c + minute * time.minute
  c = c + hour   * time.hour
  c = c + yday   * time.day
  c = c - (zone + dst) * time.hour

  return c
}

// text formatting
var default_fmt = "vB mB d hh:nn:ss a z y c"

function time_text(_num, _fmt, _zone, _dst) {
  var n = _num
  var f = _fmt
  var z = _zone
  var d = _dst
  if (n == null) n = now()
  if (f == null) f = default_fmt
  if (z == null) z = computer_zone()
  if (d == null) d = computer_dst()

  var rec = is_number(n) ? time_record(n, z, d) : n
  z = rec.zone
  d = rec.dst

  if (search(f, "a") != null) {
    if (rec.hour >= 13) { rec.hour = rec.hour - 12; f = replace(f, "a", "PM") }
    else if (rec.hour == 12) { f = replace(f, "a", "PM") }
    else if (rec.hour == 0) { rec.hour = 12; f = replace(f, "a", "AM") }
    else f = replace(f, "a", "AM")
  }

  var year = rec.year > 0 ? rec.year : rec.year - 1
  if (search(f, "c") != null) {
    if (year < 0) { year = abs(year); f = replace(f, "c", "BC") }
    else f = replace(f, "c", "AD")
  }

  var full_offset = z + (d ? 1 : 0)
  f = replace(f, "yyyy", text(year, "i4"))
  f = replace(f, "y", year)
  f = replace(f, "eee", rec.yday + 1)
  f = replace(f, "dd", text(rec.day, "i2"))
  f = replace(f, "d", rec.day)
  f = replace(f, "hh", text(rec.hour, "i2"))
  f = replace(f, "h", rec.hour)
  f = replace(f, "nn", text(rec.minute, "i2"))
  f = replace(f, "n", rec.minute)
  f = replace(f, "ss", text(rec.second, "i2"))
  f = replace(f, "s", rec.second)
  f = replace(f, "x", d ? "DST" : "")
  f = replace(f, "z", (full_offset >= 0 ? "+" : "") + text(full_offset))
  f = replace(f, /mm[^bB]/g, rec.month + 1)
  f = replace(f, /m[^bB]/g,  rec.month + 1)
  f = replace(f, /v[^bB]/g,  rec.weekday)
  f = replace(f, "mb", text(time.monthstr[rec.month], 0, 3))
  f = replace(f, "mB", time.monthstr[rec.month])
  f = replace(f, "vB", time.weekdays[rec.weekday])
  f = replace(f, "vb", text(time.weekdays[rec.weekday], 0, 3))

  return f
}

return { record: time_record, number: time_number, text: time_text }
