/** Wraps a RuleModellerWidget with an icon to delete the pattern */
  private Widget wrapLHSWidget(final CompositeFactPattern model, int i, RuleModellerWidget w) {
    DirtyableHorizontalPane horiz = new DirtyableHorizontalPane();

    final Image remove = GuidedRuleEditorImages508.INSTANCE.DeleteItemSmall();
    remove.setTitle(
        Constants.INSTANCE.RemoveThisENTIREConditionAndAllTheFieldConstraintsThatBelongToIt());
    final int idx = i;
    remove.addClickHandler(
        new ClickHandler() {

          public void onClick(ClickEvent event) {
            if (Window.confirm(Constants.INSTANCE.RemoveThisEntireConditionQ())) {
              if (pattern.removeFactPattern(idx)) {
                getModeller().refreshWidget();
              }
            }
          }
        });

    horiz.setWidth("100%");
    w.setWidth("100%");

    horiz.add(w);
    if (!(getModeller().lockLHS() || w.isReadOnly())) {
      horiz.add(remove);
    }

    return horiz;
  }
  protected void doLayout() {
    this.layout.setWidget(0, 0, getCompositeLabel());
    this.layout.getFlexCellFormatter().setColSpan(0, 0, 2);

    // this.layout.getFlexCellFormatter().setWidth(0, 0, "15%");
    this.layout.setWidget(1, 0, new HTML("    "));

    if (this.pattern.getPatterns() != null) {
      DirtyableVerticalPane vert = new DirtyableVerticalPane();
      IFactPattern[] facts = pattern.getPatterns();
      for (int i = 0; i < facts.length; i++) {
        RuleModellerWidget widget =
            this.getModeller()
                .getWidgetFactory()
                .getWidget(this.getModeller(), this.getEventBus(), facts[i], this.readOnly);
        widget.addOnModifiedCommand(
            new Command() {
              public void execute() {
                setModified(true);
              }
            });

        // Wrap widget so the Fact pattern can be deleted
        vert.add(wrapLHSWidget(pattern, i, widget));
        vert.add(spacerWidget());
      }
      this.layout.setWidget(1, 1, vert);
    }
  }
  @Override
  protected Widget getCompositeLabel() {
    ClickHandler leftPatternclick =
        new ClickHandler() {

          public void onClick(ClickEvent event) {
            Widget w = (Widget) event.getSource();
            showFactTypeSelector(w);
          }
        };
    ClickHandler sourcePatternClick =
        new ClickHandler() {

          public void onClick(ClickEvent event) {
            Widget w = (Widget) event.getSource();
            showSourcePatternSelector(w);
          }
        };

    String lbl =
        "<div class='form-field'>" + HumanReadable.getCEDisplayName("from accumulate") + "</div>";

    DirtyableFlexTable panel = new DirtyableFlexTable();

    int r = 0;

    if (pattern.getFactPattern() == null) {
      panel.setWidget(
          r++,
          0,
          new ClickableLabel(
              "<br> <font color='red'>"
                  + GuidedRuleEditorResources.CONSTANTS.clickToAddPattern()
                  + "</font>",
              leftPatternclick,
              !this.readOnly));
    }

    panel.setWidget(r++, 0, new HTML(lbl));

    if (this.getFromAccumulatePattern().getSourcePattern() == null) {
      panel.setWidget(
          r++,
          0,
          new ClickableLabel(
              "<br> <font color='red'>"
                  + GuidedRuleEditorResources.CONSTANTS.clickToAddPattern()
                  + "</font>",
              sourcePatternClick,
              !this.readOnly));
    } else {
      IPattern rPattern = this.getFromAccumulatePattern().getSourcePattern();

      RuleModellerWidget sourcePatternWidget;
      if (rPattern instanceof FactPattern) {
        sourcePatternWidget =
            new FactPatternWidget(
                this.getModeller(), getEventBus(), rPattern, true, true, this.readOnly);

      } else if (rPattern instanceof FromAccumulateCompositeFactPattern) {
        sourcePatternWidget =
            new FromAccumulateCompositeFactPatternWidget(
                this.getModeller(),
                this.getEventBus(),
                (FromAccumulateCompositeFactPattern) rPattern,
                this.readOnly);

      } else if (rPattern instanceof FromCollectCompositeFactPattern) {
        sourcePatternWidget =
            new FromCollectCompositeFactPatternWidget(
                this.getModeller(),
                this.getEventBus(),
                (FromCollectCompositeFactPattern) rPattern,
                this.readOnly);

      } else if (rPattern instanceof FromEntryPointFactPattern) {
        sourcePatternWidget =
            new FromEntryPointFactPatternWidget(
                this.getModeller(),
                this.getEventBus(),
                (FromEntryPointFactPattern) rPattern,
                this.readOnly);

      } else if (rPattern instanceof FromCompositeFactPattern) {
        sourcePatternWidget =
            new FromCompositeFactPatternWidget(
                this.getModeller(),
                this.getEventBus(),
                (FromCompositeFactPattern) rPattern,
                this.readOnly);
      } else {
        throw new IllegalArgumentException(
            "Unsupported pattern " + rPattern + " for right side of FROM ACCUMULATE");
      }

      sourcePatternWidget.addOnModifiedCommand(
          new Command() {
            public void execute() {
              setModified(true);
            }
          });

      panel.setWidget(
          r++,
          0,
          addRemoveButton(
              sourcePatternWidget,
              new ClickHandler() {

                public void onClick(ClickEvent event) {
                  if (Window.confirm(GuidedRuleEditorResources.CONSTANTS.RemoveThisBlockOfData())) {
                    setModified(true);
                    getFromAccumulatePattern().setSourcePattern(null);
                    getModeller().refreshWidget();
                  }
                }
              }));
    }

    // REVISIT: Nested TabLayoutPanel does not work, its content is truncated.
    // TabLayoutPanel tPanel = new TabLayoutPanel(2, Unit.EM);
    TabPanel tPanel = new TabPanel();

    DirtyableFlexTable codeTable = new DirtyableFlexTable();
    int codeTableRow = 0;
    int codeTableCol = 0;

    codeTable.setWidget(
        codeTableRow,
        codeTableCol++,
        new HTML(
            "<div class='form-field'>" + GuidedRuleEditorResources.CONSTANTS.Init() + ":</div>"));

    final TextBox initField = new TextBox();
    initField.setTitle(GuidedRuleEditorResources.CONSTANTS.InitCode());
    initField.setText(getFromAccumulatePattern().getInitCode());
    initField.setEnabled(!this.readOnly);
    codeTable.setWidget(codeTableRow++, codeTableCol--, initField);

    codeTable.setWidget(
        codeTableRow,
        codeTableCol++,
        new HTML(
            "<div class='form-field'>" + GuidedRuleEditorResources.CONSTANTS.Action() + ":</div>"));
    final TextBox actionField = new TextBox();
    actionField.setTitle(GuidedRuleEditorResources.CONSTANTS.ActionCode());
    actionField.setText(getFromAccumulatePattern().getActionCode());
    actionField.setEnabled(!this.readOnly);
    codeTable.setWidget(codeTableRow++, codeTableCol--, actionField);

    codeTable.setWidget(
        codeTableRow,
        codeTableCol++,
        new HTML(
            "<div class='form-field'>"
                + GuidedRuleEditorResources.CONSTANTS.Reverse()
                + ":</div>"));
    final TextBox reverseField = new TextBox();
    reverseField.setTitle(GuidedRuleEditorResources.CONSTANTS.ReverseCode());
    reverseField.setText(getFromAccumulatePattern().getReverseCode());
    reverseField.setEnabled(!this.readOnly);
    codeTable.setWidget(codeTableRow++, codeTableCol--, reverseField);

    codeTable.setWidget(
        codeTableRow,
        codeTableCol++,
        new HTML(
            "<div class='form-field'>" + GuidedRuleEditorResources.CONSTANTS.Result() + ":</div>"));
    final TextBox resultField = new TextBox();
    resultField.setTitle(GuidedRuleEditorResources.CONSTANTS.ResultCode());
    resultField.setText(getFromAccumulatePattern().getResultCode());
    resultField.setEnabled(!this.readOnly);
    codeTable.setWidget(codeTableRow++, codeTableCol--, resultField);

    // panel.setWidget(r++, 0, codeTable);
    ScrollPanel codePanel = new ScrollPanel();
    codePanel.add(codeTable);

    tPanel.add(codePanel, GuidedRuleEditorResources.CONSTANTS.CustomCode());

    DirtyableFlexTable functionTable = new DirtyableFlexTable();

    functionTable.setWidget(
        0,
        0,
        new HTML(
            "<div class='form-field'>"
                + GuidedRuleEditorResources.CONSTANTS.Function()
                + ":</div>"));
    final TextBox functionField = new TextBox();
    functionField.setTitle(GuidedRuleEditorResources.CONSTANTS.FunctionCode());
    functionField.setText(getFromAccumulatePattern().getFunction());
    functionField.setEnabled(!this.readOnly);
    functionTable.setWidget(0, 1, functionField);

    //        panel.setWidget(r++, 0, functionTable);

    ScrollPanel functionPanel = new ScrollPanel();
    functionPanel.add(functionTable);

    tPanel.add(functionPanel, GuidedRuleEditorResources.CONSTANTS.Function());
    ChangeHandler changehandler =
        new ChangeHandler() {

          public void onChange(ChangeEvent event) {
            Widget sender = (Widget) event.getSource();
            TextBox senderTB = (TextBox) event.getSource();
            String code = senderTB.getText();
            setModified(true);
            if (sender == initField) {
              getFromAccumulatePattern().setFunction(null);
              functionField.setText("");
              getFromAccumulatePattern().setInitCode(code);
            } else if (sender == actionField) {
              getFromAccumulatePattern().setFunction(null);
              functionField.setText("");
              getFromAccumulatePattern().setActionCode(code);
            } else if (sender == reverseField) {
              getFromAccumulatePattern().setFunction(null);
              functionField.setText("");
              getFromAccumulatePattern().setReverseCode(code);
            } else if (sender == resultField) {
              getFromAccumulatePattern().setFunction(null);
              functionField.setText("");
              getFromAccumulatePattern().setResultCode(code);
            } else if (sender == functionField) {
              getFromAccumulatePattern().clearCodeFields();
              initField.setText("");
              actionField.setText("");
              reverseField.setText("");
              resultField.setText("");
              getFromAccumulatePattern().setFunction(code);
            }
          }
        };

    initField.addChangeHandler(changehandler);
    actionField.addChangeHandler(changehandler);
    reverseField.addChangeHandler(changehandler);
    resultField.addChangeHandler(changehandler);
    functionField.addChangeHandler(changehandler);

    boolean useFunction =
        getFromAccumulatePattern()
            .useFunctionOrCode()
            .equals(FromAccumulateCompositeFactPattern.USE_FUNCTION);

    tPanel.selectTab(useFunction ? 1 : 0);

    panel.setWidget(r++, 0, tPanel);

    return panel;
  }