sclass G22Utils {
  settable BackgroundProcessesUI backgroundProcessesUI;
  settable Enterable module;
  settable G22MasterStuff masterStuff;
  settable Concepts concepts;
  
  gettable CombinedStringifier stringifier = new(
    o -> o cast BufferedImage ? "Image (" + o.getWidth() + "*" + o.getHeight() + " px)" : null
  );
  
  ImageSurface stdImageSurface() {
    var is = pixelatedImageSurface().setAutoZoomToDisplay(true).repaintInThread(false);
    is.specialPurposed = true;
    new ImageSurface_PositionToolTip(is);
    ret is;
  }

  ImageSurface stdImageSurface(BufferedImage etc img) {
    var is = stdImageSurface();
    is.setImage(img);
    ret is;
  }
  
  S stringify(O o) { ret stringifier.toString(o); }
  
  swappable void modifyLeftArrowParser(GazelleV_LeftArrowScriptParser parser) {}
  
  GazelleV_LeftArrowScriptParser leftArrowParser() {
    new GazelleV_LeftArrowScriptParser parser;
    parser.g22utils(this);
    modifyLeftArrowParser(parser);
    ret parser;
  }
  
  void basicParserTest() {
    var parser = leftArrowParser();
    print(classContainerPrefixes := parser.classContainerPrefixes());
    assertEquals(pair(1, 2), parser.parse("new Pair 1 2")!);
  }

  ifclass JLeftArrowScriptIDE
  JLeftArrowScriptIDE leftArrowIDE() {
    new JLeftArrowScriptIDE ide;
    ide.g22utils(this);
    ide.modifyParser = modifyLeftArrowParser;
    ret ide;
  }
  endif
  
  File byteCodePath() {
    ret assertNotNull(getBytecodePathForClass(this));
  }

  simplyCached ClassNameResolver classNameResolver() {
    ret new ClassNameResolver().byteCodePath(byteCodePath()).init();
  }
  
  File databasesMotherDir() {
    ret javaxDataDir("Gazelle-22");
  }
  
  AutoCloseable enter() { ret module?.enter(); }
  
  S defaultDBName() { ret "Default"; }
  
  File lastOpenedDBFile() {
    ret newFile(databasesMotherDir(), "Last Opened");
  }
  
  S dbToOpen() {
    S name = loadTextFile(lastOpenedDBFile());
    if (nempty(name) && fileExists(newFile(databasesMotherDir(), name)))
      ret name;
    ret defaultDBName();
  }
  
  void openedDB(File dbDir) {
    if (sameFile(databasesMotherDir(), dirOfFile(dbDir)))
      saveTextFile(lastOpenedDBFile(), fileName(dbDir));
  }
  
  ifclass SimpleCRUD_v2
  <A extends G22LeftArrowScript> void setupScriptCRUD(SimpleCRUD_v2<A> crud) {
    crud.useNewChangeHandler(true);
    crud.multiLineField("text");
    crud.multiLineField("editingText");
    crud.makeTextArea = text -> jMinHeight(200, crud.makeTextArea_base(text));
    crud.humanizeFieldNames = false;
    crud.iconButtons(true);
    crud.itemToMap_inner2 = c
      -> litorderedmap(
        "Description" := str(c),
        "LoC" := n2(linesOfCode_javaTok(c.text)));
  }
  endif
}