/* eslint-disable max-len */
/**
* Created by dierickx.len on 20/01/2017.
*/
import curry from '../curry'
import isValidDate from './isValid'
import getWeek from './getWeek'
import { WEEKDAYS } from '../constants/WEEKDAYS'
import { MONTHS } from '../constants/MONTHS'
import { DATE_TOKENS } from '../constants/DATE_TOKENS'
// utility functions for the date formatting
const ZEROS = '00000000'
const lastN = curry((n, str) => str.substring(str.length - n, str.length))
const firstN = curry((n, str) => str.substring(0, n))
const fill = curry((digits, n) => lastN(digits, ZEROS + n))
const modCeiling = (mod, val) => val % mod || mod
// tokens map to get parts of the date /time
const tokens = {
YYYY: d => fill(4, d.getFullYear()),
YY: d => lastN(2, fill(4, d.getFullYear())),
MMMM: d => MONTHS[d.getMonth()],
MMM: d => firstN(3, MONTHS[d.getMonth()]),
MM: d => fill(2, d.getMonth() + 1),
M: d => d.getMonth() + 1,
w: d => getWeek(d),
ww: d => fill(2, getWeek(d)),
DD: d => fill(2, d.getDate()),
D: d => d.getDate(),
dddd: d => WEEKDAYS[d.getDay()],
ddd: d => firstN(3, WEEKDAYS[d.getDay()]),
dd: d => firstN(2, WEEKDAYS[d.getDay()]),
d: d => d.getDay(),
HH: d => fill(2, d.getHours()),
H: d => d.getHours(),
hh: d => fill(2, modCeiling(12, d.getHours())),
h: d => modCeiling(12, d.getHours()),
mm: d => fill(2, d.getMinutes()),
m: d => d.getMinutes(),
ss: d => fill(2, d.getSeconds()),
s: d => d.getSeconds(),
A: d => d.getHours() > 11 ? 'PM' : 'AM',
a: d => d.getHours() > 11 ? 'pm' : 'am',
SSS: d => fill(3, d.getMilliseconds()),
SS: d => firstN(2, fill(3, d.getMilliseconds())),
S: d => firstN(1, fill(3, d.getMilliseconds())),
Q: d => Math.ceil((d.getMonth() + 1) / 3)
}
// map this function to get the actual time/date value for each token
const swapTokenWithValue = curry((date, token) => {
return tokens[token] ? tokens[token](date) : token
})
/**
* @function formatDateTime
* @description Formats a date object using a format string
* @param {string} format - Format date string
* @param {date} date - Date object to format
* @return {string}
* @example
*
* const formattedDate = formatDateTime('DD-MM-YYYY', new Date('1999-12-31'))
* console.log(formattedDate) // 31-12-1999
*/
export default curry(function formatDateTime (format, date) {
// check for valid date
if (!isValidDate(date)) return 'Invalid Date' // return string
return format.match(DATE_TOKENS).map(swapTokenWithValue(date)).join('') // return joined string
})