/**
   * Check if the data in all contained blocks is valid. Ignore blocks that are not visible (not
   * relevant).
   *
   * @return
   */
  private boolean dataIsValid() {
    for (Block b : blocks) {
      if (b.isVisible() && !b.dataIsValid()) return false;
    }

    return true;
  }
  /**
   * Let all editors save their content to a byte array and write it to a file.
   *
   * @param data
   */
  private void writeToEepromFile() {
    byte[] eeprom = new byte[1024]; // assume size of 1024 bytes first and truncate later
    int offset = 0;

    for (Block b : blocks) {
      if (b.isVisible()) {
        int bitsProcessed = b.writeToEepromArray(eeprom, offset);
        offset += bitsProcessed;
      }
    }

    // cut size to 512 or 1024 bytes automatically
    if (offset <= 512 * 8) {
      byte[] eeprom2 = new byte[512];
      System.arraycopy(eeprom, 0, eeprom2, 0, 512);
      eeprom = eeprom2;
    }

    try {
      Util.writeFile(filename, eeprom);
    } catch (IOException e) {
      JOptionPane.showMessageDialog(
          SHCEEMain.mySHCEEMain,
          "Could not write file " + filename + ".",
          "Error",
          JOptionPane.ERROR_MESSAGE);
      e.printStackTrace();
    }
  }
  /**
   * Feed the bytes from the EEPROM file to the editor blocks one after another with an updated bit
   * offset. The block objects are responsible for further feeding the bits and bytes to their
   * contained editor components.
   *
   * @param data
   */
  private void readFromEepromArray(byte[] eeprom) {
    int offset = 0;

    // Switch all blocks of so no blocks are displayed that are not used for the device if anything
    // goes wrong reading the bytes from the file (e.g. file too short).
    for (Block b : blocks) {
      b.setVisible(false);
    }

    for (Block b : blocks) {
      boolean match = true;

      // If a block has a condition set, check it and override
      // using this block if it is not matched.
      if (b.restrictionRefID != null) {
        String val = findValue(b.restrictionRefID, false);
        match = val.equals(b.restrictionValue);
      }

      b.setVisible(match);

      if (match) {
        int bitsProcessed = b.readFromEepromArray(eeprom, offset);
        offset += bitsProcessed;
      }
    }

    length = offset;
  }
  /**
   * Go through all blocks and editors searching for a value with the given name and return a string
   * representation.
   *
   * @param id The ID of the value (according to the e2p_layout.xml).
   * @param humanReadable If TRUE, return a better readable string representation only used for the
   *     GUI.
   * @return The value as String, or null if not found.
   */
  public String findValue(String id, boolean humanReadable) {
    for (Block b : blocks) {
      String val = b.findValue(id, humanReadable);

      if (null != val) return val;
    }

    return null;
  }
  /**
   * Update visibility of blocks according to the currently selected restriction (DeviceType)
   * without changing the content of the editors.
   */
  public void updateBlockVisibility() {
    // Switch all blocks of so no blocks are displayed that are not used for the device if anything
    // goes wrong reading the bytes from the file (e.g. file too short).
    for (Block b : blocks) {
      b.setVisible(false);
    }

    for (Block b : blocks) {
      boolean match = true;

      // If a block has a condition set, check it and override
      // using this block if it is not matched.
      if (b.restrictionRefID != null) {
        String val = findValue(b.restrictionRefID, false);
        match = val.equals(b.restrictionValue);
      }

      b.setVisible(match);
    }
  }
  /**
   * Assume that blocks are restricted by the DeviceType only (as true for smarthomatic) and switch
   * the blocks on/off using the given deviceTypeID. This is for use for the Firmware source code
   * creation process ONLY!
   *
   * @param deviceTypeID
   */
  public void enableEditorsForDeviceType(int deviceTypeID) {
    byte[] dummy = new byte[1024];
    int offset = 0;

    for (Block b : blocks) {
      boolean match = true;

      // If a block has a condition set, check it and override
      // using this block if it is not matched.
      if ((b.restrictionRefID != null) && b.restrictionRefID.equals("DeviceType")) {
        match = b.restrictionValue.equals("" + deviceTypeID);
      }

      b.setVisible(match);

      if (match) {
        int bitsProcessed = b.readFromEepromArray(dummy, offset);
        offset += bitsProcessed;
      }
    }
  }