
fr.lteconsulting.hexa.client.calendar.Calendar Maven / Gradle / Ivy
The newest version!
package fr.lteconsulting.hexa.client.calendar;
import java.util.List;
import java.util.Stack;
/**
* Top Level Class parsing complex period expression and building CalendarPeriod
* objects
* Usage :
* Expression operators: '|' => union, '&' => intersection, '~' => not
* Expression operands : '[2013-06-12;2013-06-21]' period, 'd0' => day : 0 =
* Sunday, 6 = Saturday
* Expression is built in Reverse Polish Notation format.
* Example: Period from the 12 june 2013 to the 21 june 2013 except
* Sunday
* String expression = "[2013-06-12;2013-06-21] d0 ~ &";
* Tree tree = Calendar.get().Parse(expression);
*
* Special: MakupCalendarPeriodAssociative() see method description
*
* @author Arnaud, traduction Java Laurent
*
*/
public class Calendar
{
private static Calendar _instance = null;
public static Calendar get()
{
if( _instance == null )
_instance = new Calendar();
return _instance;
}
public Tree Parse( String pExpression )
{
return _Parse( pExpression );
}
// takes as a parameter an array of period expressions and their initial
// values
// returns an associative calendar that is the merge of all these
// $addFunction is a callback that can combine two period values
/**
* Create CalendarPeriodAssociative using an adding function.
* PeriodAssociative are periods associated with an integer, result of the
* add function.
*
* @param periodsAndValues
* @param addFunction
* @return CalendarPeriodAssociative
*/
public CalendarPeriodAssociative MakeUpCalendarPeriodAssociative( List trees, List values, CalendarPeriodAssociative.AddFunction addFunction )
{
if( trees.size() != values.size() )
{
assert false : "Calendar.MakeUpCalendarPeriodAssociative : trees and values should have the same size !";
return null;
}
int nbPeriod = trees.size();
if( nbPeriod == 0 )
return new CalendarPeriodAssociative();
// get the first non empty period
CalendarPeriodAssociative res = null;
int first = 0;
do
{
Tree tree = trees.get( first );
T value = values.get( first );
// PeriodAssociative firstPeriodAndValue = periodsAndValues.get(
// first );
// Tree tree = Parse( firstPeriodAndValue.getFrom() );
if( tree.getNbDays() == 0 )
{
first++;
if( first >= nbPeriod )
return new CalendarPeriodAssociative();
continue;
}
CalendarPeriod flat = tree.getFlat();
res = new CalendarPeriodAssociative();
res.Init( flat, value );
break;
}
while( true );
if( res == null )
return null; // no non-empty period
for( int i = first + 1; i < nbPeriod; i++ )
{
Tree tree = trees.get( i );
T value = values.get( i );
if( tree.getNbDays() == 0 )
{
// echo "IGNORING N PERIOD $i (" . $periodsAndValues[$i][0] .
// ") BECAUSE EMPTY
";
continue;
}
CalendarPeriod flat = tree.getFlat();
CalendarPeriodAssociative assoc = new CalendarPeriodAssociative();
assoc.Init( flat, value );
if( res.Add( assoc, addFunction ) == null )
return null;
}
return res;
}
// public CalendarPeriodAssociative MakeUpCalendarPeriodAssociative(
// PeriodsAssociative periodsAndValues,
// CalendarPeriodAssociative.AddFunction addFunction )
// {
// int nbPeriod = periodsAndValues.size();
// if( nbPeriod == 0 )
// return new CalendarPeriodAssociative();
//
// // get the first non empty period
// CalendarPeriodAssociative res = null;
// int first = 0;
// do
// {
// PeriodAssociative firstPeriodAndValue = periodsAndValues.get( first );
// Tree tree = Parse( firstPeriodAndValue.getFrom() );
// if( tree.getNbDays() == 0 )
// {
// // echo "IGNORING F PERIOD $first (" . $firstPeriodAndValue[0] .
// ") BECAUSE EMPTY
";
// first++;
// if( first >= nbPeriod )
// return new CalendarPeriodAssociative();
// continue;
// }
//
// CalendarPeriod flat = tree.getFlat();
// res = new CalendarPeriodAssociative();
// res.Init( flat, firstPeriodAndValue.getValue() ); // TODO :
// firstPeriodAndValue might be wrong type
//
// break;
// }
// while( true );
//
// if( res == null )
// return null; // no non-empty period
//
// for( int i = first + 1; i < nbPeriod; i++ )
// {
// Tree tree = Parse( periodsAndValues.get( i ).getFrom() );
// if( tree.getNbDays() == 0 )
// {
// // echo "IGNORING N PERIOD $i (" . $periodsAndValues[$i][0] .
// ") BECAUSE EMPTY
";
// continue;
// }
//
// CalendarPeriod flat = tree.getFlat();
// CalendarPeriodAssociative assoc = new CalendarPeriodAssociative();
// assoc.Init( flat, periodsAndValues.get( i ).getValue() ); // TODO :
// firstPeriodAndValue might be wrong type
//
// if( res.Add( assoc, addFunction ) == null )
// return null;
// }
//
// return res;
// }
/**
*
* @author Arnaud, Laurent
*/
private Tree _Parse( String pExpression )
{
ParsingExpression exp = new ParsingExpression( pExpression );
Stack stack = new Stack();
Tree token;
while( (token = _NextToken( exp )) != null )
{
switch( token.getType() )
{
case ALWAYS:
case NEVER:
case DAY:
case PERIOD:
stack.push( token );
break;
case NOT:
{
Tree operand = stack.pop();
stack.push( Tree.CreateNot( operand ) );
break;
}
case AND:
{
Tree operandR = stack.pop();
Tree operandL = stack.pop();
stack.push( Tree.CreateAnd( operandL, operandR ) );
break;
}
case OR:
{
Tree operandR = stack.pop();
Tree operandL = stack.pop();
stack.push( Tree.CreateOr( operandL, operandR ) );
break;
}
}
}
if( stack.size() != 1 )
return null;
return stack.pop();
}
// public Boolean _ParseParam( String expression, String dateParam, int
// dayParam )
// {
// exp = new Expression( expression );
//
// stack = new Stack();
//
// Tree token = null;
// while( ( token = _NextToken() ) != null )
// {
// // echo "token : " . $token['t_type'] . "
";
// if( token.getType().equals( "a" ) )
// {
// stack.push( new Tree( true ) );
// }
// else if( token.getType().equals( "n" ) )
// {
// stack.push( new Tree( false ) );
// }
// else if( token.getType().equals( "d" ) )
// {
// if( token.getVal() == dayParam )
// stack.push( new Tree( true ) );
// else
// stack.push( new Tree( false ) );
// }
// else if( token.getType().equals( "p" ) )
// {
// if( (token.getFrom().compareTo( dateParam ) <= 0) &&
// (token.getTo().compareTo( dateParam ) >= 0) )
// stack.push( new Tree( true ) );
// else
// stack.push( new Tree( false ) );
// }
// else if( token.getType().equals( "~" ) )
// {
// stack.push( new Tree( !stack.pop().getBool() ) );
// }
// else if( token.getType().equals( "&" ) )
// {
// boolean operandR = stack.pop().getBool();
// boolean operandL = stack.pop().getBool();
// stack.push( new Tree( operandL & operandR ) );
// }
// else if( token.getType().equals( "|" ) )
// {
// boolean operandR = stack.pop().getBool();
// boolean operandL = stack.pop().getBool();
// stack.push( new Tree( operandL | operandR ) );
// }
// }
//
// if( stack.count() != 1 )
// return null;
//
// return stack.get0().getBool();
// }
/**
*
*
* @return boolean
*
* @author Arnaud, Laurent
*/
private Tree _NextToken( ParsingExpression exp )
{
exp.skipWhiteSpaces();
// end of text...
if( exp.isEndOfText() )
return null;
// test for period token
if( exp.testChar( '[' ) )
{
exp.incPos(); // pass the '['
// get date FROM
if( !exp.readFrom() )
{
// Date not found : finished ...
return null;
}
exp.skipWhiteSpaces();
// check for ;
if( !exp.testChar( ';' ) )
{
// error
return null;
}
exp.incPos();
exp.skipWhiteSpaces();
// get date TO
if( !exp.readTo() )
{
// Date not found : finished ...
return null;
}
exp.skipWhiteSpaces();
// check for ']'
if( !exp.testChar( ']' ) )
{
// error
return null;
}
exp.incPos();
// return the period token
Tree token = Tree.CreatePeriod( exp.getFrom(), exp.getTo() );
return token;
}
// test for day token
if( exp.testChar( 'd' ) )
{
exp.incPos(); // pass the 'd'
// get number
if( !exp.readDay() )
{
// day not found : finished ...
return null;
}
// return day token
Tree token = Tree.CreateDay( Integer.parseInt( exp.getDay() ) );
return token;
}
// test for operator token
if( exp.testChar( '~' ) || exp.testChar( '&' ) || exp.testChar( '|' ) )
{
exp.readOp();
String op = exp.getOp();
if( op.equals( "~" ) )
return Tree.CreateNot( null );
else if( op.equals( "&" ) )
return Tree.CreateAnd( null, null );
else if( op.equals( "|" ) )
return Tree.CreateOr( null, null );
else
throw new IllegalArgumentException( "Unrecognized type from token : " + op );
}
// test for the 'always' token
if( exp.testChar( 'a' ) )
{
exp.incPos();
Tree token = Tree.CreateAlways();
return token;
}
// test for the 'never' token
if( exp.testChar( 'n' ) )
{
exp.incPos();
Tree token = Tree.CreateNever();
return token;
}
// last try a date only, which is shortcut for [from;to] with from and
// to equal...
if( exp.readDate() )
{
Tree token = Tree.CreatePeriod( exp.getDate() );
return token;
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy