Package org.olat.course.condition

Source Code of org.olat.course.condition.ConditionConfigEasyController

/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS,
* <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <p>
*/
package org.olat.course.condition;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.form.flexible.DependencyRuleApplayable;
import org.olat.core.gui.components.form.flexible.FormItem;
import org.olat.core.gui.components.form.flexible.FormItemContainer;
import org.olat.core.gui.components.form.flexible.FormItemDependencyRule;
import org.olat.core.gui.components.form.flexible.elements.FormLink;
import org.olat.core.gui.components.form.flexible.elements.IntegerElement;
import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
import org.olat.core.gui.components.form.flexible.elements.TextElement;
import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
import org.olat.core.gui.components.form.flexible.impl.FormEvent;
import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
import org.olat.core.gui.components.form.flexible.impl.elements.FormLinkImpl;
import org.olat.core.gui.components.form.flexible.impl.elements.FormSubmit;
import org.olat.core.gui.components.form.flexible.impl.elements.JSDateChooser;
import org.olat.core.gui.components.form.flexible.impl.elements.SingleSelectionImpl;
import org.olat.core.gui.components.form.flexible.impl.rules.RulesFactory;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
import org.olat.core.gui.translator.Translator;
import org.olat.core.logging.AssertException;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.util.StringHelper;
import org.olat.course.editor.CourseEditorEnv;
import org.olat.course.groupsandrights.CourseGroupManager;
import org.olat.course.nodes.CourseNode;
import org.olat.group.context.BGContext;
import org.olat.group.ui.BGControllerFactory;
import org.olat.group.ui.NewAreaController;
import org.olat.group.ui.NewBGController;
import org.olat.group.ui.context.BGContextEvent;
import org.olat.shibboleth.ShibbolethModule;
/**
* Description:<br>
* The ConditionConfigEasyController implements the easy condition editing
* workflow in the course editor. It has several complex dependency rules to
* show and hide form input fields, and also the possibility to start
* subworkflows for creation of groups or areas.
* <P>
* Initial Date: 13.06.2007 <br>
*
* @author patrickb
*/
public class ConditionConfigEasyController extends FormBasicController {
  private Condition validatedCondition;
  private CourseEditorEnv courseEditorEnv;
  private List nodeIdentList;
  private FormSubmit subm;
  //private FormReset reset;
  private MultipleSelectionElement coachExclusive;
  private JSDateChooser fromDate;
  private JSDateChooser toDate;
  private FormItemContainer dateSubContainer, groupSubContainer, assessSubContainer;
  private FormLayoutContainer areaChooseSubContainer,  groupChooseSubContainer;
  private FormLayoutContainer assessNodesListContainer;
  private MultipleSelectionElement dateSwitch;
  private TextElement easyGroupTE;
  private FormLink chooseGroupsLink;
  private TextElement easyAreaTE;
  private FormLink chooseAreasLink;
  private MultipleSelectionElement groupSwitch;
  private GroupOrAreaSelectionController groupChooseC;
  private GroupOrAreaSelectionController areaChooseC;
  private FormLink fixGroupError;
  private FormLink fixAreaError;
  private MultipleSelectionElement assessmentSwitch;
  private SingleSelection assessmentTypeSwitch;
  private SingleSelection nodePassed;
  //
  private MultipleSelectionElement attributeSwitch;
  private SingleSelection attributeBconnector;
  private AttributeEasyRowAdderController attribteRowAdderSubform;
  //
  private IntegerElement cutValue;
  private MultipleSelectionElement applyRulesForCoach;
  private boolean hasAreas = false;
  private boolean hasGroups = false;
  private NewBGController groupCreateCntrllr;
  private CloseableModalController cmc;
  private NewAreaController areaCreateCntrllr;
  private FormLink createGroupsLink;
  private FormLinkImpl createAreasLink;

  private static final String NODEPASSED_VAL_PASSED = "passed";
  private static final String NODEPASSED_VAL_SCORE = "score";

  private static final String DELETED_NODE_IDENTIFYER = "deletedNode";
  private static final String NO_NODE_SELECTED_IDENTIFYER = "";
  protected static final String BCON_VAL_OR = "bcon_or";
  protected static final String BCON_VAL_AND = "bcon_and";

  /**
   * with default layout <tt>_content/easycondedit.html</tt>
   *
   * @param ureq
   * @param wControl
   * @param groupMgr The course group manager
   * @param cond condition for initialisation
   * @param title The title that should be displayed for this condition
   * @param formName Name of the condition form - must be unique within a HTML
   *          page
   * @param nodeIdentList
   * @param euce
   */
  @SuppressWarnings("unused")
  public ConditionConfigEasyController(UserRequest ureq, WindowControl wControl, Condition cond, String title,  String formName,
      List nodeIdentList, CourseEditorEnv env) {
    super(ureq, wControl, "easycondedit");
    /*
     * my instance variables, these data is used by form items to initialise
     */
    this.validatedCondition = cloneCondition(cond);
    if (this.validatedCondition == null) throw new OLATRuntimeException("CondititionEditController called with a NULL condition",
        new IllegalArgumentException());
    this.courseEditorEnv = env;
    hasAreas = courseEditorEnv.getCourseGroupManager().getAllAreasFromAllContexts().size() > 0;
    hasGroups = courseEditorEnv.getCourseGroupManager().getAllLearningGroupsFromAllContexts().size() > 0;

    this.nodeIdentList = nodeIdentList;
    /*
     * init all elements the last thing to do
     */
    initForm(this.flc, this, ureq);
  }

  /**
   * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#doDispose(boolean)
   */
  @Override
  protected void doDispose() {
    // auto dispose by basic controller
  }

  /**
   * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formOK(org.olat.core.gui.UserRequest)
   */
  @Override
  @SuppressWarnings("unused")
  protected void formOK(UserRequest ureq) {
    /*
     *
     */
    // 1) rule applies also for coach switch - one checkbox
    // has opposite meaning -> selected is saved as false, and vice versa
    if (applyRulesForCoach.getSelectedKeys().size() == 0) {
      validatedCondition.setEasyModeAlwaysAllowCoachesAndAdmins(true);
    } else {
      validatedCondition.setEasyModeAlwaysAllowCoachesAndAdmins(false);
    }
    // 2) admin and coach switch - one checkbox
    if (coachExclusive.getSelectedKeys().size() == 1) {
      validatedCondition.setEasyModeCoachesAndAdmins(true);
      // when true discard all other rules
      validatedCondition.setEasyModeBeginDate(null);
      validatedCondition.setEasyModeEndDate(null);
      validatedCondition.setEasyModeGroupAccess(null);
      validatedCondition.setEasyModeGroupAreaAccess(null);
      validatedCondition.setEasyModeCutValue(null);
      validatedCondition.setEasyModeNodePassedId(null);
      validatedCondition.setAttributeConditions(null);
      validatedCondition.setAttributeConditionsConnectorIsAND(null);
    } else {
      validatedCondition.setEasyModeCoachesAndAdmins(false);
      // 3) date switch
      if (dateSwitch.getSelectedKeys().size() == 1) {
        if (StringHelper.containsNonWhitespace(fromDate.getValue())) validatedCondition.setEasyModeBeginDate(fromDate.getValue());
        else validatedCondition.setEasyModeBeginDate(null);

        if (StringHelper.containsNonWhitespace(toDate.getValue())) validatedCondition.setEasyModeEndDate(toDate.getValue());
        else validatedCondition.setEasyModeEndDate(null);
      } else {
        validatedCondition.setEasyModeBeginDate(null);
        validatedCondition.setEasyModeEndDate(null);
      }

      // 4) group switch
      if (groupSwitch.getSelectedKeys().size() == 1) {
        // groups
        if (StringHelper.containsNonWhitespace(easyGroupTE.getValue())) validatedCondition.setEasyModeGroupAccess(easyGroupTE.getValue());
        else validatedCondition.setEasyModeGroupAccess(null);
        // areas
        if (StringHelper.containsNonWhitespace(easyAreaTE.getValue())) validatedCondition.setEasyModeGroupAreaAccess(easyAreaTE.getValue());
        else validatedCondition.setEasyModeGroupAreaAccess(null);
      } else {
        validatedCondition.setEasyModeGroupAccess(null);
        validatedCondition.setEasyModeGroupAreaAccess(null);
      }

      // 5) assessment switch
      if (assessmentSwitch.getSelectedKeys().size() == 1) {
        // now evaluate the selection
        // which node, if one is selected
        if (!nodePassed.getSelectedKey().equals("")) {
          validatedCondition.setEasyModeNodePassedId(nodePassed.getSelectedKey());
        } else {
          validatedCondition.setEasyModeNodePassedId(null);
        }
        if (assessmentTypeSwitch.getSelectedKey().equals(NODEPASSED_VAL_SCORE)) {
          // this is formOK -> value of integer elment is ensured to be an
          // int!
          validatedCondition.setEasyModeCutValue(cutValue.getValue());
        } else {
          validatedCondition.setEasyModeCutValue(null);
        }
      } else {
        validatedCondition.setEasyModeNodePassedId(null);
        if(nodeIdentList.size()==0) {
          assessmentSwitch.setEnabled(false);
        }
      }

      // 6) attribute switch
      if (ShibbolethModule.isEnableShibbolethLogins()) {
        if (attributeSwitch.getSelectedKeys().size() == 1) {
          List<ExtendedCondition> le = attribteRowAdderSubform.getAttributeConditions();
   
          if (le.size() < 1) {
            // some error(s) occured, don't save anything
            validatedCondition.setAttributeConditions(null);
          } else {
            // add the conditions
            validatedCondition.setAttributeConditions(le);
          }
          validatedCondition.setAttributeConditionsConnectorIsAND(new Boolean(attributeBconnector.getSelectedKey().equals(BCON_VAL_AND)));
   
        } else {
          validatedCondition.setAttributeConditions(null);
          validatedCondition.setAttributeConditionsConnectorIsAND(null);
        }
      }
    }

    // calculate expression from easy mode form
    String condString = validatedCondition.getConditionFromEasyModeConfiguration();
    validatedCondition.setConditionExpression(condString);
    validatedCondition.setExpertMode(false);

    /*
     * condition is updated
     */

    // Inform all listeners about the changed condition
    fireEvent(ureq, Event.CHANGED_EVENT);

  }

  @Override
  @SuppressWarnings("unused")
  protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
    /*
     * workaround: catch each inner event to set whole form dirty, in order to
     * make the $f.hasError("group") having an effect in ajax mode. E.g.
     * removing table tr's in the layouting velocity container.
     */
    this.flc.setDirty(true);
    /*
     *
     */

    if (source == chooseGroupsLink) {
      // user wants to choose groups.. either link clicked -> Startpoint for
      // group choosing workflow
      removeAsListenerAndDispose(groupChooseC);
      // already groups -> it is about selecting groups
      groupChooseC = new GroupOrAreaSelectionController(0, getWindowControl(), ureq, "group", courseEditorEnv.getCourseGroupManager(),
          easyGroupTE.getValue());
      listenTo(groupChooseC);


      //the main form gets overlayed -> hence do not mark as dirty
      //otherwise clicking any link in the overlay results in a
      //alert box -> "you have unsaved form data"
      //one has to listen for cmc closing events and then reactivate
      //dirty setting!! TODO:pb: find a better solution as this is error prone
      this.flc.getRootForm().setDirtyMarking(false);
      removeAsListenerAndDispose(cmc);
      cmc = new CloseableModalController(getWindowControl(), "close", groupChooseC.getInitialComponent(), true, getTranslator().translate("popupchoosegroups"));
      listenTo(cmc);
      cmc.activate();

    } else if (source == createGroupsLink) {
      // no groups in group management -> directly show group create dialog
      BGContext bgContext = getDefaultBGContext();
      String[] csvGroupName = easyGroupTE.isEmpty() ? new String[0] : easyGroupTE.getValue().split(",");
      // determine if bulkmode or not
      removeAsListenerAndDispose(groupCreateCntrllr);
      boolean bulkMode = csvGroupName.length > 1;
      groupCreateCntrllr = BGControllerFactory.getInstance().createNewBGController(ureq, getWindowControl(),  true,
          bgContext, bulkMode, easyGroupTE.getValue());
      listenTo(groupCreateCntrllr);

      //the main form gets overlayed -> hence do not mark as dirty
      //otherwise clicking any link in the overlay results in a
      //alert box -> "you have unsaved form data"
      //one has to listen for cmc closing events and then reactivate
      //dirty setting!! TODO:pb: find a better solution as this is error prone
      this.flc.getRootForm().setDirtyMarking(false);
      removeAsListenerAndDispose(cmc);
      cmc = new CloseableModalController(getWindowControl(), "close", groupCreateCntrllr.getInitialComponent());
      listenTo(cmc);
      cmc.activate();

    } else if (source == chooseAreasLink) {
      // already areas -> choose areas
      removeAsListenerAndDispose(areaChooseC);
      areaChooseC = new GroupOrAreaSelectionController(1, getWindowControl(), ureq, "area", courseEditorEnv.getCourseGroupManager(),
          easyAreaTE.getValue());
      listenTo(areaChooseC);
     
      //the main form gets overlayed -> hence do not mark as dirty
      //otherwise clicking any link in the overlay results in a
      //alert box -> "you have unsaved form data"
      //one has to listen for cmc closing events and then reactivate
      //dirty setting!! TODO:pb: find a better solution as this is error prone
      this.flc.getRootForm().setDirtyMarking(false);
      removeAsListenerAndDispose(cmc);
      cmc = new CloseableModalController(getWindowControl(), "close", areaChooseC.getInitialComponent(), true, getTranslator().translate("popupchooseareas"));
      listenTo(cmc);
      cmc.activate();

    } else if (source == createAreasLink) {
      // no areas -> directly show creation dialog
      BGContext bgContext = getDefaultBGContext();
      removeAsListenerAndDispose(areaCreateCntrllr);
      String[] csvAreaName = easyAreaTE.isEmpty() ? new String[0] : easyAreaTE.getValue().split(",");
      // determine if bulkmode or not
      boolean bulkMode = csvAreaName.length > 1;
      areaCreateCntrllr = BGControllerFactory.getInstance().createNewAreaController(ureq, getWindowControl(),
          bgContext, bulkMode, easyAreaTE.getValue());
      listenTo(areaCreateCntrllr);

      //the main form gets overlayed -> hence do not mark as dirty
      //otherwise clicking any link in the overlay results in a
      //alert box -> "you have unsaved form data"
      //one has to listen for cmc closing events and then reactivate
      //dirty setting!! TODO:pb: find a better solution as this is error prone
      this.flc.getRootForm().setDirtyMarking(false);
      removeAsListenerAndDispose(cmc);
      cmc = new CloseableModalController(getWindowControl(), "close", areaCreateCntrllr.getInitialComponent());
      listenTo(cmc);
      cmc.activate();

    } else if (source == fixGroupError) {
      /*
       * user wants to fix problem with fixing group error link e.g. create one
       * or more group at once.
       */
      BGContext bgContext = getDefaultBGContext();
      if (groupCreateCntrllr != null) groupCreateCntrllr.dispose();
      String[] csvGroupName = (String[]) fixGroupError.getUserObject();
      // determine if bulkmode or not
      boolean bulkMode = csvGroupName.length > 1;
      removeAsListenerAndDispose(groupCreateCntrllr);
      groupCreateCntrllr = BGControllerFactory.getInstance().createNewBGController(ureq, getWindowControl(), true,
          bgContext, bulkMode, csvGroupName[0]);
      listenTo(groupCreateCntrllr);
     
      //the main form gets overlayed -> hence do not mark as dirty
      //otherwise clicking any link in the overlay results in a
      //alert box -> "you have unsaved form data"
      //one has to listen for cmc closing events and then reactivate
      //dirty setting!! TODO:pb: find a better solution as this is error prone
      this.flc.getRootForm().setDirtyMarking(false);
      removeAsListenerAndDispose(cmc);
      cmc = new CloseableModalController(getWindowControl(), "close", groupCreateCntrllr.getInitialComponent());
      listenTo(cmc);
      cmc.activate();
    } else if (source == fixAreaError) {
      /*
       * user wants to fix problem with fixing area error link e.g. create one
       * or more areas at once.
       */
      BGContext bgContext = getDefaultBGContext();
      removeAsListenerAndDispose(areaCreateCntrllr);
      String[] csvAreaName = (String[]) fixAreaError.getUserObject();
      // determine if bulkmode or not
      boolean bulkMode = csvAreaName.length > 1;
      areaCreateCntrllr = BGControllerFactory.getInstance().createNewAreaController(ureq, getWindowControl(),
          bgContext, bulkMode, csvAreaName[0]);
      listenTo(areaCreateCntrllr);
     
      //the main form gets overlayed -> hence do not mark as dirty
      //otherwise clicking any link in the overlay results in a
      //alert box -> "you have unsaved form data"
      //one has to listen for cmc closing events and then reactivate
      //dirty setting!! TODO:pb: find a better solution as this is error prone
      this.flc.getRootForm().setDirtyMarking(false);
      removeAsListenerAndDispose(cmc);
      cmc = new CloseableModalController(getWindowControl(), "close", areaCreateCntrllr.getInitialComponent());
      listenTo(cmc);
      cmc.activate();
     
    }
  }

  /*
   * find default context if one is present
   */
  private BGContext getDefaultBGContext() {
    CourseGroupManager courseGrpMngr = courseEditorEnv.getCourseGroupManager();
    List courseLGContextes = courseGrpMngr.getLearningGroupContexts();
    for (Iterator iter = courseLGContextes.iterator(); iter.hasNext();) {
      BGContext bctxt = (BGContext) iter.next();
      if (bctxt.isDefaultContext()) { return bctxt; }
    }
    return null;
    // not found! -> disable easy creation of groups! (no workflows for choosing
    // contexts

  }

  @Override
  @SuppressWarnings("unused")
  protected void event(UserRequest ureq, Controller source, org.olat.core.gui.control.Event event) {
    /*
     * if source { if event { pattern
     */
    if(source == cmc){
      if(CloseableModalController.CLOSE_MODAL_EVENT == event){
        //close event is the only sent out by cmc
        //TODO:pb find better solution
        this.flc.getRootForm().setDirtyMarking(true);
        this.flc.setDirty(true);
      }
    }else if (source == groupChooseC) {
      if (Event.DONE_EVENT == event) {
        //TODO:pb find better solution
        this.flc.getRootForm().setDirtyMarking(true);
        this.flc.setDirty(true);
        cmc.deactivate();
        String selection = "";// FIXME:pb strange
        selection = StringHelper.formatAsCSVString(groupChooseC.getSelectedEntries());
        // apply selection to textelement
        easyGroupTE.setValue(selection);
        validateGroupFields();
      }else if (Event.CANCELLED_EVENT == event){
        closeCMCandSetWholeFormDirty(source);
        return;
      }else if(Event.CHANGED_EVENT == event){
        //a group was created in group chooser
        if(!hasGroups)
        //fires an Multiuser designed bgcontext event NOT on the systembus if business group were created
        fireEvent(ureq, new BGContextEvent(BGContextEvent.RESOURCE_ADDED,getDefaultBGContext()));
      }
    } else if (source == areaChooseC) {
      if (org.olat.core.gui.control.Event.DONE_EVENT == event) {
        //TODO:pb find better solution
        this.flc.getRootForm().setDirtyMarking(true);
        this.flc.setDirty(true);
        cmc.deactivate();
        String selection = "";
        selection = StringHelper.formatAsCSVString(areaChooseC.getSelectedEntries());
        // apply selection to textelement
        easyAreaTE.setValue(selection);
        validateGroupFields();
      }else if (org.olat.core.gui.control.Event.CANCELLED_EVENT == event){
        closeCMCandSetWholeFormDirty(source);
        return;
      }else if(Event.CHANGED_EVENT == event){
        if(!hasAreas){
          //an area was created in area chooser
          //fires an Multiuser designed bgcontext event NOT on the systembus if area were created
          fireEvent(ureq, new BGContextEvent(BGContextEvent.RESOURCE_ADDED,getDefaultBGContext()));
        }
      }
    } else if (source == groupCreateCntrllr) {
      if (org.olat.core.gui.control.Event.DONE_EVENT == event) {
        // validate element -> e.g. remove error
        if (easyGroupTE.isEmpty()) {
          // was empty before -> set the created groups
          easyGroupTE.setValue(StringHelper.formatAsCSVString(groupCreateCntrllr.getCreatedGroupNames()));
        }
        validateGroupFields();
        // toggle prepared links (create -> choose)
        flc.remove(createGroupsLink);
        flc.add(chooseGroupsLink);

        groupCreateCntrllr.dispose();
        //TODO:pb find better solution
        this.flc.getRootForm().setDirtyMarking(true);
        this.flc.setDirty(true);
        cmc.deactivate();
        if(!hasGroups){
          //fires an Multiuser designed bgcontext event NOT on the systembus if business group were created
          fireEvent(ureq, new BGContextEvent(BGContextEvent.RESOURCE_ADDED,getDefaultBGContext()));
        }
        hasGroups = true;// at least one group created
      }else if (org.olat.core.gui.control.Event.CANCELLED_EVENT == event){
        closeCMCandSetWholeFormDirty(source);
        return;
      }
    } else if (source == areaCreateCntrllr) {
      if (org.olat.core.gui.control.Event.DONE_EVENT == event) {
        // validate element -> e.g. remove error
        if (easyAreaTE.isEmpty()) {
          // was empty before -> set the created groups
          easyAreaTE.setValue(StringHelper.formatAsCSVString(areaCreateCntrllr.getCreatedAreaNames()));
        }
        validateGroupFields();
        // toggle prepared links (create -> choose)
        flc.remove(createAreasLink);
        flc.add(chooseAreasLink);

        areaCreateCntrllr.dispose();
        //TODO:pb find better solution
        this.flc.getRootForm().setDirtyMarking(true);
        this.flc.setDirty(true);
        cmc.deactivate();
        if (!hasAreas) {
          // fires an Multiuser designed bgcontext event NOT on the systembus if
          // area were created
          fireEvent(ureq, new BGContextEvent(BGContextEvent.RESOURCE_ADDED,getDefaultBGContext()));
        }
        hasAreas = true;// at least one group created
      }else if (org.olat.core.gui.control.Event.CANCELLED_EVENT == event){
        closeCMCandSetWholeFormDirty(source);
        return;
      }
    }

  }

  /**
   * @param source
   */
  private void closeCMCandSetWholeFormDirty(Controller source) {
    cmc.deactivate();
    //TODO:pb find better solution
    this.flc.getRootForm().setDirtyMarking(true);
    this.flc.setDirty(true);
    source.dispose();
  }

  @Override
  @SuppressWarnings("unused")
  protected boolean validateFormLogic(UserRequest ureq) {
    boolean retVal = true;
    // (1)
    // dateswitch is enabled and the datefields are valid
    // check complex rules involving checks over multiple elements
    Date fromDateVal = fromDate.getDate();
    Date toDateVal = toDate.getDate();
    if (dateSwitch.getSelectedKeys().size() == 1 && !fromDate.hasError() && !toDate.hasError()) {
      // one must be set
      if (fromDate.isEmpty() && toDate.isEmpty()) {
        // error concern both input fields -> set it as switch error       
        dateSubContainer.setErrorKey("form.easy.error.date", null);
        retVal = false;
      } else {
        // remove general error       
        dateSubContainer.clearError();
      }
      // check valid dates

      // if both are set, check from < to
      if (fromDateVal != null && toDateVal != null) {
        /*
         * bugfix http://bugs.olat.org/jira/browse/OLAT-813 valid dates and not
         * empty, in easy mode we assume that Start and End date should
         * implement the meaning of
         * ----false---|S|-----|now|-TRUE---------|E|---false--->t .............
         * Thus we check for Startdate < Enddate, error otherwise
         */
        if (fromDateVal.after(toDateVal)) {         
          dateSubContainer.setErrorKey("form.easy.error.bdateafteredate", null);
          retVal = false;
        } else {
          // remove general error
          dateSwitch.clearError();
        }
      } else {
        if (fromDateVal == null && !fromDate.isEmpty()) {
          //not a correct begin date
          fromDate.setErrorKey("form.easy.error.bdate", null);
          retVal = false;
        }
        if (toDateVal == null && !toDate.isEmpty()) {
          toDate.setErrorKey("form.easy.error.edate", null);
          retVal = false;
        }
      }
    }

    // (2)
    // groups switch is enabled
    // check if either group or area is defined
    retVal = validateGroupFields() && retVal;

    if (assessmentSwitch.getSelectedKeys().size() == 1) {
      // first check two error cases of a selection
      // no node selected or a deleted node selected
      if (nodePassed.getSelectedKey().equals(NO_NODE_SELECTED_IDENTIFYER)) {       
        assessNodesListContainer.setErrorKey("form.easy.error.nodePassed", null);
        retVal = false;
      } else if (nodePassed.getSelectedKey().equals(DELETED_NODE_IDENTIFYER)) {
        assessNodesListContainer.setErrorKey("form.easy.error.nodeDeleted", null);
        retVal = false;
      } else {
        //clear nodepassed error
        assessNodesListContainer.clearError();
        //retVal stays
      }
    }
   
    if (ShibbolethModule.isEnableShibbolethLogins()) {
      retVal=validateAttibuteFields()&&retVal; 
    }
    //
    return retVal;
  }

  /**
   * @param retVal
   * @return
   */
  private boolean validateGroupFields() {
    boolean retVal = true;
    if (groupSwitch.getSelectedKeys().size() == 1) {

      String[] activeGroupSelection = new String[0];
      String[] activeAreaSelection = new String[0];
      if (!easyGroupTE.isEmpty()) {
        // check whether groups exist
        activeGroupSelection = easyGroupTE.getValue().split(",");
        boolean exists = false;
        Set<String> missingGroups = new HashSet<String>();
        for (int i = 0; i < activeGroupSelection.length; i++) {
          String trimmed = activeGroupSelection[i].trim();
          exists = courseEditorEnv.existsGroup(trimmed);
          if (!exists) {
            missingGroups.add(trimmed);
          }
        }
        if (missingGroups.size() > 0) {
          retVal = false;
          String labelKey = missingGroups.size() == 1 ? "error.notfound.name" : "error.notfound.names";
          String csvMissGrps = StringHelper.formatAsCSVString(missingGroups);
          String[] params = new String[] { "-", csvMissGrps };

          /*
           * create error with link to fix it
           */
          String vc_errorPage = velocity_root + "/erroritem.html";
          FormLayoutContainer errorGroupItemLayout = (FormLayoutContainer) FormLayoutContainer.createCustomFormLayout("errorgroupitem",
              getTranslator(), vc_errorPage);

          boolean hasDefaultContext = getDefaultBGContext() != null;
          if (hasDefaultContext) {
            groupChooseSubContainer.setErrorComponent(errorGroupItemLayout, this.flc);
            // FIXING LINK ONLY IF A DEFAULTCONTEXT EXISTS
            fixGroupError = new FormLinkImpl("error.fix", "create");
            // link
            fixGroupError.setCustomEnabledLinkCSS("b_button");
            errorGroupItemLayout.add(fixGroupError);

            fixGroupError.setErrorKey(labelKey, params);
            fixGroupError.showError(true);
            fixGroupError.showLabel(false);
            // hinty to pass the information if one group is
            // missing or if 2 or more groups are missing
            // (see fixGroupErrer.getUserObject to understand)
            // e.g. if userobject String[].lenght == 1 -> one group only
            // String[].lenght > 1 -> show bulkmode creation group
            if (missingGroups.size() > 1) {
              fixGroupError.setUserObject(new String[] { csvMissGrps, "dummy" });
            } else {
              fixGroupError.setUserObject(new String[] { csvMissGrps });
            }
          } else {
            // fix helper link not possible -> errortext only
            groupChooseSubContainer.setErrorKey(labelKey, params);
          }
          /*
           *
           */
          groupChooseSubContainer.showError(true);
        } else {
          // no more errors
          groupChooseSubContainer.clearError();
        }
      }
      if (!easyAreaTE.isEmpty()) {
        // check whether areas exist
        activeAreaSelection = easyAreaTE.getValue().split(",");
        boolean exists = false;
        Set<String> missingAreas = new HashSet<String>();
        for (int i = 0; i < activeAreaSelection.length; i++) {
          String trimmed = activeAreaSelection[i].trim();
          exists = courseEditorEnv.existsArea(trimmed);
          if (!exists) {
            missingAreas.add(trimmed);
          }
        }
        if (missingAreas.size() > 0) {
          retVal = false;
          String labelKey = missingAreas.size() == 1 ? "error.notfound.name" : "error.notfound.names";
          String csvMissAreas = StringHelper.formatAsCSVString(missingAreas);
          String[] params = new String[] { "-", csvMissAreas };

          /*
           * create error with link to fix it
           */
          String vc_errorPage = velocity_root + "/erroritem.html";
          FormLayoutContainer errorAreaItemLayout = (FormLayoutContainer) FormLayoutContainer.createCustomFormLayout("errorareaitem",
              getTranslator(), vc_errorPage);
          boolean hasDefaultContext = getDefaultBGContext() != null;
          if (hasDefaultContext) {
            areaChooseSubContainer.setErrorComponent(errorAreaItemLayout, this.flc);
            // FXINGIN LINK ONLY IF DEFAULT CONTEXT EXISTS
            fixAreaError = new FormLinkImpl("error.fix", "create");// erstellen
            // link
            fixAreaError.setCustomEnabledLinkCSS("b_button");
            errorAreaItemLayout.add(fixAreaError);

            fixAreaError.setErrorKey(labelKey, params);
            fixAreaError.showError(true);
            fixAreaError.showLabel(false);
            // hint to pass the information if one area is
            // missing or if 2 or more areas are missing
            // (see fixGroupErrer.getUserObject to understand)
            // e.g. if userobject String[].lenght == 1 -> one group only
            // String[].lenght > 1 -> show bulkmode creation group
            if (missingAreas.size() > 1) {
              fixAreaError.setUserObject(new String[] { csvMissAreas, "dummy" });
            } else {
              fixAreaError.setUserObject(new String[] { csvMissAreas });
            }
          } else {
            // fixing help link not possible -> text only
            areaChooseSubContainer.setErrorKey(labelKey, params);
          }
          /*
           *
           */
          areaChooseSubContainer.showError(true);
        } else {
          // TODO:pb:introduce clear error instead hiding error!
          areaChooseSubContainer.clearError();
        }

      }

      boolean easyGroupOK = (!easyGroupTE.isEmpty() && activeGroupSelection.length != 0);
      boolean easyAreaOK = (!easyAreaTE.isEmpty() && activeAreaSelection.length != 0);
      if (easyGroupOK || easyAreaOK) {
        // clear general error
        groupSubContainer.clearError();
      } else {
        // error concerns both fields -> set it as switch error
        groupSubContainer.setErrorKey("form.easy.error.group", null);
        retVal = false;
      }

    }
    return retVal;
  }
  /**
   * @param retVal
   * @return
   */
  private boolean validateAttibuteFields() {
    boolean retVal = true;
    if (attributeSwitch.getSelectedKeys().size() == 1&&attribteRowAdderSubform.hasError()) {
      attributeSwitch.setErrorKey("form.easy.error.attribute", null);
      retVal = false;
      return retVal;
    }
    attributeSwitch.clearError();
    return retVal;
  }
 
  /**
   * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#initForm(org.olat.core.gui.components.form.flexible.FormItemContainer,
   *      org.olat.core.gui.control.Controller, org.olat.core.gui.UserRequest)
   */
  @Override
  @SuppressWarnings("unused")
  protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
   
    // the submit button
    subm = new FormSubmit("subm", "submit");
    formLayout.add(subm);
    // the reset button
    // FIXME:PB: why does rest not reset the form? Is there manual work involed?
    // Could not find help in other forms on this issue. Thanks for help! (fg)
//    reset = new FormReset("cancel", "cancel");
//    formLayout.add(reset);
    //
    // single selection radio button
    // disable/enables the rest of the form elements on yes/no choosing
    // register for >onclick<
    // "coachExclusive"
    addCoachExclusive(formLayout, listener);
    //
    // yes/no switch by Checkbox
    // disable/enables a date chooser field >from< and >to<
    // register for >onclick<
    // also the >from< and >to< date chooser fields are generated
    // "dateSwitch", "fromDate", "toDate"
    addFromToDateChooser(formLayout, listener);
    //
    // yes/no switch by Checkbox
    // enables/disables the easy group and area chooser
    // register for >onclick<
    // a texfield with a link associated for starting a subworkflow
    // -> choosing groups, -> choosing areas
    // choosing is simplified by opening a subworkflow presenting the possible
    // choices
    // with checkboxes.
    addEasyGroupAreaChoosers(formLayout, listener);
    //
    //
    addAssessmentSwitch(formLayout, listener);
    //
    if(ShibbolethModule.isEnableShibbolethLogins()){
      addAttributeSwitch(formLayout, listener, ureq);
    }
    flc.contextPut("shibbolethEnabled", new Boolean(ShibbolethModule.isEnableShibbolethLogins()));
    //
    addApplyRulesForTutorsToo(formLayout, listener);
    //
    // add rules
    addRules(formLayout);
  }

  private void addAttributeSwitch(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
    /*
     * yes / no chooser defines if learner do not see the building block at all
     */
    attributeSwitch = uifactory.addCheckboxesVertical("attributeSwitch", "form.easy.attributeSwitch", formLayout, new String[] { "ison" }, new String[] { "" }, null, 1);
    attributeSwitch.select("ison", validatedCondition.getAttributeConditions()!=null);
    // register for on click event to hide/disable other elements
    attributeSwitch.addActionListener(listener, FormEvent.ONCLICK);
    // rules are later added

    // add attribute connector: AND or OR
    final String[] attributebconnectorValues = new String[] { getTranslator().translate("form.easy.attributebconnector.and"),getTranslator().translate("form.easy.attributebconnector.or") };
    attributeBconnector = uifactory.addRadiosHorizontal("attributeBconnector", "form.easy.attributebconnector", formLayout, new String[] { BCON_VAL_AND, BCON_VAL_OR }, attributebconnectorValues);
    if(validatedCondition.isConditionsConnectorIsAND()){
      attributeBconnector.select(BCON_VAL_AND, true);
    }else{
      attributeBconnector.select(BCON_VAL_OR, true);
    }
   
    // add attribute condition rows
    attribteRowAdderSubform = new AttributeEasyRowAdderController(ureq, getWindowControl(), mainForm);
    flc.add(attribteRowAdderSubform.getFormItem());
   
    listenTo(attribteRowAdderSubform);
    flc.put("attribteRowAdderSubform", attribteRowAdderSubform.getInitialComponent());
    if (validatedCondition.getAttributeConditions() != null && validatedCondition.getAttributeConditions().size() > 0) {
      this.attribteRowAdderSubform.setAttributeConditions(validatedCondition.getAttributeConditions());
    }
  }

  /**
   * you may find here now the complexest rule set ever use in OLAT<br>
   * This form has a 5 switches<br>
   * <ul>
   * <li>[] 1 Learners only</li>
   * <li>[] 2 Date dependent</li>
   * <li>[] 3 Group dependent</li>
   * <li>[] 4 Assess dependent</li>
   * <li>[] 5 Apply rules also to coaches</li>
   * </ul>
   * enable [1] this greys out all others<br>
   * if one of [2] [3] or [4] is selected -> [5] becomes selectable<br>
   * selecting [2] [3] or [4] opens their respective subconfiguration<br>
   * "[2] date dependent" shows an end and startdate where at least one must be 
   * selected and the start date must be before the enddate.<br>
   * "[3] group dependent" shows a group or area input field. which takes group
   * or area names comma separated. the form evaluates if the areas or groups
   * exists, and if not, a quick fix is provided to create the missing groups/areas.
   * furthermore there is a "choose" button to choose groups/areas. This choose
   * button is named "create" if there are no groups or areas to choose from. If
   * create is clicked a create group/area workflow is started directly. If some
   * comma separated values are in the input field, it allows to create them at
   * once. At least an area or groupname must be specified, and all the specified
   * names must exist.<br>
   * "[4] assessment " allows to choose a node and to define a cut value or if
   * it should be checked for passed.<br>
   * To accomplish all the hiding, disabling, enabling, resetting to initial values
   * the following rules are added. this may look confusing, and it is confusing.
   * It took quite some days and testing until to get it right.
   * @param formLayout
   */
  private void addRules(FormItemContainer formLayout) {
   
    // disable date choosers if date switch is set to no
    // enable it otherwise.
    final Set<FormItem> dependenciesDateSwitch = new HashSet<FormItem>() {
      {
        add(toDate);
        add(fromDate);
        add(dateSubContainer);
      }
    };
   
    final Set<FormItem> dependenciesAttributeSwitch = new HashSet<FormItem>() {
      {
        // only add when initialized. is null when shibboleth module is not enabled
        if (ShibbolethModule.isEnableShibbolethLogins()) {
          add(attributeBconnector);
        }
      }
    };
   
    // show elements dependent on other values set.
    FormItemDependencyRule hideClearDateSwitchDeps = RulesFactory.createCustomRule(dateSwitch, null, dependenciesDateSwitch, formLayout);
    hideClearDateSwitchDeps.setDependencyRuleApplayable(new DependencyRuleApplayable() {
      @SuppressWarnings("unused")
      public void apply(FormItem triggerElement, Object triggerVal, Set<FormItem> targets) {
        toDate.setDate(null);
        toDate.setVisible(false);
        fromDate.setDate(null);
        fromDate.setVisible(false);
        toDate.clearError();
        fromDate.clearError();
        dateSwitch.clearError();
        dateSubContainer.setVisible(false);       
       
        fromDate.setFocus(false);
        /*
         * special rules for apply rules for coach and for assessment dependent
         */
        //assessment switch only enabled if nodes to be selected
        boolean coachExclIsOn = coachExclusive.getSelectedKeys().size() == 1;
        assessmentSwitch.setEnabled(!coachExclIsOn && (nodeIdentList.size() > || isSelectedNodeDeleted()));
                       
        boolean atLeastOneOn = dateSwitch.getSelectedKeys().size() == 1 || groupSwitch.getSelectedKeys().size() == 1 || assessmentSwitch.getSelectedKeys().size() == 1|| (attributeSwitch != null && attributeSwitch.getSelectedKeys().size()==1);
        if(!applyRulesForCoach.isEnabled() && atLeastOneOn){
          //not enabled AND at least another dependent on
          applyRulesForCoach.setEnabled(true);
        }else if(!atLeastOneOn){
          //enabled (or not) AND not at least another dependent on
          applyRulesForCoach.setEnabled(false);
          applyRulesForCoach.select("ison", true);
        }
      }
    });
    RulesFactory.createShowRule(dateSwitch, "ison", dependenciesDateSwitch, formLayout);
    FormItemDependencyRule toggleApplyRule = RulesFactory.createCustomRule(dateSwitch, "ison", dependenciesDateSwitch, formLayout);
    toggleApplyRule.setDependencyRuleApplayable(new DependencyRuleApplayable() {
      public void apply(FormItem triggerElement, Object triggerVal, Set<FormItem> targets) {

        fromDate.setFocus(true);
       
        //assessment switch only enabled if nodes to be selected
        assessmentSwitch.setEnabled((nodeIdentList.size() > || isSelectedNodeDeleted()));
               
        if(!applyRulesForCoach.isEnabled()){
          applyRulesForCoach.setEnabled(true);
        }
      }
    });
   
    if (ShibbolethModule.isEnableShibbolethLogins()) {
      FormItemDependencyRule hideClearAttibuteSwitchDeps = RulesFactory.createCustomRule(attributeSwitch, null, dependenciesAttributeSwitch, formLayout);
     
      hideClearAttibuteSwitchDeps.setDependencyRuleApplayable(new DependencyRuleApplayable() {
        @SuppressWarnings("unused")
        public void apply(FormItem triggerElement, Object triggerVal, Set<FormItem> targets) {
          attributeSwitch.clearError();
          attributeBconnector.select(BCON_VAL_AND, true);
          attributeBconnector.setVisible(false);
          if(attribteRowAdderSubform!=null){
            attribteRowAdderSubform.cleanup();
          }
          boolean atLeastOneOn = dateSwitch.getSelectedKeys().size() == 1 || groupSwitch.getSelectedKeys().size() == 1 || assessmentSwitch.getSelectedKeys().size() == 1||attributeSwitch.getSelectedKeys().size()==1;
          if(!applyRulesForCoach.isEnabled() && atLeastOneOn){
            //not enabled AND at least another dependent on
            applyRulesForCoach.setEnabled(true);
          }else if(!atLeastOneOn){
            //enabled (or not) AND not at least another dependent on
            applyRulesForCoach.setEnabled(false);
            applyRulesForCoach.select("ison", true);
          }
        }
      });
     
      RulesFactory.createShowRule(attributeSwitch, "ison", dependenciesAttributeSwitch, formLayout);
     
      FormItemDependencyRule attributeSwitchtoggleApplyRule = RulesFactory.createCustomRule(attributeSwitch, "ison", dependenciesAttributeSwitch, formLayout);
      attributeSwitchtoggleApplyRule.setDependencyRuleApplayable(new DependencyRuleApplayable() {
        public void apply(FormItem triggerElement, Object triggerVal, Set<FormItem> targets) {
          attributeBconnector.setVisible(true);
          if(attribteRowAdderSubform!=null){
            attribteRowAdderSubform.init();
          }
          if(!applyRulesForCoach.isEnabled()){
            applyRulesForCoach.setEnabled(true);
          }
        }
      });
    }
 
    //
    // enable textfields and subworkflow-start-links if groups is yes
    // disable it otherwise
    final Set<FormItem> dependenciesGroupSwitch = new HashSet<FormItem>() {
      {
        add(groupSubContainer);
        add(easyAreaTE);
        add(chooseAreasLink);
        add(createAreasLink);
        add(easyGroupTE);
        add(chooseGroupsLink);
        add(createGroupsLink);
      }
    };
    FormItemDependencyRule hideClearGroupSwitchDeps = RulesFactory.createCustomRule(groupSwitch, null, dependenciesGroupSwitch, formLayout);
    hideClearGroupSwitchDeps.setDependencyRuleApplayable(new DependencyRuleApplayable() {
      @SuppressWarnings("unused")
      public void apply(FormItem triggerElement, Object triggerVal, Set<FormItem> targets) {
        easyAreaTE.setValue("");
        easyGroupTE.setValue("");
        easyAreaTE.setVisible(false);
        easyGroupTE.setVisible(false);
        chooseAreasLink.setVisible(false);
        createAreasLink.setVisible(false);
        chooseGroupsLink.setVisible(false);
        createGroupsLink.setVisible(false);
        easyAreaTE.clearError();
        easyGroupTE.clearError();
        groupSwitch.clearError();
        groupSubContainer.setVisible(false);       
        if (ShibbolethModule.isEnableShibbolethLogins()) {
          attributeSwitch.clearError();
        }
        easyGroupTE.setFocus(false);
       
        //assessment switch only enabled if nodes to be selected
        boolean coachExclIsOn = coachExclusive.getSelectedKeys().size() == 1;
        assessmentSwitch.setEnabled(!coachExclIsOn && (nodeIdentList.size() > || isSelectedNodeDeleted()));
                               
        boolean atLeastOneOn = dateSwitch.getSelectedKeys().size() == 1 || groupSwitch.getSelectedKeys().size() == 1 || assessmentSwitch.getSelectedKeys().size() == 1||(attributeSwitch != null && attributeSwitch.getSelectedKeys().size()==1);
        if(!applyRulesForCoach.isEnabled() && atLeastOneOn){
          applyRulesForCoach.setEnabled(true);
        }else if(!atLeastOneOn){
          //enabled (or not) AND not at least another dependent on
          applyRulesForCoach.setEnabled(false);
          applyRulesForCoach.select("ison", true);
        }
      }
    });
    RulesFactory.createShowRule(groupSwitch, "ison", dependenciesGroupSwitch, formLayout);
    toggleApplyRule = RulesFactory.createCustomRule(groupSwitch, "ison", dependenciesGroupSwitch, formLayout);
    toggleApplyRule.setDependencyRuleApplayable(new DependencyRuleApplayable() {
      public void apply(FormItem triggerElement, Object triggerVal, Set<FormItem> targets) {

        easyGroupTE.setFocus(true);
       
        //assessment switch only enabled if nodes to be selected
        assessmentSwitch.setEnabled((nodeIdentList.size() > || isSelectedNodeDeleted()));
               
        if(!applyRulesForCoach.isEnabled()){
          applyRulesForCoach.setEnabled(true);
        }
      }
    });
   
    // 
    // dependencies of assessment switch
    final Set<FormItem> assessDeps = new HashSet<FormItem>() {
      {
        add(assessmentTypeSwitch);
        add(nodePassed);
        add(cutValue);
        add(assessSubContainer);
      }
    };

    // show elements dependent on other values set.
    FormItemDependencyRule showAssessmentSwitchDeps = RulesFactory.createCustomRule(assessmentSwitch, "ison", assessDeps, formLayout);
    showAssessmentSwitchDeps.setDependencyRuleApplayable(new DependencyRuleApplayable() {
      public void apply(FormItem triggerElement, Object triggerVal, Set<FormItem> targets) {
        boolean cutValueVisibility = assessmentTypeSwitch.getSelectedKey().equals(NODEPASSED_VAL_SCORE);
        assessSubContainer.setVisible(true);       
        assessmentTypeSwitch.setVisible(true);
        nodePassed.setVisible(true);
        cutValue.setVisible(cutValueVisibility);
        assessmentSwitch.clearError();
        cutValue.clearError();
        nodePassed.clearError();

        if(!applyRulesForCoach.isEnabled()){
          applyRulesForCoach.setEnabled(true);
        }
      }
    });

    // hide elements and reset values.
    FormItemDependencyRule hideResetAssessmentSwitchDeps = RulesFactory.createCustomRule(assessmentSwitch, null, assessDeps, formLayout);
    hideResetAssessmentSwitchDeps.setDependencyRuleApplayable(new DependencyRuleApplayable() {
      public void apply(FormItem triggerElement, Object triggerVal, Set<FormItem> targets) {
        assessSubContainer.setVisible(false);       
        assessmentTypeSwitch.select(NODEPASSED_VAL_PASSED, true);
        assessmentTypeSwitch.setVisible(false);
        nodePassed.select(NO_NODE_SELECTED_IDENTIFYER, true);
        nodePassed.setVisible(false);
        cutValue.setIntValue(0);
        cutValue.setVisible(false);

        boolean atLeastOneOn = dateSwitch.getSelectedKeys().size() == 1 || groupSwitch.getSelectedKeys().size() == 1 || assessmentSwitch.getSelectedKeys().size() == 1||(attributeSwitch != null && attributeSwitch.getSelectedKeys().size()==1);
        if(!applyRulesForCoach.isEnabled() && atLeastOneOn){
          applyRulesForCoach.setEnabled(true);
        }else if(!atLeastOneOn){
          //enabled (or not) AND not at least another dependent on
          applyRulesForCoach.setEnabled(false);
          applyRulesForCoach.select("ison", true);
        }
      }
    });

    final Set<FormItem> assessTypeDeps = new HashSet<FormItem>() {
      {
        add(cutValue);
      }
    };
    RulesFactory.createHideRule(assessmentTypeSwitch, NODEPASSED_VAL_PASSED, assessTypeDeps, assessSubContainer);
    RulesFactory.createShowRule(assessmentTypeSwitch, NODEPASSED_VAL_SCORE, assessTypeDeps, assessSubContainer);

    //
    //
    final Set<FormItem> dependenciesCoachExclusiveReadonly = new HashSet<FormItem>() {
      {
        addAll(dependenciesDateSwitch);
        addAll(dependenciesGroupSwitch);
        addAll(assessDeps);
        addAll(dependenciesAttributeSwitch);
      }
    };
    // coach exclusive switch rules
    // -> custom rule implementation because it is not a simple hide / show rule
    // while disabling reset the elements
    FormItemDependencyRule disableAndResetOthers = RulesFactory.createCustomRule(coachExclusive, "ison",
        dependenciesCoachExclusiveReadonly, formLayout);
    disableAndResetOthers.setDependencyRuleApplayable(new DependencyRuleApplayable() {
      public void apply(FormItem triggerElement, Object triggerVal, Set<FormItem> targets) {
        // disable and remove checkbox selection
        // uncheck and disable checkboxes
        dateSwitch.select("ison", false);
        groupSwitch.select("ison", false);
        assessmentSwitch.select("ison", false);
        dateSwitch.setEnabled(false);
        toDate.setDate(null);
        fromDate.setDate(null);
        groupSwitch.setEnabled(false);
        easyAreaTE.setValue("");
        easyGroupTE.setValue("");
        assessmentSwitch.setEnabled(false);
        // disable the shibboleth attributes switch and reset the row subform
        if (attributeSwitch != null) {
          attributeSwitch.select("ison", false);
          attributeSwitch.setEnabled(false);
          attribteRowAdderSubform.cleanup();
          attributeSwitch.clearError();
        }
        //opposite meaning! see creation of applyRulesForCoach
        applyRulesForCoach.select("ison", true);
        applyRulesForCoach.setEnabled(false);
        // hide (e.g. remove) general erros
        dateSwitch.clearError();
        groupSwitch.clearError();
        assessmentSwitch.clearError();

       
        // all dependent elements become invisible
        for (Iterator<FormItem> iter = dependenciesCoachExclusiveReadonly.iterator(); iter.hasNext();) {
          FormItem element = iter.next();
          element.setVisible(false);
        }
      }
    });

    // two rules to bring them back visible and also checkable
    // dependencies of assessment switch
    final Set<FormItem> switchesOnly = new HashSet<FormItem>() {
      {
        add(dateSwitch);
        add(groupSwitch);
        add(assessmentSwitch);
        add(applyRulesForCoach);
        if (ShibbolethModule.isEnableShibbolethLogins()) {
          add(attributeSwitch);
        }
      }
    };
    FormItemDependencyRule enableOthers = RulesFactory.createCustomRule(coachExclusive, null, switchesOnly, formLayout);
    enableOthers.setDependencyRuleApplayable(new DependencyRuleApplayable() {
      private boolean firedDuringInit = true;
      public void apply(FormItem triggerElement, Object triggerVal, Set<FormItem> targets) {
        dateSwitch.setEnabled(true);
        groupSwitch.setEnabled(true);
        //assessment switch only enabled if nodes to be selected
        assessmentSwitch.setEnabled((nodeIdentList.size() > || isSelectedNodeDeleted()));
               
        //default is a checked disabled apply rules for coach
        if (ShibbolethModule.isEnableShibbolethLogins()) {
          attributeSwitch.setEnabled(true);
        }
        if(!firedDuringInit){
          applyRulesForCoach.select("ison", true);
          applyRulesForCoach.setEnabled(false);
        }
        firedDuringInit = false;
      }
    });
   

  }

  /*
   * methods to add elements
   */
  /**
   * @param formLayout
   * @param listener
   */
  private void addCoachExclusive(FormItemContainer formLayout, Controller listener) {
    /*
     * yes / no chooser defines if learner do not see the building block at all
     */
    coachExclusive = uifactory.addCheckboxesHorizontal("coachExclusive", null, formLayout, new String[] { "ison" }, new String[] { translate("form.easy.coachExclusive") }, null);
    boolean coachesAndAdminsInitValue = validatedCondition.isEasyModeCoachesAndAdmins();
    coachExclusive.select("ison", coachesAndAdminsInitValue);
   
    // register for on click event to hide/disable other elements
    coachExclusive.addActionListener(listener, FormEvent.ONCLICK);
    // rules are later added
  }

  /**
   * @param formLayout
   * @param listener
   */
  @SuppressWarnings("unused")
  private void addApplyRulesForTutorsToo(FormItemContainer formLayout, Controller listener) {
    /*
     * yes / no chooser defines if learner do not see the building block at all
     */
    applyRulesForCoach = uifactory.addCheckboxesHorizontal("applyRulesForCoach", null, formLayout, new String[] { "ison" }, new String[] { translate("form.easy.applyRulesForCoach") }, null);
    //note that in the condition this rule is saved with the opposite meaning:
    // true when
    // coach and admins always have access, false when rule should apply also to
    // them
    boolean alwaysAllowCoachesAndAdminsInitValue = validatedCondition.isEasyModeAlwaysAllowCoachesAndAdmins();
    if (alwaysAllowCoachesAndAdminsInitValue) {
      applyRulesForCoach.select("ison", false);
    } else {
      applyRulesForCoach.select("ison", true);
    }
  }

  /**
   * @param formLayout
   * @param listener
   */
  private void addFromToDateChooser(FormItemContainer formLayout, Controller listener) {
    /*
     * yes / no switch if a date.time constraint is defined
     */
    dateSubContainer = (FormItemContainer) FormLayoutContainer.createDefaultFormLayout("dateSubContainer", getTranslator());
    formLayout.add(dateSubContainer);

    fromDate = new JSDateChooser("fromDate", validatedCondition.getEasyModeBeginDate()) {
      {
        setLabel("form.easy.bdate", null);
        displaySize = 17;
        setExampleKey("form.easy.example.bdate", null);
        // time is enabled
        setDateChooserTimeEnabled(true);
        // not i18n'ified yet
        setDateChooserDateFormat("%d.%m.%Y %H:%M");
        setCustomDateFormat("dd.MM.yyyy HH:mm");
        displaySize = getExampleDateString().length();
      }
    };
    dateSubContainer.add(fromDate);
   
    toDate = new JSDateChooser("toDate", validatedCondition.getEasyModeEndDate()) {
      {
        setLabel("form.easy.edate", null);
        setExampleKey("form.easy.example.edate", null);
        // time is enabled
        setDateChooserTimeEnabled(true);
        // not i18n'ified yet
        setDateChooserDateFormat("%d.%m.%Y %H:%M");
        setCustomDateFormat("dd.MM.yyyy HH:mm");
        setDisplaySize(getExampleDateString().length());
      }
    };
    dateSubContainer.add(toDate);

    dateSwitch = uifactory.addCheckboxesHorizontal("dateSwitch", null, formLayout, new String[] { "ison" }, new String[] { translate("form.easy.dateSwitch") }, null);
    if (fromDate.getDate() != null || toDate.getDate() != null) {
      dateSwitch.select("ison", true);
    } else {
      dateSwitch.select("ison", false);
    }
    dateSwitch.addActionListener(listener, FormEvent.ONCLICK);
  }

  /**
   * @param formLayout
   * @param listener
   */
  private void addEasyGroupAreaChoosers(FormItemContainer formLayout, Controller listener) {

    groupSubContainer = (FormItemContainer) FormLayoutContainer.createDefaultFormLayout("groupSubContainer", getTranslator());
    formLayout.add(groupSubContainer);

    String groupInitVal = validatedCondition.getEasyModeGroupAccess();
    String areaInitVal = validatedCondition.getEasyModeGroupAreaAccess();

    groupSwitch = uifactory.addCheckboxesHorizontal("groupSwitch", null, formLayout, new String[] { "ison" }, new String[] { translate("form.easy.groupSwitch") }, null);
    // initialise selection
    if (groupInitVal != null || areaInitVal != null) {
      groupSwitch.select("ison", true);
    } else {
      groupSwitch.select("ison", false);
    }
    groupSwitch.addActionListener(listener, FormEvent.ONCLICK);
   
    //
    groupChooseSubContainer = (FormLayoutContainer)FormLayoutContainer.createHorizontalFormLayout("groupChooseSubContainer", getTranslator());
    groupChooseSubContainer.setLabel("form.easy.group", null);
    groupSubContainer.add(groupChooseSubContainer);   

    easyGroupTE = uifactory.addTextElement("group", null, 1024, groupInitVal, groupChooseSubContainer);
    easyGroupTE.setDisplaySize(24);
    easyGroupTE.setExampleKey("form.easy.example.group", null);
    /*
     * check for defaultcontext
     */
    boolean hasDefaultContext = getDefaultBGContext() != null;
    //
    chooseGroupsLink = new FormLinkImpl("choosegroups", "choose");
    chooseGroupsLink.setCustomEnabledLinkCSS("b_form_groupchooser");
   
    // prepare create groups link which is used instead of chooseGroupsLink in
    // the
    // case where no groups are configured in the groupmanagement
    createGroupsLink = new FormLinkImpl("choosegroups", "create");
    createGroupsLink.setCustomEnabledLinkCSS("b_form_groupchooser");
   
    // create groups if no groups in groupmanagement, and default context
    // available
    groupChooseSubContainer.add(hasDefaultContext && !hasGroups ? createGroupsLink : chooseGroupsLink);
   
    //
    areaChooseSubContainer = (FormLayoutContainer)FormLayoutContainer.createHorizontalFormLayout("areaChooseSubContainer", getTranslator());
    areaChooseSubContainer.setLabel("form.easy.area", null);
    groupSubContainer.add(areaChooseSubContainer);   

    easyAreaTE = uifactory.addTextElement("area", null, 1024, areaInitVal, areaChooseSubContainer);
    easyAreaTE.setExampleKey("form.easy.example.area", null);
   
    chooseAreasLink = new FormLinkImpl("chooseareas", "choose");
    chooseAreasLink.setCustomEnabledLinkCSS("b_form_groupchooser");

    // prepare create are link which is used instead of choose area link in the
    // case where no areas are configured in the groupmanagement
    createAreasLink = new FormLinkImpl("chooseareas", "create");
    createAreasLink.setCustomEnabledLinkCSS("b_form_groupchooser");

    areaChooseSubContainer.add(hasDefaultContext && !hasAreas ? createAreasLink : chooseAreasLink);
  }

  private void addAssessmentSwitch(FormItemContainer formLayout, Controller listener) {

    assessSubContainer = (FormItemContainer) FormLayoutContainer.createDefaultFormLayout("assessSubContainer", getTranslator());
    formLayout.add(assessSubContainer);

    Translator translator = getTranslator();

    final String[] assessmentSwitchKeys = new String[] { NODEPASSED_VAL_PASSED, NODEPASSED_VAL_SCORE };
    final String[] assessmentSwitchValues = new String[] { translator.translate("form.easy.assessmentSwitch.passed"),
        translator.translate("form.easy.assessmentSwitch.score") };

    String nodePassedInitVal = validatedCondition.getEasyModeNodePassedId();
    String cutInitStrValue = validatedCondition.getEasyModeCutValue();
    int cutInitValue = 0;
   
    assessmentSwitch = uifactory.addCheckboxesHorizontal("assessmentSwitch", null, formLayout, new String[] { "ison" }, new String[] { translate("form.easy.assessmentSwitch") }, null);
    assessmentSwitch.addActionListener(listener, FormEvent.ONCLICK);
   

    boolean selectedNodeIsInList = false;
    List<String> keysList = new ArrayList<String>();
    List<String> valuesList = new ArrayList<String>();
    if (nodeIdentList.size() > 0) {
      // there are nodes to be selected
      keysList.add(NO_NODE_SELECTED_IDENTIFYER);
      valuesList.add("- " + translator.translate("form.easy.nodePassed.select") + " -");
      for (int i = 0; i < nodeIdentList.size(); i++) {
        CourseNode courseNode = (CourseNode) nodeIdentList.get(i);
        keysList.add(courseNode.getIdent());
        valuesList.add(courseNode.getShortName() + " (Id:" + courseNode.getIdent() + ")");
        if (courseNode.getIdent().equals(nodePassedInitVal)) selectedNodeIsInList = true;
      }
    } else {
      // no nodes to be selected
      keysList.add(NO_NODE_SELECTED_IDENTIFYER);
      valuesList.add("- " + translator.translate("form.easy.nodePassed.noNodes"));
      //disable switch
      assessmentSwitch.setEnabled(false);
    }
    // add dummy value if needed
    if (nodePassedInitVal != null && !selectedNodeIsInList) {
      keysList.add(DELETED_NODE_IDENTIFYER);
      valuesList.add("- " + translator.translate("form.easy.nodePassed.deletedNode") + " -");
    }
    final String[] nodePassedKeys = new String[keysList.size()];
    keysList.toArray(nodePassedKeys);
    final String[] nodePassedValues = new String[valuesList.size()];
    valuesList.toArray(nodePassedValues);

    // list of assessable nodes is wrapped in a layout container for proper rendering
    assessNodesListContainer = (FormLayoutContainer)FormLayoutContainer.createSelbox("assNodesListContainer", getTranslator());
    assessNodesListContainer.setLabel("form.easy.nodePassed", null);
    assessSubContainer.add(assessNodesListContainer);
    nodePassed = new SingleSelectionImpl("nodePassed", assessNodesListContainer) {
      {
        keys = nodePassedKeys;
        values = nodePassedValues;
      }
    };
   
    if (nodePassedInitVal != null) {
      if (selectedNodeIsInList) {
        nodePassed.select(nodePassedInitVal, true);
      } else {
        nodePassed.select(DELETED_NODE_IDENTIFYER, true);
      }
    } else {
      nodePassed.select(NO_NODE_SELECTED_IDENTIFYER, true);
    }
    assessNodesListContainer.add(nodePassed);
   
    assessmentTypeSwitch = new SingleSelectionImpl("assessmentTypeSwitch", SingleSelectionImpl.createVerticalLayout("yingyang")) {
      {
        keys = assessmentSwitchKeys;
        values = assessmentSwitchValues;
      }
    };
    assessmentTypeSwitch.setLabel("form.easy.assessmentSwitch.type", null);
    assessmentTypeSwitch.addActionListener(listener, FormEvent.ONCLICK);

    if (nodePassedInitVal != null) {
      // has a node configured
      if (cutInitStrValue == null) {
        // with cut value
        assessmentTypeSwitch.select(NODEPASSED_VAL_PASSED, true);
      } else {
        cutInitValue = Integer.valueOf(cutInitStrValue);
        assessmentTypeSwitch.select(NODEPASSED_VAL_SCORE, true);
      }
      assessmentSwitch.select("ison", true);
      assessmentTypeSwitch.setVisible(true);
    } else {
      assessmentSwitch.select("ison", false);
      assessmentTypeSwitch.setVisible(false);
      assessmentTypeSwitch.select(NODEPASSED_VAL_PASSED, true);
    }
    assessSubContainer.add(assessmentTypeSwitch);
   
    cutValue = uifactory.addIntegerElement("cutval", "form.easy.cutValue", cutInitValue, assessSubContainer);
    cutValue.setDisplaySize(3);
  }

  /*
   * HELPER METHODS AFTER HERE
   */
  private Condition cloneCondition(Condition orig) {
    try {
      return (Condition) orig.clone();
    } catch (CloneNotSupportedException e) {
      throw new AssertException("could not clone condition " + orig, e);
      //
    }
  }

  public Condition getCondition() {
    return validatedCondition;
  }

  /**
   * gets called if other condition edit controller on the same screen has
   * created groups or areas and informs other condition edit controller to
   * update for example the "create link" to "choose link"
   *
   */
  public void updateGroupsAndAreasCheck() {
    boolean oldHasAreas = hasAreas;
    boolean oldHasGroups = hasGroups;
    hasAreas = courseEditorEnv.getCourseGroupManager().getAllAreasFromAllContexts().size() > 0;
    hasGroups = courseEditorEnv.getCourseGroupManager().getAllLearningGroupsFromAllContexts().size() > 0;
    if(oldHasAreas != hasAreas && hasAreas){
      // toggle prepared links (create -> choose)
      flc.remove(createAreasLink);
      flc.add(chooseAreasLink);
    }
    if(oldHasGroups != hasGroups && hasGroups){
      // toggle prepared links (create -> choose)
      flc.remove(createGroupsLink);
      flc.add(chooseGroupsLink);
    }
  }
     
  /**
   * It checks if the selected EasyModeNodePassedId is not null, while the assessable node list is empty,
   * and it enables the assessmentSwitch.
   *
   * @return
   */
  private boolean isSelectedNodeDeleted() {
    String nodePassedInitVal = validatedCondition.getEasyModeNodePassedId();
    if(nodePassedInitVal!=null && nodeIdentList.size()==0) {     
      assessmentSwitch.setEnabled(true);
           
      return true;
    }
    return false;
  }
}
TOP

Related Classes of org.olat.course.condition.ConditionConfigEasyController

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.