package com.github.mikhailerofeev.mars.calendar.model.values.time;
import org.joda.time.*;
/**
* Created by Anton on 11.04.2014.
*
*/
public class PlanetDateTime {
private DateTime timePoint;
private DateTime epoch;
private PlanetCalendar calendar;
private Duration solDuration;
private Integer year = null;
private Integer monthOfYear = null; // from 1 ...
private Integer solOfMonth = null; // from 1 ...
private Integer hourOfSol = null; // from 1 ...
private Integer minuteOfHour = null; // from 1 ...
private Integer secondOfMinute = null; // from 1 ...
private Integer week = null; // from 1 ...
public PlanetDateTime(DateTime timePoint, DateTime epoch, PlanetCalendar calendar, Duration solDuration) {
this.timePoint = timePoint;
this.epoch = epoch;
this.calendar = calendar;
this.solDuration = solDuration;
}
public PlanetDateTime(DateTime epoch, PlanetCalendar calendar, Duration solDuration, int year, int monthOfYear, int solOfMonth, int hourOfSol, int minuteOfHour, int secondOfMinute) {
this.epoch = epoch;
this.calendar = calendar;
this.year = year;
this.monthOfYear = monthOfYear;
this.solOfMonth = solOfMonth;
this.hourOfSol = hourOfSol;
this.minuteOfHour = minuteOfHour;
this.secondOfMinute = secondOfMinute;
MutableDateTime mutableTimePoint = new MutableDateTime(epoch);
mutableTimePoint.add(calendar.solsInLeapPeriod() * solDuration.getMillis());
int yearsUntilCurrentCalc = year - (year % calendar.getLeapPeriod().size());
while (yearsUntilCurrentCalc <= year) {
mutableTimePoint.add(calendar.solsInYear(yearsUntilCurrentCalc) * solDuration.getMillis());
++yearsUntilCurrentCalc;
}
--yearsUntilCurrentCalc;
for (int currentMonth = 0; currentMonth < monthOfYear - 1; ++currentMonth) {
mutableTimePoint.add(calendar.solsInMonth(yearsUntilCurrentCalc, monthOfYear) * solDuration.getMillis());
}
for (int currentSol = 0; currentSol < solOfMonth - 1; ++currentSol) {
mutableTimePoint.add(solDuration.getMillis());
}
for (int currentHour = 0; currentHour < hourOfSol; ++currentHour) {
mutableTimePoint.add(3600000);
}
for (int currentMinute = 0; currentMinute < minuteOfHour; ++currentMinute) {
mutableTimePoint.add(60000);
}
for (int currentSecond = 0; currentSecond < secondOfMinute; ++currentSecond) {
mutableTimePoint.add(1000);
}
timePoint = new DateTime(mutableTimePoint);
}
public Duration timeSinceEpoch() {
return new Duration(epoch, timePoint);
}
private double solsSinceEpoch() {
return timeSinceEpoch().getMillis() / solDuration.getMillis();
}
public long wholeSolsSinceEpoch() {
return (long)solsSinceEpoch();
}
public Duration durationSinceSolStart() {
return new Duration(timeSinceEpoch().getMillis() % solDuration.getMillis());
}
public DateTime toTerrestrial() {
return timePoint;
}
public DateTime getTimePoint() {
return timePoint;
}
public DateTime getEpoch() {
return epoch;
}
public PlanetCalendar getCalendar() {
return calendar;
}
public Duration getSolDuration() {
return solDuration;
}
/**
*
* @param year
* @return terrestrial duration of the specific year
*/
public Duration yearDuration(int year) {
return new Duration(solDuration.getMillis() * calendar.solsInYear(year));
}
public Duration monthDuration(int year, int month) {
return new Duration(solDuration.getMillis() * calendar.solsInMonth(year, month));
}
private void calcTime() {
long wholeSolsSinceEpoch = wholeSolsSinceEpoch();
long solsInLeapPeriod = calendar.solsInLeapPeriod();
int periodsSinceEpoch = (int)(wholeSolsSinceEpoch / solsInLeapPeriod);
year = periodsSinceEpoch * calendar.getLeapPeriod().size();
long solsElapsedUntilCurrentCalc = periodsSinceEpoch * solsInLeapPeriod;
// may need to be changed to 1 (instead of 0)
while (solsElapsedUntilCurrentCalc <= wholeSolsSinceEpoch) {
++year;
solsElapsedUntilCurrentCalc += calendar.solsInYear(year);
}
solsElapsedUntilCurrentCalc -= calendar.solsInYear(year);
//--year; // because we return the nearest PREVIOUS year, not the NEXT one (!!!)
// -- by now, the year is supposed to be calculated -- //
monthOfYear = 0;
while (solsElapsedUntilCurrentCalc <= wholeSolsSinceEpoch) { // <= -> <
solsElapsedUntilCurrentCalc += calendar.solsInMonth(year, monthOfYear);
++monthOfYear;
}
solsElapsedUntilCurrentCalc -= calendar.solsInMonth(year, monthOfYear);
// no need to decrement solOfMonth because it should start from 0 (!!!)
// -- by now, we have month -- //
solOfMonth = 1; // because it should start from 1
while (solsElapsedUntilCurrentCalc < wholeSolsSinceEpoch) {
++solOfMonth;
++solsElapsedUntilCurrentCalc;
}
// solOfMonth calculated
long secondsElapsedUntilCurrentCalc = solsElapsedUntilCurrentCalc * solDuration.getMillis() / 1000;
long totalSecondsElapsed = timeSinceEpoch().getStandardSeconds();
hourOfSol = 0;
while (secondsElapsedUntilCurrentCalc <= totalSecondsElapsed) {
secondsElapsedUntilCurrentCalc += 3600;
++hourOfSol;
}
secondsElapsedUntilCurrentCalc -= 3600;
--hourOfSol;
// hourOfSol calculated
minuteOfHour = 0;
while (secondsElapsedUntilCurrentCalc <= totalSecondsElapsed) {
secondsElapsedUntilCurrentCalc += 60;
++minuteOfHour;
}
secondsElapsedUntilCurrentCalc -= 60;
--minuteOfHour;
// minuteOfHour calculated
secondOfMinute = 0;
while (secondsElapsedUntilCurrentCalc < totalSecondsElapsed) {
++secondsElapsedUntilCurrentCalc;
++secondOfMinute;
}
// secondOfMinute calculated
// // kludges:
// if (hourOfSol == solDuration.getStandardHours()) hourOfSol = 0;
// if (minuteOfHour == 60) minuteOfHour = 0;
// if (secondOfMinute == 60) secondOfMinute = 0;
}
/**
* returns the year in the natural form
* @return
*/
public int getYear() {
if (year == null) calcTime();
return year;
}
/**
*
* @return month number starting from 1
*/
public int getMonthOfYear() {
if (monthOfYear == null) calcTime();
return monthOfYear;
}
/**
*
* @return month object (if you need month number use getMonthOfYear instead)
*/
public PlanetMonth getMonthObject() {
return calendar.getMonths().get(getMonthOfYear() - 1);
}
/**
*
* @return solOfMonth number starting with 1
*/
public int getSolOfMonth() {
if (solOfMonth == null) calcTime();
return solOfMonth;
}
@SuppressWarnings("UnusedDeclaration")
public int getHourOfDay() {
if (hourOfSol == null) calcTime();
return hourOfSol;
}
public int getMinuteOfHour() {
if (minuteOfHour == null) calcTime();
return minuteOfHour;
}
public int getSecondOfMinute() {
if (secondOfMinute == null) calcTime();
return secondOfMinute;
}
/**
*
* @return week number starting with 1
*/
public int getWeek(){
if (week == null) {
if (calendar.weekRestarts()) {
// we use solOfMonth minus one because getSolOfMonth returns the number of the solOfMonth for normal humans
// (i.e. starting from 1)
week = (getSolOfMonth() - 1) / calendar.getWeekSols().size() + 1;
} else {
week = (int)(wholeSolsSinceEpoch() / calendar.getWeekSols().size() + 1);
}
}
return week;
}
}