package fr.lteconsulting.hexa.client.calendar; import java.util.ArrayList; import java.util.List; import fr.lteconsulting.hexa.client.calendar.CalendarPeriod.Period; public class CalendarPeriodAssociative<T> { // Attributes // list of untouching periods in chronological order private List<PeriodAssociative<T>> periods = new ArrayList<PeriodAssociative<T>>(); // 0:from, // 1:to, // 2:value // Constructors public CalendarPeriodAssociative() { } // Laurent : Constructors added for commodity public CalendarPeriodAssociative( CalendarPeriod period, T value ) { Init( period, value ); } // Getters public List<PeriodAssociative<T>> getPeriods() { return periods; } // Setters public void setPeriods( List<PeriodAssociative<T>> p ) { periods = p; } // init from a CalendarPeriod with a value public void Init( CalendarPeriod period, T value ) { for( int i = 0; i < period.getPeriods().size(); i++ ) { Period p = period.getPeriods().get( i ); periods.add( new PeriodAssociative<T>( p.getFrom(), p.getTo(), value ) ); } } // print string public String Out() { String out = ""; for( int i = 0; i < periods.size(); i++ ) { PeriodAssociative<T> period = periods.get( i ); out += "[" + period.getFrom() + ";" + period.getTo() + "] => " + period.getValue() + "<br>"; } return out; } // print string public String OutEx( Printer<T> printer ) { String out = ""; for( int i = 0; i < periods.size(); i++ ) { PeriodAssociative<T> period = periods.get( i ); out += "[" + period.getFrom() + "->" + period.getTo() + "] => " + printer.print( period.getValue() ) + "<br>"; } return out; } // adding two associative periods public Boolean Add( CalendarPeriodAssociative<T> period, AddFunction<T> addFunction ) { // combine les deux tableaux dans ordre croissant List<PeriodAssociative<T>> combined = _Combine( periods, period.getPeriods() ); // merge overlapping periods List<PeriodAssociative<T>> result = _Merge( combined, addFunction ); if( result == null ) return null; // we should stop the MakeUpCalendarAssociative process periods = result; // to say we can continue... return true; } // returns the same but with no values, and with the periods merged public CalendarPeriod GetCalendarPeriod() { CalendarPeriod res = new CalendarPeriod(); List<Period> periods = new ArrayList<Period>(); for( int i = 0; i < this.periods.size(); i++ ) { PeriodAssociative<T> p = this.periods.get( i ); periods.add( new Period( p.getFrom(), p.getTo() ) ); } // use merge to merge jointed periods... res.setPeriods( res._Merge( periods ) ); return res; } // returns a CalendarPeriodAssociative objet corresponding to the periods // where $testFunction returned true public CalendarPeriodAssociative<T> Extract( TestFunction<T> testFunction ) { List<PeriodAssociative<T>> _periods = new ArrayList<PeriodAssociative<T>>(); for( int i = 0; i < periods.size(); i++ ) { PeriodAssociative<T> test = periods.get( i ); if( testFunction.function( test.getValue() ) ) _periods.add( test ); } CalendarPeriodAssociative<T> res = new CalendarPeriodAssociative<T>(); res.setPeriods( _periods ); return res; } // returns a new object that is the current object trimmed by the given // $calendarPeriod public CalendarPeriodAssociative<T> Trim( CalendarPeriodAssociative<T> calendarPeriod ) { List<PeriodAssociative<T>> result = new ArrayList<PeriodAssociative<T>>(); int count1 = periods.size(); int count2 = calendarPeriod.getPeriods().size(); int i = 0; int j = 0; while( i < count1 && j < count2 ) { // one of the periods begins after the end of the other if( periods.get( i ).getFrom().compareTo( calendarPeriod.getPeriods().get( j ).getTo() ) > 0 ) { // period 1 begins after period 2 finishes => period2 is // eliminated ! j++; } else if( calendarPeriod.getPeriods().get( j ).getFrom().compareTo( periods.get( i ).getTo() ) > 0 ) { // period 2 begins after end of period 1 => period 1 is eliminated // ! i++; } // after that test, we can assume there is a non-void intersection else { result.add( new PeriodAssociative<T>( CalendarFunctions.max_date( periods.get( i ).getFrom(), calendarPeriod.getPeriods().get( j ).getFrom() ), CalendarFunctions.min_date( periods.get( i ).getTo(), calendarPeriod.getPeriods().get( j ).getTo() ), periods.get( i ) .getValue() ) ); if( periods.get( i ).getTo().compareTo( calendarPeriod.getPeriods().get( j ).getTo() ) > 0 ) j++; else i++; } } CalendarPeriodAssociative<T> res = new CalendarPeriodAssociative<T>(); res.setPeriods( result ); return res; } // combine two period arrays ordered by from date private List<PeriodAssociative<T>> _Combine( List<PeriodAssociative<T>> periods1, List<PeriodAssociative<T>> periods2 ) { List<PeriodAssociative<T>> result = new ArrayList<PeriodAssociative<T>>(); int count1 = periods1.size(); int count2 = periods2.size(); int i = 0; int j = 0; while( i < count1 && j < count2 ) { if( periods1.get( i ).getFrom().compareTo( periods2.get( j ).getFrom() ) <= 0 ) { result.add( periods1.get( i ) ); i++; } else { result.add( periods2.get( j ) ); j++; } } while( i < count1 ) { result.add( periods1.get( i ) ); i++; } while( j < count2 ) { result.add( periods2.get( j ) ); j++; } return result; } // merge, that is combine overlapping periods private List<PeriodAssociative<T>> _Merge( List<PeriodAssociative<T>> periods, AddFunction<T> addFunction ) { int count = periods.size(); if( count == 0 ) return new ArrayList<PeriodAssociative<T>>(); if( count == 1 ) return periods; List<PeriodAssociative<T>> result = new ArrayList<PeriodAssociative<T>>(); while( periods.size() > 1 ) { if( periods.get( 1 ).getFrom().compareTo( periods.get( 0 ).getTo() ) > 0 ) { // period is disjointed, so forget the first period, add it // directly into the results result.add( periods.remove( 0 ) ); } else { List<PeriodAssociative<T>> toAdd = new ArrayList<PeriodAssociative<T>>(); if( periods.get( 0 ).getFrom().compareTo( periods.get( 1 ).getFrom() ) < 0 ) { PeriodAssociative<T> created = new PeriodAssociative<T>( periods.get( 0 ).getFrom(), CalendarFunctions.date_add_day( periods.get( 1 ).getFrom(), -1 ), periods.get( 0 ).getValue() ); toAdd.add( created ); } if( periods.get( 1 ).getTo().compareTo( periods.get( 0 ).getTo() ) < 0 ) { T r = addFunction.function( periods.get( 0 ).getValue(), periods.get( 1 ).getValue() ); if( r == null ) return null; toAdd.add( new PeriodAssociative<T>( periods.get( 1 ).getFrom(), periods.get( 1 ).getTo(), r ) ); toAdd.add( new PeriodAssociative<T>( CalendarFunctions.date_add_day( periods.get( 1 ).getTo(), 1 ), periods.get( 0 ).getTo(), periods.get( 0 ).getValue() ) ); } else if( periods.get( 1 ).getTo().equals( periods.get( 0 ).getTo() ) ) { T r = addFunction.function( periods.get( 0 ).getValue(), periods.get( 1 ).getValue() ); if( r == null ) return null; toAdd.add( new PeriodAssociative<T>( periods.get( 1 ).getFrom(), periods.get( 1 ).getTo(), r ) ); } else // $periods[1][1] > $periods[0][1] { T r = addFunction.function( periods.get( 0 ).getValue(), periods.get( 1 ).getValue() ); if( r == null ) return null; toAdd.add( new PeriodAssociative<T>( periods.get( 1 ).getFrom(), periods.get( 0 ).getTo(), r ) ); toAdd.add( new PeriodAssociative<T>( CalendarFunctions.date_add_day( periods.get( 0 ).getTo(), 1 ), periods.get( 1 ).getTo(), periods.get( 1 ).getValue() ) ); } // periods 0 and 1 should be replaced by the newly calculated // $toAdd periods // remove periods 0 and 1 periods.remove( 0 ); periods.remove( 0 ); periods = _Combine( periods, toAdd ); } } if( periods.size() > 0 ) result.add( periods.remove( 0 ) ); return result; } // Additional Classes for Java (not in PHP source) @Override public String toString() { return periods.toString(); } // Interfaces public interface Printer<T> { public String print( T value ); } public interface AddFunction<T> { public T function( T a, T b ); } public interface TestFunction<T> { public Boolean function( T a ); } public static class PeriodAssociative<T> { // Attributes private String from = null; private String to = null; private T value = null; // Constructors PeriodAssociative() { } PeriodAssociative( String pFrom, String pTo ) { from = pFrom; to = pTo; } PeriodAssociative( String pFrom, String pTo, T pV ) { from = pFrom; to = pTo; value = pV; } // Getters public String getFrom() { return from; } public String getTo() { return to; } public T getValue() { return value; } // Setters public void setValue( T v ) { value = v; } // Public methods @Override public String toString() { String res = "[" + from + ":" + to + "] = " + value; return res; } } }