/*
* Copyright 2014 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.workbench.screens.guided.rule.client.editor.util;
import java.util.List;
import org.drools.workbench.models.datamodel.oracle.DataType;
import org.drools.workbench.models.datamodel.oracle.DropDownData;
import org.drools.workbench.models.datamodel.rule.BaseSingleFieldConstraint;
import org.drools.workbench.models.datamodel.rule.FactPattern;
import org.drools.workbench.models.datamodel.rule.FieldConstraint;
import org.drools.workbench.models.datamodel.rule.RuleModel;
import org.drools.workbench.models.datamodel.rule.SingleFieldConstraint;
import org.kie.workbench.common.widgets.client.datamodel.AsyncPackageDataModelOracle;
import org.kie.workbench.common.widgets.client.datamodel.CEPOracle;
import org.uberfire.client.callbacks.Callback;
public class ConstraintValueEditorHelper {
private final RuleModel model;
private final AsyncPackageDataModelOracle oracle;
private final String factType;
private final String fieldName;
private final BaseSingleFieldConstraint constraint;
private final String fieldType;
private final DropDownData dropDownData;
public ConstraintValueEditorHelper(
RuleModel model,
AsyncPackageDataModelOracle oracle,
String factType,
String fieldName,
BaseSingleFieldConstraint constraint,
String fieldType,
DropDownData dropDownData ) {
this.model = model;
this.oracle = oracle;
this.factType = factType;
this.fieldName = fieldName;
this.constraint = constraint;
this.fieldType = fieldType;
this.dropDownData = dropDownData;
}
public void isBoundVariableApplicable( final String boundVariable,
final Callback<Boolean> callback ) {
isBoundVariableApplicableByField( boundVariable, new Callback<Boolean>() {
@Override
public void callback( Boolean result ) {
if ( result ) {
callback.callback( true );
return;
} else {
isBoundVariableApplicableByFactType( boundVariable,
callback );
}
}
} );
}
public void isApplicableBindingsInScope( final String binding,
final Callback<Boolean> callback ) {
//LHS FactPattern
isLHSFactTypeEquivalent( binding,
new Callback<Boolean>() {
@Override
public void callback( Boolean result ) {
if ( result ) {
callback.callback( true );
return;
} else {
//LHS FieldConstraint
isBoundVariableApplicableByField( binding,
callback );
}
}
} );
}
private void isBoundVariableApplicableByField( final String boundVariable,
final Callback<Boolean> callback ) {
isLHSFieldTypeEquivalent( boundVariable,
new Callback<Boolean>() {
@Override
public void callback( Boolean result ) {
if ( result ) {
callback.callback( true );
} else {
SingleFieldConstraint lhsBoundField = model.getLHSBoundField( boundVariable );
if ( lhsBoundField != null ) {
final String boundClassName = oracle.getFieldClassName( lhsBoundField.getFactType(), lhsBoundField.getFieldName() );
if ( getFieldTypeClazz().equals( boundClassName ) ) {
callback.callback( true );
return;
}
oracle.getSuperTypes( boundClassName, new Callback<List<String>>() {
@Override
public void callback( List<String> superTypes ) {
callback.callback( checkSuperTypes( superTypes ) );
return;
}
} );
} else {
callback.callback( false );
}
}
}
} );
}
private void isBoundVariableApplicableByFactType( final String boundVariable,
final Callback<Boolean> callback ) {
FactPattern lhsBoundFact = model.getLHSBoundFact( boundVariable );
if ( lhsBoundFact != null ) {
String boundFactType = lhsBoundFact.getFactType();
//For collection, present the list of possible bound variable
String factCollectionType = oracle.getParametricFieldType( this.factType,
this.fieldName );
if ( boundFactType != null && factCollectionType != null && boundFactType.equals( factCollectionType ) ) {
callback.callback( true );
return;
}
}
callback.callback( false );
}
private void isBoundVariableApplicableByFieldType( final String boundFieldType,
final Callback<Boolean> callback ) {
//'this' can be compared to bound events if using a CEP operator
if ( this.fieldName.equals( DataType.TYPE_THIS ) ) {
oracle.isFactTypeAnEvent( boundFieldType,
new Callback<Boolean>() {
@Override
public void callback( final Boolean result ) {
if ( Boolean.TRUE.equals( result ) ) {
oracle.isFactTypeAnEvent( fieldType,
new Callback<Boolean>() {
@Override
public void callback( final Boolean result ) {
if ( Boolean.TRUE.equals( result ) ) {
if ( CEPOracle.isCEPOperator( constraint.getOperator() ) ) {
callback.callback( true );
return;
}
} else {
callback.callback( false );
return;
}
}
} );
} else {
callback.callback( false );
return;
}
}
} );
}
//'this' can be compared to bound Dates if using a CEP operator
if ( this.fieldName.equals( DataType.TYPE_THIS ) && boundFieldType.equals( DataType.TYPE_DATE ) ) {
if ( CEPOracle.isCEPOperator( constraint.getOperator() ) ) {
callback.callback( true );
return;
}
}
//Dates can be compared to bound events if using a CEP operator
if ( this.fieldType.equals( DataType.TYPE_DATE ) ) {
oracle.isFactTypeAnEvent( boundFieldType,
new Callback<Boolean>() {
@Override
public void callback( final Boolean result ) {
if ( Boolean.TRUE.equals( result ) ) {
if ( CEPOracle.isCEPOperator( constraint.getOperator() ) ) {
callback.callback( true );
return;
}
}
}
} );
}
//For collection, present the list of possible bound variable
String factCollectionType = oracle.getParametricFieldType( this.factType,
this.fieldName );
if ( factCollectionType != null && factCollectionType.equals( boundFieldType ) ) {
callback.callback( true );
return;
}
callback.callback( false );
}
private void isLHSFieldTypeEquivalent( final String boundVariable,
final Callback<Boolean> callback ) {
String boundFieldType = this.model.getLHSBindingType( boundVariable );
//If the fieldTypes are SuggestionCompletionEngine.TYPE_COMPARABLE check the enums are equivalent
if ( boundFieldType.equals( DataType.TYPE_COMPARABLE ) ) {
if ( !this.fieldType.equals( DataType.TYPE_COMPARABLE ) ) {
callback.callback( false );
return;
}
SingleFieldConstraint fc = this.model.getLHSBoundField( boundVariable );
String fieldName = fc.getFieldName();
String parentFactTypeForBinding = this.model.getLHSParentFactPatternForBinding( boundVariable ).getFactType();
String[] dd = this.oracle.getEnumValues( parentFactTypeForBinding,
fieldName );
callback.callback( isEnumEquivalent( dd ) );
return;
}
isBoundVariableApplicableByFieldType( boundFieldType,
callback );
}
private boolean isEnumEquivalent( String[] values ) {
if ( values == null && this.dropDownData.getFixedList() == null ) {
return true;
}
if ( values == null && this.dropDownData.getFixedList() != null ) {
return false;
}
if ( values != null && this.dropDownData.getFixedList() == null ) {
return false;
}
if ( values.length != this.dropDownData.getFixedList().length ) {
return false;
}
for ( int i = 0; i < values.length; i++ ) {
if ( !values[ i ].equals( this.dropDownData.getFixedList()[ i ] ) ) {
return false;
}
}
return true;
}
private void isLHSFactTypeEquivalent( final String boundVariable,
final Callback<Boolean> callback ) {
FactPattern factPattern = model.getLHSBoundFact( boundVariable );
if ( factPattern == null ) {
callback.callback( false );
return;
}
//Both types are identical
final String boundFactType = factPattern.getFactType();
final String fieldType = getFieldTypeClazz();
if ( fieldType.equals( boundFactType ) ) {
callback.callback( true );
return;
} else {
isLHSFactTypeAnEvent( boundVariable,
boundFactType,
fieldType,
callback );
}
}
//Both types are events
private void isLHSFactTypeAnEvent( final String boundVariable,
final String boundFactType,
final String fieldType,
final Callback<Boolean> callback ) {
oracle.isFactTypeAnEvent( boundFactType,
new Callback<Boolean>() {
@Override
public void callback( final Boolean result ) {
if ( Boolean.TRUE.equals( result ) ) {
oracle.isFactTypeAnEvent( fieldType,
new Callback<Boolean>() {
@Override
public void callback( final Boolean result ) {
if ( Boolean.TRUE.equals( result ) ) {
if ( CEPOracle.isCEPOperator( constraint.getOperator() ) ) {
callback.callback( true );
return;
} else {
isLHSFactTypeAssignable( boundVariable,
boundFactType,
callback );
}
} else {
isLHSFactTypeAssignable( boundVariable,
boundFactType,
callback );
}
}
} );
} else {
isLHSFactTypeAssignable( boundVariable,
boundFactType,
callback );
}
}
} );
}
private void isLHSFactTypeAssignable( final String boundVariable,
final String boundFactType,
final Callback<Boolean> callback ) {
if ( boundFactType.equals( DataType.TYPE_COMPARABLE ) ) {
//If the types are SuggestionCompletionEngine.TYPE_COMPARABLE check the enums are equivalent
if ( !fieldType.equals( DataType.TYPE_COMPARABLE ) ) {
callback.callback( false );
return;
}
String[] dd = oracle.getEnumValues( boundFactType,
fieldName );
callback.callback( isEnumEquivalent( dd ) );
} else {
this.oracle.getSuperTypes( boundFactType, new Callback<List<String>>() {
@Override
public void callback( List<String> superTypes ) {
if ( checkSuperTypes( superTypes ) ) {
callback.callback( true );
return;
} else {
isBoundVariableApplicable( boundVariable,
callback );
}
}
} );
}
}
private boolean checkSuperTypes( List<String> superTypes ) {
if ( superTypes != null ) {
for ( String superType : superTypes ) {
if ( getFieldTypeClazz().equals( superType ) ) {
return true;
}
}
}
return false;
}
private String getFieldTypeClazz() {
String fieldClassName = oracle.getFieldClassName( factType, fieldName );
return fieldClassName;
}
}