/** * Information on matched way point * * @author ab */ package btools.memrouter; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; final class TrainSchedule { private static class TrainScheduleCron { long minutes; long hours; long dows; TrainScheduleCron( String value ) { StringTokenizer tk = new StringTokenizer( value, "_" ); minutes = parseElement( tk.nextToken() ); hours = parseElement( tk.nextToken() ); dows = parseElement( tk.nextToken() ); } private long parseElement( String s ) { if ( "*".equals( s ) ) { return Long.MAX_VALUE; } StringTokenizer tk = new StringTokenizer( s, "," ); long res = 0; while (tk.hasMoreTokens()) { String sub = tk.nextToken(); int start, end; int idx = sub.indexOf( '-' ); if ( idx < 0 ) { start = Integer.parseInt( sub ); end = start; } else { start = Integer.parseInt( sub.substring( 0, idx ) ); end = Integer.parseInt( sub.substring( idx + 1 ) ); } for ( int i = start; i <= end; i++ ) { res |= ( 1L << i ); } } return res; } boolean matches( int minute, int hour, int dow ) { return ( ( 1L << minute ) & minutes ) != 0 && ( ( 1L << hour ) & hours ) != 0 && ( ( 1L << dow ) & dows ) != 0; } } private List cronsPositive; private List cronsNegative; private Map> timeTable = new HashMap>(); public TrainSchedule( String cronstring ) { StringTokenizer tk = new StringTokenizer( cronstring, " " ); cronsPositive = new ArrayList(); cronsNegative = new ArrayList(); while (tk.hasMoreTokens()) { String prefix = tk.nextToken(); String value = tk.nextToken(); if ( "+".equals( prefix ) ) { cronsPositive.add( new TrainScheduleCron( value ) ); } else if ( "-".equals( prefix ) ) { cronsNegative.add( new TrainScheduleCron( value ) ); } else { // prefix is a calendar id, value a slash-separated time list List times = new ArrayList(); StringTokenizer tk3 = new StringTokenizer( value, "/" ); while( tk3.hasMoreTokens() ) { times.add( Integer.valueOf( time2Minute( tk3.nextToken() ) ) ); } Collections.sort( times ); timeTable.put( prefix, times ); } } } private static int time2Minute( String s ) { StringTokenizer tk = new StringTokenizer( s, ":" ); int mins = 60 * Integer.parseInt( tk.nextToken() ); mins += Integer.parseInt( tk.nextToken() ); return mins; } public int getMinutesToNext( long timeFrom ) { if ( timeTable.isEmpty() ) { return getMinutesToNextCron( timeFrom ); } Calendar cal = Calendar.getInstance(); cal.setTime( new Date( timeFrom ) ); int minute = cal.get( Calendar.MINUTE ); int hour = cal.get( Calendar.HOUR_OF_DAY ); int year = cal.get( Calendar.YEAR ); int month = cal.get( Calendar.MONTH ) + 1; int day = cal.get( Calendar.DAY_OF_MONTH ); String sday = "" + ( year*10000 + month * 100 + day ); List alltimes = null; boolean listIsCopy = false; for( String calId : timeTable.keySet() ) { if ( calendarHasDate( calId, sday ) ) { List times = timeTable.get( calId ); if ( alltimes == null ) { alltimes = times; } else { if ( !listIsCopy ) { alltimes = new ArrayList( alltimes ); listIsCopy = true; } alltimes.addAll( times ); } } } if ( alltimes == null ) return -1; if ( listIsCopy ) { Collections.sort( alltimes ); } int mins = 60*hour + minute; for( Integer t : alltimes ) { if ( t.intValue() >= mins ) { return t.intValue() - mins; } } return -1; } private int getMinutesToNextCron( long timeFrom ) { Calendar cal = Calendar.getInstance(); cal.setTime( new Date( timeFrom ) ); int minute = cal.get( Calendar.MINUTE ); int hour = cal.get( Calendar.HOUR_OF_DAY ); int dow = cal.get( Calendar.DAY_OF_WEEK ); dow = dow > 1 ? dow - 1 : dow + 6; for ( int cnt = 0; cnt < 180; cnt++ ) { boolean veto = false; for ( TrainScheduleCron cron : cronsNegative ) { if ( cron.matches( minute, hour, dow ) ) { veto = true; break; } } if ( !veto ) { for ( TrainScheduleCron cron : cronsPositive ) { if ( cron.matches( minute, hour, dow ) ) return cnt; } } if ( ++minute == 60 ) { minute = 0; if ( ++hour == 24 ) { hour = 0; if ( ++dow == 8 ) { dow = 1; } } } } return -1; } private static Map> calendarMap; private static boolean calendarHasDate( String calId, String date ) { if ( calendarMap == null ) { try { readCalendar(); } catch (Exception e) { throw new RuntimeException( "cannot readcalendar: " + e ); } } Set idSet = calendarMap.get( calId ); if ( idSet != null ) { return idSet.contains( date ); } return true; } private static void readCalendar() throws Exception { System.out.println( "reading calendar..." ); calendarMap = new HashMap>(); Map uniqueMap = new HashMap(); BufferedReader br = new BufferedReader( new InputStreamReader( new FileInputStream( new File( "../calendar_dates.txt" ) ), "UTF-8" ) ); br.readLine(); // skip header for ( ;; ) { String line = br.readLine(); if ( line == null ) break; StringTokenizer tk = new StringTokenizer( line, "," ); String calId = tk.nextToken(); String calDate = tk.nextToken(); Set idSet = calendarMap.get( calId ); if ( idSet == null ) { idSet = new HashSet(); calendarMap.put( calId, idSet ); } String uniqueDate = uniqueMap.get( calDate ); if ( uniqueDate == null ) { uniqueDate = calDate; uniqueMap.put( uniqueDate, uniqueDate ); } idSet.add( uniqueDate ); } br.close(); System.out.println( "read calendar with " + calendarMap.size() + " ids" ); } }