/**
* Copyright (C) 2016 eBusiness Information
*
* This file is part of OSM Contributor.
*
* OSM Contributor is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OSM Contributor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OSM Contributor. If not, see <http://www.gnu.org/licenses/>.
*/
package io.jawg.osmcontributor.ui.adapters.parser;
import org.joda.time.LocalTime;
import org.joda.time.Period;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import io.jawg.osmcontributor.model.utils.OpeningHours;
/**
* @author Tommy Buonomo on 18/07/16.
*/
@Singleton
public class OpeningHoursValueParser implements ValueParser<List<OpeningHours>> {
public static final String NON_STOP = "24/7";
public static final String RANGE_SEP = "-";
public static final String RULE_SEP = ",";
public static final String HOURS_SEP = ", ";
public static final String DAYS_SEP = " ";
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormat.forPattern("kk:mm");
@Inject
public OpeningHoursValueParser() {
}
@Override
public String toValue(List<OpeningHours> openingHours) {
StringBuilder openingHoursBuilder = new StringBuilder();
for (OpeningHours o : openingHours) {
openingHoursBuilder.append(openingHoursBuilder.length() == 0 ? "" : HOURS_SEP);
openingHoursBuilder.append(toSingleValue(o));
}
return openingHoursBuilder.toString();
}
private StringBuilder toSingleValue(OpeningHours openingHours) {
StringBuilder hoursBuilder = new StringBuilder();
if (openingHours.getFromTime() == null && openingHours.getToTime() == null) {
return new StringBuilder("");
}
// Return 24/7 if opening hours id non-stop
if (isNonStop(openingHours)) {
return new StringBuilder(NON_STOP);
} else {
OpeningHours.Days[] days = openingHours.getDays();
StringBuilder daysBuilder = new StringBuilder();
for (int i = 0; i < days.length; i++) {
OpeningHours.Days d = days[i];
// Get the period in days
if (d != null) {
// A day is detected, look if this is a period by iterate the next days
String fromDay = d.getData();
String toDay = null;
i++;
while (i < days.length && days[i] != null) {
toDay = days[i].getData();
i++;
}
daysBuilder.append(daysBuilder.length() == 0 ? "" : RULE_SEP);
daysBuilder.append(fromDay);
if (toDay != null) {
// This is a period
daysBuilder.append(RANGE_SEP).append(toDay);
}
}
}
hoursBuilder.append(daysBuilder);
hoursBuilder.append(" ");
hoursBuilder.append(TIME_FORMATTER.print(openingHours.getFromTime()));
hoursBuilder.append(RANGE_SEP);
hoursBuilder.append(TIME_FORMATTER.print(openingHours.getToTime()));
}
return hoursBuilder;
}
public boolean isNonStop(OpeningHours openingHours) {
for (OpeningHours.Days b : openingHours.getDays()) {
if (b == null) {
return false;
}
}
return isNonStopHours(openingHours);
}
public boolean isNonStopHours(OpeningHours openingHours) {
if (openingHours.getFromTime().equals(openingHours.getToTime())) {
return true;
}
LocalTime diff = openingHours.getToTime().minus(new Period(openingHours.getFromTime().getHourOfDay(),
openingHours.getFromTime().getMinuteOfHour(), 0, 0));
return diff.minus(new Period(23, 50, 0, 0)).getMinuteOfHour() < 10;
}
@Override
public List<OpeningHours> fromValue(String value) {
if (value.trim().isEmpty()) {
return null;
}
List<OpeningHours> openingHoursList = new ArrayList<>();
String[] openingHours = value.split(HOURS_SEP);
for (String o : openingHours) {
if (!o.trim().isEmpty()) {
fromSingleValue(o, openingHoursList);
}
}
return openingHoursList;
}
public void fromSingleValue(String value, List<OpeningHours> openingHoursList) {
// TODO: 19/07/16 We,Fr-Sa 10:45-19:15, Tu,Sa-Su 05:30-17:30, We 08:00-18:00
OpeningHours openingHours = new OpeningHours();
openingHours.setAllDaysActivated(false);
String[] openingHoursValues = value.split(DAYS_SEP);
String daysPart = null;
String hoursPart = null;
if (value.equals("24/7")) {
daysPart = "Mo-Su";
hoursPart = "24:00-24:00";
} else if (openingHoursValues.length == 2) {
daysPart = openingHoursValues[0];
hoursPart = openingHoursValues[1];
} else if (openingHoursValues.length == 1) {
hoursPart = openingHoursValues[0];
}
if (daysPart != null) {
String[] dayPeriods = daysPart.split(RULE_SEP);
for (String period : dayPeriods) {
if (isPeriod(period)) {
OpeningHours.Days[] d = OpeningHours.Days.fromDatas(period.split(RANGE_SEP));
for (int i = d[0].ordinal(); i <= d[1].ordinal(); i++) {
openingHours.setDayActivated(i, true);
}
} else {
openingHours.setDayActivated(OpeningHours.Days.fromData(period).ordinal(), true);
}
}
}
if (hoursPart != null) {
String[] hours = hoursPart.split(",");
if (hours.length > 1) {
for (String hour : hours) {
value = daysPart + " " + hour;
fromSingleValue(value, openingHoursList);
}
} else {
String[] hourPeriod = hoursPart.split(RANGE_SEP);
LocalTime from = TIME_FORMATTER.parseLocalTime(hourPeriod[0]);
if (hourPeriod.length > 1) {
LocalTime to = TIME_FORMATTER.parseLocalTime(hourPeriod[1]);
openingHours.setToTime(to);
} else {
openingHours.setToTime(from.plusMinutes(5));
}
openingHours.setFromTime(from);
openingHoursList.add(openingHours);
}
}
//return openingHours;
}
@Override
public int getPriority() {
return ParserManager.PRIORITY_HIGH;
}
/**
* Return true if the days expression is a period
* For example 'Sa-Su' is a period, 'Tu' is not.
* @param period
* @return
*/
private boolean isPeriod(String period) {
return period.contains(RANGE_SEP);
}
}