
fr.lteconsulting.hexa.client.calendar.CalendarPeriodAssociative Maven / Gradle / Ivy
The newest version!
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
{
// Attributes
// list of untouching periods in chronological order
private List> periods = new ArrayList>(); // 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> getPeriods()
{
return periods;
}
// Setters
public void setPeriods( List> 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( p.getFrom(), p.getTo(), value ) );
}
}
// print string
public String Out()
{
String out = "";
for( int i = 0; i < periods.size(); i++ )
{
PeriodAssociative period = periods.get( i );
out += "[" + period.getFrom() + ";" + period.getTo() + "] => " + period.getValue() + "
";
}
return out;
}
// print string
public String OutEx( Printer printer )
{
String out = "";
for( int i = 0; i < periods.size(); i++ )
{
PeriodAssociative period = periods.get( i );
out += "[" + period.getFrom() + "->" + period.getTo() + "] => " + printer.print( period.getValue() ) + "
";
}
return out;
}
// adding two associative periods
public Boolean Add( CalendarPeriodAssociative period, AddFunction addFunction )
{
// combine les deux tableaux dans ordre croissant
List> combined = _Combine( periods, period.getPeriods() );
// merge overlapping periods
List> 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 periods = new ArrayList();
for( int i = 0; i < this.periods.size(); i++ )
{
PeriodAssociative 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 Extract( TestFunction testFunction )
{
List> _periods = new ArrayList>();
for( int i = 0; i < periods.size(); i++ )
{
PeriodAssociative test = periods.get( i );
if( testFunction.function( test.getValue() ) )
_periods.add( test );
}
CalendarPeriodAssociative res = new CalendarPeriodAssociative();
res.setPeriods( _periods );
return res;
}
// returns a new object that is the current object trimmed by the given
// $calendarPeriod
public CalendarPeriodAssociative Trim( CalendarPeriodAssociative calendarPeriod )
{
List> result = new ArrayList>();
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( 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 res = new CalendarPeriodAssociative();
res.setPeriods( result );
return res;
}
// combine two period arrays ordered by from date
private List> _Combine( List> periods1, List> periods2 )
{
List> result = new ArrayList>();
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> _Merge( List> periods, AddFunction addFunction )
{
int count = periods.size();
if( count == 0 )
return new ArrayList>();
if( count == 1 )
return periods;
List> result = new ArrayList>();
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> toAdd = new ArrayList>();
if( periods.get( 0 ).getFrom().compareTo( periods.get( 1 ).getFrom() ) < 0 )
{
PeriodAssociative created = new PeriodAssociative( 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( periods.get( 1 ).getFrom(), periods.get( 1 ).getTo(), r ) );
toAdd.add( new PeriodAssociative( 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( 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( periods.get( 1 ).getFrom(), periods.get( 0 ).getTo(), r ) );
toAdd.add( new PeriodAssociative( 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
{
public String print( T value );
}
public interface AddFunction
{
public T function( T a, T b );
}
public interface TestFunction
{
public Boolean function( T a );
}
public static class PeriodAssociative
{
// 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;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy