Fixed formatting for file.

This commit is contained in:
GaidamakUA 2016-02-12 16:28:39 +02:00
parent 5dc376e891
commit 134c6de70b
2 changed files with 173 additions and 152 deletions

View file

@ -1,6 +1,6 @@
apply plugin: 'java'
apply plugin: 'application'
mainClassName = "net.osmand.util.GeoPointParserUtil"
mainClassName = "net.osmand.util.OpeningHoursParser"
sourceSets {
main {

View file

@ -12,15 +12,15 @@ import gnu.trove.list.array.TIntArrayList;
/**
* Class used to parse opening hours
*
* <p/>
* the method "parseOpenedHours" will parse an OSM opening_hours string and
* return an object of the type OpeningHours. That object can be used to check
* if the OSM feature is open at a certain time.
* if the OSM feature is open at a certain time.
*/
public class OpeningHoursParser {
private static final String[] daysStr = new String[] {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
private static final String[] monthsStr = new String[] {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
private static final String[] daysStr = new String[]{"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
private static final String[] monthsStr = new String[]{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
/**
* Default values for sunrise and sunset. Might be computed afterwards, not final.
*/
@ -28,125 +28,127 @@ public class OpeningHoursParser {
/**
* Hour of when you would expect a day to be ended.
* This is to be used when no end hour is known (like pubs that open at a certain time,
* This is to be used when no end hour is known (like pubs that open at a certain time,
* but close at a variable time, depending on the number of clients).
* OsmAnd needs to show a value, so there is some arbitrary default value chosen.
*/
private static String endOfDay = "24:00";
/**
* This class contains the entire OpeningHours schema and
* This class contains the entire OpeningHours schema and
* offers methods to check directly weather something is open
*
*
* @author sander
*/
public static class OpeningHours implements Serializable {
/**
* list of the different rules
*/
private ArrayList<OpeningHoursRule> rules;
/**
* Constructor
*
* @param rules List of OpeningHoursRule to be given
*
* @param rules List of OpeningHoursRule to be given
*/
public OpeningHours(ArrayList<OpeningHoursRule> rules) {
this.rules = rules;
}
/**
* Empty constructor
*/
public OpeningHours(){
public OpeningHours() {
rules = new ArrayList<OpeningHoursRule>();
}
/**
* add a rule to the opening hours
* @param r rule to add
*
* @param r rule to add
*/
public void addRule(OpeningHoursRule r){
public void addRule(OpeningHoursRule r) {
rules.add(r);
}
/**
* return the list of rules
*
*
* @return the rules
*/
public ArrayList<OpeningHoursRule> getRules(){
public ArrayList<OpeningHoursRule> getRules() {
return rules;
}
/**
* check if the feature is opened at time "cal"
* @param cal the time to check
*
* @param cal the time to check
* @return true if feature is open
*/
public boolean isOpenedForTime(Calendar cal){
public boolean isOpenedForTime(Calendar cal) {
/*
* first check for rules that contain the current day
* afterwards check for rules that contain the previous
* day with overlapping times (times after midnight)
*/
boolean isOpenDay = false;
for (OpeningHoursRule r : rules){
if(r.containsDay(cal) && r.containsMonth(cal)){
for (OpeningHoursRule r : rules) {
if (r.containsDay(cal) && r.containsMonth(cal)) {
isOpenDay = r.isOpenedForTime(cal, false);
}
}
boolean isOpenPrevious = false;
for (OpeningHoursRule r : rules){
if(r.containsPreviousDay(cal) && r.containsMonth(cal)){
for (OpeningHoursRule r : rules) {
if (r.containsPreviousDay(cal) && r.containsMonth(cal)) {
isOpenPrevious = r.isOpenedForTime(cal, true);
}
}
return isOpenDay || isOpenPrevious;
}
public String getCurrentRuleTime(Calendar cal) {
String ruleOpen = null;
String ruleClosed = null;
for (OpeningHoursRule r : rules){
if(r.containsPreviousDay(cal) && r.containsMonth(cal)){
if(r.isOpenedForTime(cal, true)) {
for (OpeningHoursRule r : rules) {
if (r.containsPreviousDay(cal) && r.containsMonth(cal)) {
if (r.isOpenedForTime(cal, true)) {
ruleOpen = r.toRuleString(true);
} else {
ruleClosed = r.toRuleString(true);
}
}
}
for (OpeningHoursRule r : rules){
if(r.containsDay(cal) && r.containsMonth(cal)){
if(r.isOpenedForTime(cal, false)) {
for (OpeningHoursRule r : rules) {
if (r.containsDay(cal) && r.containsMonth(cal)) {
if (r.isOpenedForTime(cal, false)) {
ruleOpen = r.toRuleString(true);
} else {
ruleClosed = r.toRuleString(true);
}
}
}
if(ruleOpen != null) {
if (ruleOpen != null) {
return ruleOpen;
}
return ruleClosed;
return ruleClosed;
}
@Override
public String toString(){
public String toString() {
StringBuilder s = new StringBuilder();
if (rules.isEmpty()) {
return "";
}
for (OpeningHoursRule r : rules) {
s.append(r.toString()).append("; ");
}
return s.substring(0, s.length()-2);
return s.substring(0, s.length() - 2);
}
public String toStringNoMonths() {
@ -159,61 +161,63 @@ public class OpeningHoursParser {
s.append(r.toRuleString(true)).append("; ");
}
return s.substring(0, s.length()-2);
return s.substring(0, s.length() - 2);
}
}
/**
* Interface to represent a single rule
*
* A rule consist out of
* - a collection of days/dates
* - a time range
* <p/>
* A rule consist out of
* - a collection of days/dates
* - a time range
*/
public static interface OpeningHoursRule extends Serializable {
/**
* Check if, for this rule, the feature is opened for time "cal"
* @param cal the time to check
*
* @param cal the time to check
* @param checkPrevious only check for overflowing times (after midnight) or don't check for it
* @return true if the feature is open
*/
public boolean isOpenedForTime(Calendar cal, boolean checkPrevious);
/**
* Check if the previous day before "cal" is part of this rule
* @param cal; the time to check
*
* @param cal; the time to check
* @return true if the previous day is part of the rule
*/
public boolean containsPreviousDay(Calendar cal);
/**
* Check if the day of "cal" is part of this rule
* @param cal the time to check
*
* @param cal the time to check
* @return true if the day is part of the rule
*/
public boolean containsDay(Calendar cal);
/**
* Check if the month of "cal" is part of this rule
*
*
* @param cal the time to check
* @return true if the month is part of the rule
*/
public boolean containsMonth(Calendar cal);
public String toRuleString(boolean avoidMonths);
}
/**
* implementation of the basic OpeningHoursRule
*
* <p/>
* This implementation only supports month, day of weeks and numeral times, or the value "off"
*
*/
public static class BasicOpeningHourRule implements OpeningHoursRule {
public static class BasicOpeningHourRule implements OpeningHoursRule {
/**
* represents the list on which days it is open.
* Day number 0 is MONDAY
@ -230,41 +234,45 @@ public class OpeningHoursParser {
* lists of equal size representing the start and end times
*/
private TIntArrayList startTimes = new TIntArrayList(), endTimes = new TIntArrayList();
/**
* return an array representing the days of the rule
*
* @return the days of the rule
*/
public boolean[] getDays() {
return days;
}
/**
* return an array representing the months of the rule
*
* @return the months of the rule
*/
public boolean[] getMonths() {
return months;
}
/**
* set a single start time, erase all previously added start times
*
* @param s startTime to set
*/
public void setStartTime(int s) {
setSingleValueForArrayList(startTimes, s);
if(endTimes.size() != 1) {
if (endTimes.size() != 1) {
setSingleValueForArrayList(endTimes, 0);
}
}
/**
* set a single end time, erase all previously added end times
*
* @param e endTime to set
*/
public void setEndTime(int e) {
setSingleValueForArrayList(endTimes, e);
if(startTimes.size() != 1) {
if (startTimes.size() != 1) {
setSingleValueForArrayList(startTimes, 0);
}
}
@ -275,7 +283,8 @@ public class OpeningHoursParser {
* If value is between 0 and last index, then value in the position p will be overwritten
* with new one.
* Else exception will be thrown.
* @param s - value
*
* @param s - value
* @param position - position to add
*/
public void setStartTime(int s, int position) {
@ -293,7 +302,8 @@ public class OpeningHoursParser {
* If value is between 0 and last index, then value in the position p will be overwritten
* with new one.
* Else exception will be thrown.
* @param s - value
*
* @param s - value
* @param position - position to add
*/
public void setEndTime(int s, int position) {
@ -304,13 +314,14 @@ public class OpeningHoursParser {
endTimes.set(position, s);
}
}
/**
* get a single start time
*
* @return a single start time
*/
public int getStartTime() {
if(startTimes.size() == 0) {
if (startTimes.size() == 0) {
return 0;
}
return startTimes.get(0);
@ -318,19 +329,21 @@ public class OpeningHoursParser {
/**
* get a single start time in position
*
* @param position position to get value from
* @return a single start time
*/
public int getStartTime(int position) {
return startTimes.get(position);
}
/**
* get a single end time
*
* @return a single end time
*/
public int getEndTime() {
if(endTimes.size() == 0) {
if (endTimes.size() == 0) {
return 0;
}
return endTimes.get(0);
@ -338,6 +351,7 @@ public class OpeningHoursParser {
/**
* get a single end time in position
*
* @param position position to get value from
* @return a single end time
*/
@ -347,6 +361,7 @@ public class OpeningHoursParser {
/**
* get all start times as independent list
*
* @return all start times
*/
public TIntArrayList getStartTimes() {
@ -355,19 +370,21 @@ public class OpeningHoursParser {
/**
* get all end times as independent list
*
* @return all end times
*/
public TIntArrayList getEndTimes() {
return new TIntArrayList(endTimes);
}
/**
* Check if the weekday of time "cal" is part of this rule
*
* @param cal the time to check
* @return true if this day is part of the rule
*/
@Override
public boolean containsDay(Calendar cal){
public boolean containsDay(Calendar cal) {
int i = cal.get(Calendar.DAY_OF_WEEK);
int d = (i + 5) % 7;
if (days[d]) {
@ -375,14 +392,15 @@ public class OpeningHoursParser {
}
return false;
}
/**
* Check if the previous weekday of time "cal" is part of this rule
*
* @param cal the time to check
* @return true if the previous day is part of the rule
*/
@Override
public boolean containsPreviousDay(Calendar cal){
public boolean containsPreviousDay(Calendar cal) {
int i = cal.get(Calendar.DAY_OF_WEEK);
int p = (i + 4) % 7;
if (days[p]) {
@ -390,10 +408,10 @@ public class OpeningHoursParser {
}
return false;
}
/**
* Check if the month of "cal" is part of this rule
*
*
* @param cal the time to check
* @return true if the month is part of the rule
*/
@ -405,12 +423,11 @@ public class OpeningHoursParser {
}
return false;
}
/**
* Check if this rule says the feature is open at time "cal"
*
* @param cal the time to check
* @return true if this rule contains the day to check and the start and end times denote it's open
* @return true if this rule contains the previous day and an endTime>startTime such that the time to check falls before the endtime
* @return false in all other cases, also if only day is wrong
*/
@Override
@ -445,13 +462,13 @@ public class OpeningHoursParser {
}
return false;
}
@Override
public String toRuleString(boolean avoidMonths) {
StringBuilder b = new StringBuilder(25);
// Month
boolean dash = false;
boolean dash = false;
boolean first = true;
if (!avoidMonths) {
for (int i = 0; i < 12; i++) {
@ -486,10 +503,10 @@ public class OpeningHoursParser {
}
appendDaysString(b);
// Time
if (startTimes == null || startTimes.size() == 0){
if (startTimes == null || startTimes.size() == 0) {
b.append(" off ");
} else {
for (int i = 0; i<startTimes.size(); i++) {
for (int i = 0; i < startTimes.size(); i++) {
int startTime = startTimes.get(i);
int endTime = endTimes.get(i);
if (open24_7 && startTime == 0 && endTime / 60 == 24) {
@ -506,7 +523,7 @@ public class OpeningHoursParser {
b.append(",");
}
}
return b.substring(0, b.length()-1);
return b.substring(0, b.length() - 1);
}
@Override
@ -515,7 +532,7 @@ public class OpeningHoursParser {
}
public void appendDaysString(StringBuilder builder) {
boolean dash = false;
boolean dash = false;
boolean first = true;
for (int i = 0; i < 7; i++) {
if (days[i]) {
@ -539,8 +556,9 @@ public class OpeningHoursParser {
/**
* Add a time range (startTime-endTime) to this rule
*
* @param startTime startTime to add
* @param endTime endTime to add
* @param endTime endTime to add
*/
public void addTimeRange(int startTime, int endTime) {
startTimes.add(startTime);
@ -605,32 +623,33 @@ public class OpeningHoursParser {
/**
* Parse an opening_hours string from OSM to an OpeningHours object which can be used to check
*
* @param r the string to parse
* @return BasicRule if the String is successfully parsed and UnparseableRule otherwise
*/
public static OpeningHoursParser.OpeningHoursRule parseRule(String r){
public static OpeningHoursParser.OpeningHoursRule parseRule(String r) {
// replace words "sunrise" and "sunset" by real hours
r = r.toLowerCase();
final String[] daysStr = new String[] {"mo", "tu", "we", "th", "fr", "sa", "su"};
final String[] monthsStr = new String[] {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"};
final String[] holidayStr = new String[] {"ph", "sh"};
final String[] daysStr = new String[]{"mo", "tu", "we", "th", "fr", "sa", "su"};
final String[] monthsStr = new String[]{"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"};
final String[] holidayStr = new String[]{"ph", "sh"};
String sunrise = "07:00";
String sunset = "21:00";
String endOfDay = "24:00";
String localRuleString = r.replaceAll("sunset", sunset).replaceAll("sunrise", sunrise)
.replaceAll("\\+", "-" + endOfDay);
int startDay = -1;
int previousDay = -1;
int startMonth = -1;
int startDay = -1;
int previousDay = -1;
int startMonth = -1;
int previousMonth = -1;
int k = 0; // Position in opening_hours string
int k = 0; // Position in opening_hours string
BasicOpeningHourRule basic = new BasicOpeningHourRule();
boolean[] days = basic.getDays();
boolean[] days = basic.getDays();
boolean[] months = basic.getMonths();
// check 24/7
if("24/7".equals(localRuleString)){
if ("24/7".equals(localRuleString)) {
Arrays.fill(days, true);
Arrays.fill(months, true);
basic.addTimeRange(0, 24 * 60);
@ -648,9 +667,9 @@ public class OpeningHoursParser {
// value "off" is found
break;
}
if(Character.isWhitespace(ch) || ch == ','){
if (Character.isWhitespace(ch) || ch == ',') {
} else if (ch == '-') {
if(previousDay != -1){
if (previousDay != -1) {
startDay = previousDay;
} else if (previousMonth != -1) {
startMonth = previousMonth;
@ -659,22 +678,22 @@ public class OpeningHoursParser {
}
} else if (k < r.length() - 1) {
int i = 0;
for(String s : daysStr){
if(s.charAt(0) == ch && s.charAt(1) == r.charAt(k+1)){
for (String s : daysStr) {
if (s.charAt(0) == ch && s.charAt(1) == r.charAt(k + 1)) {
break;
}
i++;
}
if(i < daysStr.length){
if(startDay != -1){
if (i < daysStr.length) {
if (startDay != -1) {
for (int j = startDay; j <= i; j++) {
days[j] = true;
}
if(startDay > i){// overflow handling, e.g. Su-We
if (startDay > i) {// overflow handling, e.g. Su-We
for (int j = startDay; j <= 6; j++) {
days[j] = true;
}
for (int j = 0; j <= i; j++){
for (int j = 0; j <= i; j++) {
days[j] = true;
}
}
@ -714,8 +733,8 @@ public class OpeningHoursParser {
}
if (previousMonth == -1) {
int h = 0;
for(String s : holidayStr){
if(s.charAt(0) == ch && s.charAt(1) == r.charAt(k+1)){
for (String s : holidayStr) {
if (s.charAt(0) == ch && s.charAt(1) == r.charAt(k + 1)) {
return new UnparseableRule(r);
}
}
@ -725,9 +744,9 @@ public class OpeningHoursParser {
return new UnparseableRule(r);
}
}
if(previousDay == -1){
if (previousDay == -1) {
// no days given => take all days.
for (int i = 0; i<7; i++){
for (int i = 0; i < 7; i++) {
days[i] = true;
}
}
@ -743,15 +762,15 @@ public class OpeningHoursParser {
for (int i = 0; i < times.length; i++) {
String time = times[i];
time = time.trim();
if(time.length() == 0){
if (time.length() == 0) {
continue;
}
if(time.equals("off")){
if (time.equals("off")) {
break; // add no time values
}
if(time.equals("24/7")){
if (time.equals("24/7")) {
// for some reason, this is used. See tagwatch.
basic.addTimeRange(0, 24*60);
basic.addTimeRange(0, 24 * 60);
break;
}
String[] stEnd = time.split("-"); //$NON-NLS-1$
@ -768,50 +787,50 @@ public class OpeningHoursParser {
int i1 = stEnd[0].indexOf(':');
int i2 = stEnd[1].indexOf(':');
int startHour, startMin, endHour, endMin;
if(i1 == -1) {
if (i1 == -1) {
// if no minutes are given, try complete value as hour
startHour = Integer.parseInt(stEnd[0].trim());
startMin = 0;
startMin = 0;
} else {
startHour = Integer.parseInt(stEnd[0].substring(0, i1).trim());
startMin = Integer.parseInt(stEnd[0].substring(i1 + 1).trim());
startMin = Integer.parseInt(stEnd[0].substring(i1 + 1).trim());
}
if(i2 == -1) {
if (i2 == -1) {
// if no minutes are given, try complete value as hour
endHour = Integer.parseInt(stEnd[1].trim());
endMin = 0;
endMin = 0;
} else {
endHour = Integer.parseInt(stEnd[1].substring(0, i2).trim());
endMin = Integer.parseInt(stEnd[1].substring(i2 + 1).trim());
endMin = Integer.parseInt(stEnd[1].substring(i2 + 1).trim());
}
st = startHour * 60 + startMin;
end = endHour * 60 + endMin;
st = startHour * 60 + startMin;
end = endHour * 60 + endMin;
} catch (NumberFormatException e) {
return new UnparseableRule(r);
}
basic.addTimeRange(st, end);
}
if(!timesExist){
if (!timesExist) {
return new UnparseableRule(r);
}
return basic;
}
/**
* parse OSM opening_hours string to an OpeningHours object
*
* @param format the string to parse
* @return the OpeningHours object when parsing was successful
* @return null when parsing was unsuccessful
*/
public static OpeningHours parseOpenedHours(String format){
if(format == null) {
public static OpeningHours parseOpenedHours(String format) {
if (format == null) {
return null;
}
// split the OSM string in multiple rules
String[] rules = format.split(";"); //$NON-NLS-1$
// FIXME: What if the semicolon is inside a quoted string?
OpeningHours rs = new OpeningHours();
for(String r : rules){
for (String r : rules) {
r = r.trim();
if (r.length() == 0) {
continue;
@ -830,16 +849,17 @@ public class OpeningHoursParser {
* parse OSM opening_hours string to an OpeningHours object.
* Does not return null when parsing unsuccessful. When parsing rule is unsuccessful,
* such rule is stored as UnparseableRule.
*
* @param format the string to parse
* @return the OpeningHours object
*/
public static OpeningHoursParser.OpeningHours parseOpenedHoursHandleErrors(String format){
if(format == null) {
public static OpeningHoursParser.OpeningHours parseOpenedHoursHandleErrors(String format) {
if (format == null) {
return null;
}
String[] rules = format.split(";"); //$NON-NLS-1$
OpeningHoursParser.OpeningHours rs = new OpeningHoursParser.OpeningHours();
for(String r : rules){
for (String r : rules) {
r = r.trim();
if (r.length() == 0) {
continue;
@ -849,8 +869,8 @@ public class OpeningHoursParser {
}
return rs;
}
private static void formatTime(int h, int t, StringBuilder b){
private static void formatTime(int h, int t, StringBuilder b) {
if (h < 10) {
b.append("0"); //$NON-NLS-1$
}
@ -860,12 +880,13 @@ public class OpeningHoursParser {
}
b.append(t);
}
/**
* test if the calculated opening hours are what you expect
* @param time the time to test in the format "dd.MM.yyyy HH:mm"
* @param hours the OpeningHours object
*
* @param time the time to test in the format "dd.MM.yyyy HH:mm"
* @param hours the OpeningHours object
* @param expected the expected state
*/
private static void testOpened(String time, OpeningHours hours, boolean expected) throws ParseException {
@ -874,9 +895,9 @@ public class OpeningHoursParser {
boolean calculated = hours.isOpenedForTime(cal);
System.out.printf(" %sok: Expected %s: %b = %b (rule %s)\n",
((calculated != expected) ? "NOT " : ""), time, expected, calculated, hours.getCurrentRuleTime(cal));
if(calculated != expected) {
throw new IllegalArgumentException("BUG!!!");
}
if (calculated != expected) {
throw new IllegalArgumentException("BUG!!!");
}
}
private static void testParsedAndAssembledCorrectly(String timeString, OpeningHours hours) {
@ -888,22 +909,22 @@ public class OpeningHoursParser {
throw new IllegalArgumentException("BUG!!!");
}
}
public static void main(String[] args) throws ParseException {
// Test basic case
OpeningHours hours = parseOpenedHours("Mo-Fr 08:30-14:40" ); //$NON-NLS-1$
OpeningHours hours = parseOpenedHours("Mo-Fr 08:30-14:40"); //$NON-NLS-1$
System.out.println(hours);
testOpened("09.08.2012 11:00", hours, true);
testOpened("09.08.2012 16:00", hours, false);
hours = parseOpenedHours("mo-fr 07:00-19:00; sa 12:00-18:00");
System.out.println(hours);
hours = parseOpenedHours("Mo-Fr 11:30-15:00,17:30-23:00; Sa-Su,PH 11:30-23:00");
System.out.println(hours);
testOpened("7.09.2015 14:54", hours, true);
testOpened("7.09.2015 15:05", hours, false);
// two time and date ranges
hours = parseOpenedHours("Mo-We, Fr 08:30-14:40,15:00-19:00"); //$NON-NLS-1$
@ -993,7 +1014,7 @@ public class OpeningHoursParser {
testOpened("11.05.2015 09:01", hours, true);
testOpened("12.05.2015 02:59", hours, true);
testOpened("12.05.2015 03:00", hours, false);
testOpened("16.05.2015 03:59", hours, true);
testOpened("16.05.2015 03:59", hours, true);
testOpened("16.05.2015 04:01", hours, false);
testOpened("17.05.2015 01:00", hours, true);
testOpened("17.05.2015 04:01", hours, false);
@ -1003,7 +1024,7 @@ public class OpeningHoursParser {
testOpened("11.05.2015 09:01", hours, false);
testOpened("12.05.2015 02:59", hours, false);
testOpened("12.05.2015 03:00", hours, false);
testOpened("16.05.2015 03:59", hours, true);
testOpened("16.05.2015 03:59", hours, true);
testOpened("16.05.2015 04:01", hours, false);
testOpened("17.05.2015 01:00", hours, true);
testOpened("17.05.2015 05:01", hours, false);