153 lines
5.1 KiB
Scala
153 lines
5.1 KiB
Scala
import java.util.{ Calendar, GregorianCalendar }
|
|
import language.postfixOps
|
|
import collection.mutable.ListBuffer
|
|
|
|
object CalendarPrint extends App {
|
|
val locd = java.util.Locale.getDefault()
|
|
val cal = new GregorianCalendar
|
|
val monthsMax = cal.getMaximum(Calendar.MONTH)
|
|
|
|
def JDKweekDaysToISO(dn: Int) = {
|
|
val nday = dn - Calendar.MONDAY
|
|
if (nday < 0) (dn + Calendar.THURSDAY) else nday
|
|
}
|
|
|
|
def daysInMonth(year: Int, monthMinusOne: Int): Int = {
|
|
cal.set(year, monthMinusOne, 1)
|
|
cal.getActualMaximum(Calendar.DAY_OF_MONTH)
|
|
}
|
|
|
|
def namesOfMonths() = {
|
|
def f1(i: Int): String = {
|
|
cal.set(2013, i, 1)
|
|
cal.getDisplayName(Calendar.MONTH, Calendar.LONG, locd)
|
|
}
|
|
(0 to monthsMax) map f1
|
|
}
|
|
|
|
def offsets(year: Int): List[Int] = {
|
|
val months = cal.getMaximum(Calendar.MONTH)
|
|
def get1stDayOfWeek(i: Int) = {
|
|
cal.set(year, i, 1)
|
|
cal.get(Calendar.DAY_OF_WEEK)
|
|
}
|
|
(0 to monthsMax).toList map get1stDayOfWeek map { i => JDKweekDaysToISO(i) }
|
|
}
|
|
|
|
def headerNameOfDays() = {
|
|
val mdow = cal.getDisplayNames(Calendar.DAY_OF_WEEK, Calendar.SHORT, locd) // map days of week
|
|
val it = mdow.keySet.iterator
|
|
val keySet = new ListBuffer[String]
|
|
while (it.hasNext) keySet += it.next
|
|
(keySet.map { key => (JDKweekDaysToISO(mdow.get(key)), key.take(2))
|
|
}.sortWith(_._1 < _._1) map (_._2)).mkString(" ")
|
|
}
|
|
|
|
def getGregCal(year: Int) = {
|
|
{
|
|
|
|
def dayOfMonth(month: Int) = new Iterator[(Int, Int)] {
|
|
cal.set(year, month, 1)
|
|
var ldom = 0
|
|
|
|
def next() = {
|
|
val res = (cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH))
|
|
ldom = res._2
|
|
cal.roll(Calendar.DAY_OF_MONTH, true)
|
|
res
|
|
}
|
|
|
|
def hasNext() = (cal.get(Calendar.DAY_OF_MONTH) > ldom)
|
|
}
|
|
var ret: List[(Int, Int)] = Nil
|
|
for (i <- 0 to monthsMax) ret = ret ++ (dayOfMonth(i).toSeq)
|
|
(ret, offsets(year))
|
|
}
|
|
}
|
|
|
|
def printCalendar(calendar: (List[(Int, Int)], List[Int]),
|
|
headerList: List[String] = Nil,
|
|
printerWidth: Int = 80) = {
|
|
val mw = 20 // month width
|
|
val gwf = 2 // gap width fixed
|
|
val gwm = 2 // gap width minimum
|
|
val fgw = true
|
|
|
|
val arr = Array.ofDim[String](6, 7)
|
|
|
|
def limits(printerWidth: Int): (Int, Int, Int, Int, Int) = {
|
|
val pw = if (printerWidth < 20) 20 else if (printerWidth > 300) 300 else printerWidth
|
|
|
|
// months side by side, gaps sum minimum
|
|
val (msbs, gsm) = {
|
|
val x1 = {
|
|
val c = if (pw / mw > 12) 12 else pw / mw
|
|
val a = (c - 1)
|
|
if (c * mw + a * gwm <= pw) c else a
|
|
} match {
|
|
case 5 => 4
|
|
case a if (a > 6 && a < 12) => 6
|
|
case other => other
|
|
}
|
|
(x1, (x1 - 1) * gwm)
|
|
}
|
|
|
|
def getFGW(msbs: Int, gsm: Int) = { val r = (pw - msbs * mw - gsm) / 2; (r, gwf, r) } // fixed gap width
|
|
def getVGW(msbs: Int, gsm: Int) = pw - msbs * mw - gsm match { // variable gap width
|
|
case a if (a < 2 * gwm) => (a / 2, gwm, a / 2)
|
|
case b => { val x = (b + gsm) / (msbs + 1); (x, x, x) }
|
|
}
|
|
|
|
// left margin, gap width, right margin
|
|
val (lm, gw, rm) = if (fgw) getFGW(msbs, gsm) else getVGW(msbs, gsm)
|
|
(pw, msbs, lm, gw, rm)
|
|
} // def limits(
|
|
|
|
val (pw, msbs, lm, gw, rm) = limits(printerWidth)
|
|
val monthsList = (0 to monthsMax).map { m => calendar._1.filter { _._1 == m } }
|
|
val nom = namesOfMonths()
|
|
val hnod = headerNameOfDays
|
|
|
|
def fsplit(list: List[(Int, Int)]): List[String] = {
|
|
def fap(p: Int) = (p / 7, p % 7)
|
|
for (i <- 0 until 6) for (j <- 0 until 7) arr(i)(j) = " "
|
|
for (i <- 0 until list.size)
|
|
arr(fap(i + calendar._2(list(i)._1))._1)(fap(i + calendar._2(list(i)._1))._2) =
|
|
f"${(list(i)._2)}%2d"
|
|
arr.toList.map(_.foldRight("")(_ + " " + _))
|
|
}
|
|
val monthsRows = monthsList.map(fsplit)
|
|
|
|
def center(s: String, l: Int): String = {
|
|
(if (s.size >= l) s
|
|
else " " * ((l - s.size) / 2) + s + " " * ((l - s.size) / 2) + " ").substring(0, l)
|
|
}
|
|
|
|
val maxMonths = monthsMax + 1
|
|
|
|
val rowblocks = (1 to maxMonths / msbs).map { i =>
|
|
(0 to 5).map { j =>
|
|
val lb = new ListBuffer[String]
|
|
val k = (i - 1) * msbs
|
|
(k to k + msbs - 1).map { l => lb += monthsRows(l)(j) }
|
|
lb
|
|
}
|
|
}
|
|
|
|
val mheaders = (1 to maxMonths / msbs).
|
|
map { i => (0 to msbs - 1).map { j => center(nom(j + (i - 1) * msbs), 20) } }
|
|
val dowheaders = (1 to maxMonths / msbs).
|
|
map { i => (0 to msbs - 1).map { j => center(hnod, 20) } }
|
|
|
|
headerList.foreach(xs => println(center(xs + '\n', pw)))
|
|
(1 to 12 / msbs).foreach { i =>
|
|
println(" " * lm + mheaders(i - 1).foldRight("")(_ + " " * gw + _))
|
|
println(" " * lm + dowheaders(i - 1).foldRight("")(_ + " " * gw + _))
|
|
rowblocks(i - 1).foreach { xs => println(" " * lm + xs.foldRight("")(_ + " " * (gw - 1) + _)) }
|
|
println
|
|
}
|
|
} // def printCal(
|
|
|
|
printCalendar(getGregCal(1969), List("[Snoopy Picture]", "1969"))
|
|
printCalendar(getGregCal(1582), List("[Snoopy Picture]", "1582"), printerWidth = 132)
|
|
}
|