@Override
 public void networkState(String string) {
   if (ansiConsole) {
     String str = EscapeSeq.ansiLocate(0, 21) + ">>>> " + string;
     AnsiConsole.out.println(str);
   } else log(string);
 }
  /*
  private static void businessLogic_v1(int waterLevel, int oilLevel)
  {
  //  log(">>> In BusinessLogic (" + waterLevel + ", " + oilLevel + ")");
    int oilThickness = Math.max(0, oilLevel - waterLevel);
    currentWaterLevel   = waterLevel;
    currentOilThickness = oilThickness;

  //  System.out.println("Business Logic - Water:" + waterLevel + ", oil:" + oilLevel);
    if (oilLevel > -1)
    {
  //    log("Oil thick:" + oilThickness + ", Water:" + waterLevel);
      if (waterLevel < 0 && oilThickness > 0)
      {
        // Switch the relay off?
        RelayManager.RelayState status = rm.getStatus("00");
     // log("Relay is:" + status);
        if (RelayManager.RelayState.ON.equals(status))
        {
          log("Turning relay off!");
          try { rm.set("00", RelayManager.RelayState.OFF); }
          catch (Exception ex)
          {
            System.err.println(ex.toString());
          }
        }
        if (currentStatus.equals(ProcessStatus.ALL_OK))
        {
          log("Oil thick:" + oilThickness + ", Water:" + waterLevel + " (Oil Level:" + oilLevel + ")");
          // Make a call
          String[] mess = {"Oil the bilge of " + boatName + ": " + oilThickness + ".",
                            "Please reply CLEAN to this message when done with it."};
      //  String mess = "First warning to " + boatName;

          displayAppMess(" >>>>>>>>>> CALLING " + phoneNumber_1); // + "Mess is a " + mess.getClass().getName() + "\n" + mess);
          sendSMS(phoneNumber_1, mess);
          currentStatus = ProcessStatus.MESSAGE_SENT_TO_CAPTAIN;
          WaitForCleanThread wfct = new WaitForCleanThread();
          wfct.start();
        }
      }
      else
      {
        System.out.println("                            ");
        System.out.println("                            ");
      }
    }
  }
  */
  @Override
  public void setTypeOfChannel(int channel, SevenADCChannelsManager.Material material, float val) {
    data[channel] = new LevelMaterial(val, material);
    manageData();
    // Debug
    if (ansiConsole && "true".equals(System.getProperty("debug", "false"))) {
      AnsiConsole.out.println(EscapeSeq.ansiLocate(1, 15 + channel));
      Date now = new Date();
      AnsiConsole.out.println(
          now.toString()
              + ": Channel "
              + channel
              + " >> ("
              + DF31.format(val)
              + ") "
              + materialToString(material)
              + "       ");
    }
  }
 public static final void displayAppErr(Exception ex) {
   if (ansiConsole) {
     AnsiConsole.out.println(EscapeSeq.ansiLocate(1, 60));
     AnsiConsole.out.println(rpad(ex.toString(), " ", 80));
   } else ex.printStackTrace();
 }
 public static final void displayAppMess(String mess) {
   if (false && ansiConsole) {
     AnsiConsole.out.println(EscapeSeq.ansiLocate(1, 50));
     AnsiConsole.out.println(rpad(mess, " ", 80));
   } else log("AppMess>> " + mess);
 }
  // User Interface ... Sovietic! And business logic.
  private static void manageData() {
    int maxWaterLevel = -1;
    //  int maxOilLevel   = -1;
    // Clear the screen, cursor on top left.
    String str = "";
    int y = 1;
    if (ansiConsole) {
      // AnsiConsole.out.println(EscapeSeq.ANSI_CLS);
      //    AnsiConsole.out.println(EscapeSeq.ansiLocate(0, y++));
      // Firts line to erase what was there before starting.
      AnsiConsole.out.println(
          EscapeSeq.ansiLocate(0, y++)
              + "WT:"
              + SevenADCChannelsManager.getWaterThreshold()
              +
              // ", OT:" + SevenADCChannelsManager.getOilThreshold() +
              ", Sensor Height: "
              + DF23.format(rangeSensorHeight)
              + " cm, D2S:"
              + DF23.format(distanceToSurface * 100)
              + " cm                      ");
      str = EscapeSeq.ansiLocate(0, y++) + "+---+--------+---------+";
      AnsiConsole.out.println(str);
      str = EscapeSeq.ansiLocate(0, y++) + "| C |  Vol % |   Mat   |";
      AnsiConsole.out.println(str);

      str = EscapeSeq.ansiLocate(0, y++) + "+---+--------+---------+";
      AnsiConsole.out.println(str);
    }
    for (int chan = data.length - 1; chan >= 0; chan--) // Top to bottom
    {
      if (previousMaterial[chan] != null && previousMaterial[chan] == data[chan].getMaterial())
        nbSameMaterialInARow[chan] += 1;
      else nbSameMaterialInARow[chan] = 0;

      String color = EscapeSeq.ANSI_BLACK; // ANSI_DEFAULT_BACKGROUND;

      if (nbSameMaterialInARow[chan] > nbSeenInARow) {
        //        if (data[chan].getMaterial().equals(SevenADCChannelsManager.Material.OIL))
        //          color = EscapeSeq.ANSI_RED;
        //        else
        if (data[chan].getMaterial().equals(SevenADCChannelsManager.Material.WATER))
          color = EscapeSeq.ANSI_BLUE;
      }

      String prefix =
          EscapeSeq.ansiLocate(0, y++)
              + EscapeSeq.ansiSetTextAndBackgroundColor(EscapeSeq.ANSI_WHITE, color)
              + EscapeSeq.ANSI_BOLD;
      String suffix =
          EscapeSeq.ANSI_NORMAL + EscapeSeq.ANSI_DEFAULT_BACKGROUND + EscapeSeq.ANSI_DEFAULT_TEXT;
      str =
          "| "
              + Integer.toString(chan + 1)
              + " | "
              + lpad(DF4.format(data[chan].getPercent()), " ", 4)
              + " % | "
              + lpad(materialToString(data[chan].getMaterial()), " ", 7)
              + " |";
      str += (" " + nbSameMaterialInARow[chan] + "   ");
      // if (maxOilLevel == -1 &&
      // data[chan].getMaterial().equals(SevenADCChannelsManager.Material.OIL))
      //   maxOilLevel = chan;
      if (maxWaterLevel == -1
          && data[chan].getMaterial().equals(SevenADCChannelsManager.Material.WATER))
        maxWaterLevel = chan;
      if (ansiConsole) AnsiConsole.out.println(prefix + str + suffix);

      previousMaterial[chan] = data[chan].getMaterial();
    }
    if (ansiConsole) {
      str = EscapeSeq.ansiLocate(0, y++) + "+---+--------+---------+";
      AnsiConsole.out.println(str);
    }
    double waterThickness = (maxWaterLevel + 1) * SENSOR_SPACING;
    double oilThickness = rangeSensorHeight - (waterThickness + (distanceToSurface * 100));
    if (ansiConsole) {
      str =
          EscapeSeq.ansiLocate(0, y++)
              + "Water:"
              + waterThickness
              + ", OT:"
              + oilThickness
              + " cm"
              + "                  ";
      AnsiConsole.out.println(str);
    }
    if (webSocketClient != null) {
      JSONObject json = new JSONObject();
      json.put("water", waterThickness);
      json.put("oil", oilThickness);
      try {
        webSocketClient.send(json.toString());
      } // [1..100]
      catch (Exception ex) {
        displayAppErr(ex);
        //  ex.printStackTrace();
      }
    }
    //  log(">>> To BusinessLogic (" + maxWaterLevel + ", " + maxOilLevel + ")");
    //  businessLogic(maxWaterLevel, maxOilLevel); // Before
    if (deviceStarted) businessLogic(maxWaterLevel, oilThickness);
  }