/****************************************************************************** * Copyright (c) 2016 Oracle * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Konstantin Komissarchik - initial implementation and ongoing maintenance ******************************************************************************/ package org.eclipse.sapphire.modeling.el; import java.util.Collections; import java.util.List; import org.eclipse.sapphire.Event; import org.eclipse.sapphire.Listener; import org.eclipse.sapphire.modeling.util.MiscUtil; /** * Function that returns one of two alternatives depending on a condition. * * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a> */ public final class ConditionalFunction extends Function { public static ConditionalFunction create( final Function condition, final Function positive, final Function negative ) { final ConditionalFunction function = new ConditionalFunction(); function.init( condition, positive, negative ); return function; } @Override public String name() { return "Conditional"; } @Override public boolean operator() { return true; } @Override public int precedence() { return 7; } @Override public FunctionResult evaluate( final FunctionContext context ) { return new FunctionResult( this, context ) { private Boolean lastConditionValue; private FunctionResult lastActiveBranch; private Listener listener; @Override protected void init() { super.init(); this.listener = new Listener() { @Override public void handle( final Event event ) { refresh(); } }; } @Override protected List<FunctionResult> initOperands() { // Only initialize the condition operand as the other two operands should only be evaluated based // on condition's value. return Collections.singletonList( function().operands().get( 0 ).evaluate( context ) ); } @Override protected Object evaluate() { final Boolean conditionValue = cast( operand( 0 ), Boolean.class ); if( this.lastActiveBranch != null && ! MiscUtil.equal( this.lastConditionValue, conditionValue ) ) { this.lastConditionValue = null; this.lastActiveBranch.dispose(); this.lastActiveBranch = null; } if( this.lastActiveBranch == null ) { this.lastConditionValue = conditionValue; final FunctionResult res; if( conditionValue == true ) { res = function().operand( 1 ).evaluate( context ); } else { res = function().operand( 2 ).evaluate( context ); } if( this.lastActiveBranch != null ) { throw new IllegalStateException(); } this.lastActiveBranch = res; this.lastActiveBranch.attach( this.listener ); } return this.lastActiveBranch.value(); } @Override public void dispose() { super.dispose(); if( this.lastActiveBranch != null ) { this.lastActiveBranch.dispose(); } } }; } @Override public void toString( final StringBuilder buf, final boolean topLevel ) { toString( buf, operand( 0 ) ); buf.append( " ? " ); toString( buf, operand( 1 ) ); buf.append( " : " ); toString( buf, operand( 2 ) ); } private void toString( final StringBuilder buf, final Function operand ) { final boolean parens = ( precedence() <= operand.precedence() ); if( parens ) { buf.append( "( " ); } operand.toString( buf, false ); if( parens ) { buf.append( " )" ); } } }