!7

module ShowRandomColor > DynModule {
  RGB color;
  S myGuess, yourName, lastOverwrite;
  bool voiceMode = true; // voice input & output
  
  transient double maxDiff = 0.25; // max difference to assume it's a similar color
  transient JPanel colorPanel;
  transient JTextField tfYourName;
  transient JButton btnSave;
  transient Pair<S, Double> closestColor;
  
  enhanceFrame {
    onInternalFrameDeactivated(f/JInternalFrame, r {
      dm_hideYesPopupForComponent(btnSave)
    });
    growInternalFrameLeft(f, 250); // space to type
    growInternalFrameSouth(f, 150); // space to see the color
  }
  
  visualize {
    dm_showTalkingSmiley();
    if (color == null) setField(color := makeRandomColor());
    dm_onTopInput_q(voidfunc(S s) {
      if (!licensed()) ret;
      //if (!dm_isActiveModule(module())) ret with print("not active");
      if (!voiceMode) ret;
      S _lastOverwrite = lastOverwrite;
      setField(lastOverwrite := null);
      JComponent popup = dm_generalMap_get('yesPopup);
      if "no problem|stop listening|thanks" {}
      else if (containsWord(s, "reload")) dm_reloadModuleInBackground();
      else if (match_vbar("accept|except|save|definitely|and if it is|is if it is right|is this|right|enter|submit|send|you got it|close enough|that it is|bingo|confirm|confirming|confirmed|i said yes|it is|surely|is this the man|guess my man|just|sieve|yesterday's", s)
        || matchStart_vbar("yes|yeah|yep|yay|absolutely|correct|you can say that|chore|sure|is yes|okay|ok|that's correct|you are right|you're right|you're correct", s)
        || matchEnd_vbar("that's right|got it|could say that|could say so|that's it|couldn't be anything else", s)) {
        confirm();
      } else if "no|nope|undo|scratch that|scrap that|oops|oopsie" {
        removeFromParent(popup);
        if (_lastOverwrite != null) {
          setField(yourName := _lastOverwrite);
          dm_say(oneOf("oops", "oopsie", "sorry"));
        } else
          dm_say("What is it then?");
      } else if (matchStart_vbar("no idea", s)) {
        dm_say("OK I'll move on.");
        newColor();
      } else if (matchStart_vbar("new|next|another|hit me|again|do it again", dropPrefix_repeat_matchVBar("give me|a", s)))
        newColor();
      else {
        print("Got input: " + s);
        
        // "that is" is often heard as "what is"
        S stuff = "no|actually|maybe|I think|it's|that's|this is|it is|that is|that looks like|I guess|or something|I'd call that|I would call that|I would say|I'd call it|Some call it|Some people call it|is what it is|definitely|of course|well|rather|confirmed|called|that would be called|I say|I said|damn it|what is|make that|a|my friend|buddy|you silly thing|or|just|simply|straight|plain|normal|simple|nothing but|really|good old|plain old|what's|playing|pure|dude|my man|let's|sir|is this|confirmed|confirming";
        s = dropPrefix_repeat_matchVBar(stuff, s);
        s = dropSuffix_repeat_matchVBar(stuff, s);
        s = replaceWords(s, "blew", "blue", "great", "gray", "grey", "gray", "read", "red");
        print("Simplified to: " + s);
        if (empty(s)) ret;
        if (eqic(s, yourName)) ret with confirm();
        setField(lastOverwrite := yourName);
        setField(yourName := s);
        dm_showYesToAcceptPopupAbove(btnSave);
        if (voiceMode) dm_say(s);
      }
    });
    JComponent theForm = vstackWithSpacing(
      makeBold(fontSize(20, liveValueLabel(mapLiveValue(dm_fieldLiveValue('myGuess), S, func(S s) -> S { "I call this color: " + or2(s, "Uh... no idea") + "." })))),
      westCenterAndEastWithMargin(fontSize(20, jBoldLabel("How do you call this color?")),
        withSideMargin(15, 5, onEnter(tfYourName = focusOnShow(selectAllOnFocus(
          fontSize(20, makeBold(dm_centeredFieldTextField('yourName))))), rThread saveName)),
        btnSave = jBoldButton("SAVE", rThread saveName)),
      withTopMargin(rightAlignedLine(jBoldButton("NEXT ONE PLEASE", rThread newColor))));

    ret onFirstShow(rThread { setColor(color) /* talk */ },
     centerAndSouthWithMargin(
      northAndCenterWithMargins(
        westAndCenter(dm_fieldCheckBox('voiceMode),
          rightAlignedLine(
            withLabel("Color Code:", jBoldLiveValueLabel(mapLiveValue(func(O color) -> S { "#" + color }, S, dm_fieldLiveValue('color)))),
            jPopDownButton_noText("Choose color...", rThread chooseColor))),
        jCenteredSectionWithFont(sansSerifBold(18), " HERE'S A COLOR FOR YOU ", colorPanel = singleColorPanel(toColor(color)))),
      withBottomMargin(withSideMargin(15, theForm))));
  }
  
  void newColor enter {
    setColor(makeRandomColor());
  }
  
  void setColor(RGB color) enter {
    setField(+color);
    closestColor = (Pair) quickImport(dm_callModule(dm_colorNamesModule(), 'getClosestColor, color.getColor()));
    S guess = pairA(closestColor);
    bool closeEnough = guess != null && pairB(closestColor) <= maxDiff;
    if (!closeEnough) guess = null;
    setField(myGuess := or(guess, "no idea"));
    setField(yourName := guess);
    changeSingleColorPanel(colorPanel, color.getColor());
    selectAll(tfYourName);
    if (guess != null) {
      dm_showYesToAcceptPopupAbove(btnSave);
      if (voiceMode)
        dm_say("Is this " + myGuess + oneOf("", " that I see") + "?");
    } else if (voiceMode)
      dm_say("Master! What is the name of this color?");
  }
  
  void saveName enter {
    setField(yourName := trim(yourName));
    if (empty(yourName)) ret;
    if (eqic(myGuess, yourName))
      dm_infoBoxOrTalk(voiceMode, randomLL(
        "Hey I got this one right.",
        "I'm good!",
        "I'm so good.",
        "I'm so smart.",
        "I'm so smart, don't you think?",
        "Yippieh!"));
    else
      dm_infoBoxOrTalk(voiceMode, quote(yourName) + " confirmed.");
    dm_callModule(dm_colorNamesModule(), 'addColorName, color.getColor(), yourName, "");
    newColor();
  }
  
  RGB makeRandomColor() { ret randomHSBColor(); }
  
  void chooseColor enter {
    inputText("Choose a color (RRGGBB)", color.getHexString(), voidfunc(S s) enter {
      setColor(rgbFromHex(s))
    });
  }
  
  S switchableFields() { ret 'voiceMode; }
  
  void confirm enter {
    dm_hideYesPopupForComponent(btnSave);
    simulateClick(btnSave);
  }
}