package com.aragaer.jtt;

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

import com.luckycatlabs.sunrisesunset.SunriseSunsetCalculator;
import com.luckycatlabs.sunrisesunset.dto.Location;

import android.support.v4.util.LongSparseArray;

public class JTT {
	LongSparseArray<long[]> cache = new LongSparseArray<long[]>();
	SunriseSunsetCalculator calculator;

	public JTT(float lat, float lon) {
		move(lat, lon);
	}

	public void move(float lat, float lon) {
		calculator = new SunriseSunsetCalculator(new Location(lat, lon), TimeZone.getDefault());
		cache.clear();
	}

	static final long ms_per_minute = TimeUnit.SECONDS.toMillis(60);
	static final long ms_per_hour = TimeUnit.SECONDS.toMillis(60 * 60);
	static final long ms_per_day = TimeUnit.SECONDS.toMillis(60 * 60 * 24);

	public JTTHour time_to_jtt(Date d) {
		return time_to_jtt(d == null ? System.currentTimeMillis() : d.getTime());
	}

	// wrapped jtt is jtt written as a single integer from range [0; 1200)
	public int time_to_jtt_wrapped(long time) {
		long day = longToJDN(time);
		long tr[] = computeTr(day);
		int dayAdd = 0;
		if (time > tr[1]) // "day" is actually yesterday
			tr = computeTr(++day);

		if (time < tr[0]) { // before sunrise. Get prev sunset (from cache apparently)
			tr[1] = tr[0];
			tr[0] = computeTr(day - 1)[1];
		} else if (time > tr[1]) { // after sunset. Get next sunrise
			tr[0] = tr[1];
			tr[1] = computeTr(day + 1)[0];
		} else {
			dayAdd = 600;
		}
		return (int) (600 * (time - tr[0]) / (tr[1] - tr[0]) + dayAdd);
	}

	public JTTHour time_to_jtt(long time) {
		long h = time_to_jtt_wrapped(time);
		return new JTTHour((int) (h / 100), (int) h % 100);
	}

	public Date jtt_to_time(JTTHour hour, Date date) {
		return jtt_to_time(hour.num, hour.fraction, date);
	}

	public Date jtt_to_time(int n, int f, Date date) {
		return jtt_to_time(n, f, date == null ? System.currentTimeMillis() : date.getTime());
	}

	// FIXME: this one isn't working properly
	public long wrapped_jtt_to_long(int n, long t) {
		long day = longToJDN(t);
		long tr[] = computeTr(day);
		if (n < 300) {// get prev sunset
			tr[1] = tr[0];
			tr[0] = computeTr(day - 1)[1];
		} else if (n > 799) {// get next sunrise
			tr[0] = tr[1];
			tr[1] = computeTr(day + 1)[0];
		}
		long offset = (tr[1] - tr[0]) * n / 600;

		return tr[0] + offset;
	}

	public long jtt_to_long(int n, int f, long t) {
		return wrapped_jtt_to_long(n * 100 + f, t);
	}

	public Date jtt_to_time(int n, int f, long t) {
		return new Date(jtt_to_long(n, f, t));
	}

	public static long longToJDN(long time) {
		return (int) Math.floor(longToJD(time));
	}

	private static double longToJD(long time) {
		return time / ((double) ms_per_day) + 2440587.5;
	}

	private static long JDToLong(double jd) {
		return Math.round((jd - 2440587.5) * ms_per_day);
	}

	// it's ok to call this function often since the data is cached
	public long[] computeTr(long jdn) {
		long result[] = cache.get(jdn);
		if (result == null) {
			Calendar date = Calendar.getInstance();
			date.setTimeInMillis(JDToLong(jdn));
			Calendar rise = calculator.getOfficialSunriseCalendarForDate(date);
			Calendar set = calculator.getOfficialSunsetCalendarForDate(date);
			result = new long[] { rise.getTimeInMillis(), set.getTimeInMillis() };
			cache.put(jdn, result);
		}
		return result;
	}
}

@@ -50,31 +50,8 @@
 ar;%0A
-import java.util.Date;%0A
 impo
@@ -847,22 +847,26 @@
 _to_jtt(
-Date d
+Calendar c
 ) %7B%0A%09%09re
@@ -882,17 +882,17 @@
 _to_jtt(
-d
+c
  == null
@@ -927,17 +927,17 @@
 ) : 
-d
+c
 .getTime
 ());
@@ -924,32 +924,40 @@
 is() : c.getTime
+InMillis
 ());%0A%09%7D%0A%0A%09// wra
@@ -1709,36 +1709,40 @@
 0);%0A%09%7D%0A%0A%09public 
-Date
+Calendar
  jtt_to_time(JTT
@@ -1752,25 +1752,28 @@
 r hour, 
-Date date
+Calendar cal
 ) %7B%0A%09%09re
@@ -1814,20 +1814,19 @@
 action, 
-date
+cal
 );%0A%09%7D%0A%0A%09
@@ -1824,36 +1824,40 @@
 l);%0A%09%7D%0A%0A%09public 
-Date
+Calendar
  jtt_to_time(int
@@ -1871,17 +1871,20 @@
  f, 
-Date date
+Calendar cal
 ) %7B%0A
@@ -1910,20 +1910,19 @@
 e(n, f, 
-date
+cal
  == null
@@ -1957,20 +1957,19 @@
 ) : 
-date
+cal
 .getTime
 ());
@@ -1964,16 +1964,24 @@
 .getTime
+InMillis
 ());%0A%09%7D%0A
@@ -2497,20 +2497,24 @@
 %09public 
-Date
+Calendar
  jtt_to_
@@ -2548,23 +2548,68 @@
 %7B%0A%09%09
-return new Date
+Calendar cal = Calendar.getInstance();%0A%09%09cal.setTimeInMillis
 (jtt
@@ -2624,24 +2624,38 @@
 (n, f, t));%0A
+%09%09return cal;%0A
 %09%7D%0A%0A%09public 

Use Calendar instead of Date everywhere