!7

concept Scenario {
  S name;
  LS conditions;
  LS actions;

  toString { ret "Scenario " + quote(name); }
}

cmodule Scenarios > DynCRUD<Scenario> {
  transient Scenario selected;
  new L<UndoableWithAnswer> undoList;

  Scenario findConceptWithName(S name) {
    ret conceptWhereCI Scenario(+name);
  }
  
  S answer(S s) {
    ret dm_q(() -> {
      print("answering: " + s);
      new Matches m;

      // undo actions
      
      if "undo" ret singleUndo();
      if "anything to undo"
        ret empty(undoList) ? "Nothing to undo" : n2(undoList, "undoable action");
      if "clear undos" ret "OK" with clearUndos();

      // scenario actions
      
      if "how many scenarios"
        ret str(countConcepts(Scenario));
      if "delete scenario *" {
        S name = $1;
        setField(selected := null);
        Scenario sc = findConceptWithName(name);
        if (sc == null)
 ret format("Scenario * not found", name);
        unregisterConcept(sc);
        addUndo(new UndoDeleteConcept(sc));
        ret format("Scenario * deleted", name);
      }
      if "new scenario *" {
        S name = $1;
        Scenario sc = conceptWhereCI Scenario(+name);
        if (sc != null)
          ret format("Scenario * exists", name);
        setField(selected := uniqCI Scenario(+name));
        addUndo(new UndoCreateConcept(selected.id));
        ret format("Scenario * created", name);
      }
      if "list scenarios"
        ret or2(joinWithComma(collect name(list(Scenario))), "No scenarios defined");
      if "rename scenario * to *" {
        S name1 = $1, name2 = $2;
        if (!eqic(name1, name2)
          && conceptWhereCI Scenario(name := name2) != null)
          ret format("A scenario named * exists", name2);
        Scenario sc = findConceptWithName(name1);
        if (sc == null)
          ret format("Scenario * not found", name1);
        addUndo(new UndoSetConceptField(sc.id, 'name, name1, name2));
        cset(sc, name := name2);
        ret format("Scenario * renamed to *", name1, name2);
      }

      null;
    });
  }

  void addUndo(UndoableWithAnswer undo) {
    if (undo == null) ret;
    undoList.add(undo);
    change();
    print("Undo added: " + undo);
  }

  afterVisualize {
    addComponent(crud.buttons, jbutton("Talk to me", rThread talkToMe));
  }

  void talkToMe enter { dm_showConversationPopupForModule(); }

  void clearUndos q {
    if (empty(undoList)) ret;
    undoList.clear();
    change;
    print("Undo list cleared");
  }

  S singleUndo() {
    UndoableWithAnswer undo = popLast(undoList);
    if (undo == null) ret "Nothing to undo";
    change();
    ret or2(undo.undo(), "Last action undone");
  }

  // API

  UndoableWithAnswer lastUndo() {
    ret dm_q(() -> last(undoList));
  }
}