im-router-update

This commit is contained in:
Arndt 2016-08-05 16:02:13 +02:00
parent cd8082f2b2
commit d277db0bd1
19 changed files with 1506 additions and 903 deletions

View file

@ -5,142 +5,278 @@
*/
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;
boolean isNegative;
String cronSource;
private static class TrainScheduleCron
{
long minutes;
long hours;
long dows;
TrainScheduleCron( String value )
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 ) )
{
StringTokenizer tk = new StringTokenizer( value, "_" );
minutes = parseElement( tk.nextToken() );
hours = parseElement( tk.nextToken() );
dows = parseElement( tk.nextToken() );
cronSource = value;
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<TrainScheduleCron> cronsPositive;
private List<TrainScheduleCron> cronsNegative;
private Map<String,List<Integer>> timeTable = new HashMap<String,List<Integer>>();
public TrainSchedule( String cronstring )
{
StringTokenizer tk = new StringTokenizer( cronstring, " " );
cronsPositive = new ArrayList<TrainScheduleCron>();
cronsNegative = new ArrayList<TrainScheduleCron>();
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<Integer> times = new ArrayList<Integer>();
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<Integer> alltimes = null;
boolean listIsCopy = false;
for( String calId : timeTable.keySet() )
{
if ( calendarHasDate( calId, sday ) )
{
List<Integer> times = timeTable.get( calId );
if ( alltimes == null )
{
alltimes = times;
}
else
{
if ( !listIsCopy )
{
alltimes = new ArrayList<Integer>( 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<String,Set<String>> calendarMap;
private static boolean calendarHasDate( String calId, String date )
{
if ( calendarMap == null )
{
try
{
readCalendar();
}
catch (Exception e)
{
throw new RuntimeException( "cannot readcalendar: " + e );
}
}
Set<String> 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<String,Set<String>>();
Map<String,String> uniqueMap = new HashMap<String,String>();
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();
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<TrainScheduleCron> cronsPositive;
private List<TrainScheduleCron> cronsNegative;
public TrainSchedule( String cronstring )
{
StringTokenizer tk = new StringTokenizer( cronstring, " " );
cronsPositive = new ArrayList<TrainScheduleCron>();
cronsNegative = new ArrayList<TrainScheduleCron>();
while ( tk.hasMoreTokens() )
{
String sign = tk.nextToken();
String value = tk.nextToken();
TrainScheduleCron cron = new TrainScheduleCron( value );
if ( "+".equals( sign ) )
{
cronsPositive.add( cron );
}
else if ( "-".equals( sign ) )
{
cronsNegative.add( cron );
}
else throw new IllegalArgumentException( "invalid cron sign: " + sign );
}
}
public int getMinutesToNext( 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 < 10080; 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;
}
Set<String> idSet = calendarMap.get( calId );
if ( idSet == null )
{
idSet = new HashSet<String>();
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" );
}
}