/**
   * executeCommand
   *
   * @param map of APDU commands (Structure: Applet<-Instructions<-Fields<-Commands)
   * @param commandId
   * @return boolean
   * @throws Exception
   */
  boolean executeCommand(Map<String, Object> maps, int commandId) throws Exception {
    AppletModel applet = null;
    Object a = maps.get(SeqlWords.STR_APPLET);

    if (a instanceof AppletModel) {
      applet = (AppletModel) a;
    }

    if (applet == null) {
      callback.onNoApplet();
      return false;
    }

    try {
      if (!sayHello(applet.getAlias(), CMD_HELLO)) {
        throw new ChannelNotOpenException();
      }
    } catch (Exception e) {
      throw e;
    }

    byte[][] commands = (byte[][]) maps.get(SeqlWords.STR_COMMAND);
    String[] fields = (String[]) maps.get(SeqlWords.STR_FIELD);

    Map<String, Object> response = new HashMap<String, Object>();
    int idxField = 0;
    boolean success = false;
    for (byte[] command : commands) {
      byte[] rep = null;
      rep = sendCommand(command, channel);

      if (!APDUModel.isResponseSucceded(rep)) {
        if (APDUModel.isPinRequired(rep)) {
          if (callback != null) callback.onPINRequired();
        } else {
          APDUError error =
              new APDUError("Wrong APDU response", APDUModel.getResponseStatusWord(rep));
          if (callback != null) callback.onAPDUError(error);
        }
      } else {
        String r = APDUModel.getResponseBody(rep);
        response.put(fields[idxField], r);
        // Repeat fields loop for each instruction sequence
        idxField = (idxField == fields.length ? 0 : idxField + 1);
        success = true;
      }

      if (!success) {
        // TODO: rollback all transactions!!!
        break;
      }
    }
    if (success) {
      // System.out.println("Response sending...........");
      if (callback != null) callback.onResponse(response, commandId);
    }
    disconnect();
    return success;
  }
  /**
   * sayHello (SELECT AID APDU ISO 7816-4)
   *
   * @param appletName
   * @param commandId
   * @return boolean
   */
  @Override
  public boolean sayHello(String appletName, int commandHelloId) {
    try {
      AppletModel model = null;
      try {
        model = SeqlMetadata.getInstance(configFile).getAppletByAlias(appletName);
      } catch (Exception e) {
        e.printStackTrace();
      }
      if (model == null) {
        callback.onNoApplet();
      }

      channel = openChannel(model);

      byte[] apdu = null;
      APDUResponse resp = new APDUResponse();
      try {
        // select the applet
        apdu = APDUModel.getSelectAidApdu(BytesTool.hexStringToByteArray(model.getAID()));
        apdu = sendCommand(apdu, channel);
        resp.setResponse(apdu);
        return APDUModel.isResponseSucceded(resp.getStatusWord());
      } catch (Exception e) {
        e.printStackTrace();
        callback.onNoApplet();
      }
    } catch (NoSuchElementException e) {
      callback.onNoApplet();
    } catch (IOException e) {
      callback.onNoSecureElement();
    } catch (NoReaderException e) {
      callback.onNoReader();
    } catch (NoSecureElementException e) {
      callback.onNoSecureElement();
    } catch (BadRequestException e) {
      callback.onBadRequest(e.getMessage());
    } catch (Exception e) {
      callback.onNotConnected();
    }
    return false;
  }