private boolean isNewRecord(DatabaseTable table, DatabaseTableFilter filter)
     throws CantLoadTableToMemoryException {
   table.addStringFilter(filter.getColumn(), filter.getValue(), filter.getType());
   table.loadToMemory();
   if (table.getRecords().isEmpty()) return true;
   else return false;
 }
  private List<DatabaseTableRecord> getRecordsByFilter(DatabaseTableFilter filter)
      throws CantLoadTableToMemoryException {
    DatabaseTable table =
        this.database.getTable(
            BitcoinVenezuelaProviderDatabaseConstants.DAILY_EXCHANGE_RATES_TABLE_NAME);

    if (filter != null)
      table.addStringFilter(filter.getColumn(), filter.getValue(), filter.getType());

    table.loadToMemory();
    return table.getRecords();
  }
  private List<DatabaseTableRecord> getCryptoMoneyRestockData(DatabaseTableFilter filter)
      throws CantLoadTableToMemoryException {
    DatabaseTable table =
        getDatabaseTable(
            StockTransactionsCrpytoMoneyRestockDatabaseConstants.CRYPTO_MONEY_RESTOCK_TABLE_NAME);

    if (filter != null)
      table.addStringFilter(filter.getColumn(), filter.getValue(), filter.getType());

    table.loadToMemory();

    return table.getRecords();
  }
  private List<DatabaseTableRecord> getBankMoneyRestockData(DatabaseTableFilter filter)
      throws CantLoadTableToMemoryException {
    DatabaseTable table =
        getDatabaseTable(
            BussinessTransactionBankMoneyRestockDatabaseConstants.BANK_MONEY_STOCK_TABLE_NAME);

    if (filter != null)
      table.addStringFilter(filter.getColumn(), filter.getValue(), filter.getType());

    table.loadToMemory();

    return table.getRecords();
  }
  private List<DatabaseTableRecord> getTransactionRecordsByFilter(
      DatabaseTableFilter filter, int max, int offset) throws CantLoadTableToMemoryException {
    DatabaseTable table =
        this.database.getTable(CashMoneyWalletDatabaseConstants.TRANSACTIONS_TABLE_NAME);

    if (filter != null)
      table.addStringFilter(filter.getColumn(), filter.getValue(), filter.getType());

    if (offset >= 0) table.setFilterOffSet(String.valueOf(offset));

    if (max >= 0) table.setFilterTop(String.valueOf(max));

    table.loadToMemory();
    return table.getRecords();
  }
  public List<CryptoMoneyTransaction> getCryptoMoneyTransactionList(DatabaseTableFilter filter)
      throws DatabaseOperationException, InvalidParameterException {
    Database database = null;
    try {
      database = openDatabase();
      List<CryptoMoneyTransaction> cryptoMoneyTransactions = new ArrayList<>();
      // I will add the Asset Factory information from the database
      for (DatabaseTableRecord cryptoMoneyRestockRecord : getCryptoMoneyRestockData(filter)) {
        final CryptoMoneyTransaction cryptoMoneyTransaction =
            getCryptoMoneyRestockTransaction(cryptoMoneyRestockRecord);

        cryptoMoneyTransactions.add(cryptoMoneyTransaction);
      }

      database.closeDatabase();

      return cryptoMoneyTransactions;
    } catch (Exception e) {
      if (database != null) database.closeDatabase();
      throw new DatabaseOperationException(
          DatabaseOperationException.DEFAULT_MESSAGE,
          e,
          "error trying to get Bank Money Restock Transaction from the database with filter: "
              + filter.toString(),
          null);
    }
  }
  public void saveBankMoneyRestockTransactionData(BankMoneyTransaction bankMoneyTransaction)
      throws DatabaseOperationException, MissingBankMoneyRestockDataException {

    try {
      database = openDatabase();
      DatabaseTransaction transaction = database.newTransaction();

      // TODO: Solo para prueba ya que priceReference viene null desde android revisar con Nelson
      bankMoneyTransaction.setPriceReference(new BigDecimal(0));

      /*//TODO:Revisar con guillermo que el accountNumber viene null
      bankMoneyTransaction.setBankAccount("123456");
      */
      DatabaseTable table =
          getDatabaseTable(
              BussinessTransactionBankMoneyRestockDatabaseConstants.BANK_MONEY_STOCK_TABLE_NAME);
      DatabaseTableRecord bankMoneyRestockRecord = getBankMoneyRestockRecord(bankMoneyTransaction);
      DatabaseTableFilter filter = table.getEmptyTableFilter();
      filter.setType(DatabaseFilterType.EQUAL);
      filter.setValue(bankMoneyTransaction.getTransactionId().toString());
      filter.setColumn(
          BussinessTransactionBankMoneyRestockDatabaseConstants
              .BANK_MONEY_RESTOCK_TRANSACTION_ID_COLUMN_NAME);

      if (isNewRecord(table, filter)) transaction.addRecordToInsert(table, bankMoneyRestockRecord);
      else {
        table.addStringFilter(filter.getColumn(), filter.getValue(), filter.getType());
        transaction.addRecordToUpdate(table, bankMoneyRestockRecord);
      }

      // I execute the transaction and persist the database side of the asset.
      database.executeTransaction(transaction);
      database.closeDatabase();

    } catch (Exception e) {
      if (database != null) database.closeDatabase();
      throw new DatabaseOperationException(
          DatabaseOperationException.DEFAULT_MESSAGE,
          e,
          "Error trying to save the Bank Money Restock Transaction in the database.",
          null);
    }
  }
  /**
   * Updates the execution statistics of the event Agent it will insert a new record if we have
   * pending transactions, and update the existing value if we have zero transactions.
   *
   * @param pendingIncoming
   * @param pendingOutgoing
   */
  public void updateEventAgentStats(int pendingIncoming, int pendingOutgoing)
      throws CantExecuteDatabaseOperationException {
    DatabaseTable databaseTable =
        database.getTable(BitcoinCryptoNetworkDatabaseConstants.EVENTAGENT_STATS_TABLE_NAME);

    /** I will get the current execution number */
    int currentExecutionNumber;
    databaseTable.setFilterOrder(
        BitcoinCryptoNetworkDatabaseConstants.EVENTAGENT_STATS_EXECUTION_NUMBER_COLUMN_NAME,
        DatabaseFilterOrder.DESCENDING);
    try {
      databaseTable.loadToMemory();
    } catch (CantLoadTableToMemoryException e) {
      throwLoadToMemoryException(e, databaseTable.getTableName());
    }

    if (databaseTable.getRecords().size() != 0)
      currentExecutionNumber =
          databaseTable
              .getRecords()
              .get(0)
              .getIntegerValue(
                  BitcoinCryptoNetworkDatabaseConstants
                      .EVENTAGENT_STATS_EXECUTION_NUMBER_COLUMN_NAME);
    else currentExecutionNumber = 0;

    /**
     * if I have pending transactions, I will insert a new record, also if this is the first time
     * I'm executing.
     */
    DatabaseTableRecord record = null;
    try {
      if (pendingIncoming != 0 || pendingOutgoing != 0 || currentExecutionNumber == 0) {
        record = databaseTable.getEmptyRecord();
        record.setIntegerValue(
            BitcoinCryptoNetworkDatabaseConstants.EVENTAGENT_STATS_EXECUTION_NUMBER_COLUMN_NAME,
            currentExecutionNumber + 1);
        record.setStringValue(
            BitcoinCryptoNetworkDatabaseConstants.EVENTAGENT_STATS_LAST_EXECUTION_DATE_COLUMN_NAME,
            getCurrentDateTime());
        record.setIntegerValue(
            BitcoinCryptoNetworkDatabaseConstants
                .EVENTAGENT_STATS_PENDING_INCOMING_TRANSACTIONS_COLUMN_NAME,
            pendingIncoming);
        record.setIntegerValue(
            BitcoinCryptoNetworkDatabaseConstants
                .EVENTAGENT_STATS_PENDING_OUTGOING_TRANSACTIONS_COLUMN_NAME,
            pendingOutgoing);

        databaseTable.insertRecord(record);

      } else {
        /** I will update existing value with zero pending transactions */
        DatabaseTableFilter filterIncoming = databaseTable.getEmptyTableFilter();
        filterIncoming.setColumn(
            BitcoinCryptoNetworkDatabaseConstants
                .EVENTAGENT_STATS_PENDING_INCOMING_TRANSACTIONS_COLUMN_NAME);
        filterIncoming.setValue("0");
        filterIncoming.setType(DatabaseFilterType.EQUAL);

        DatabaseTableFilter filterOutgoing = databaseTable.getEmptyTableFilter();
        filterOutgoing.setColumn(
            BitcoinCryptoNetworkDatabaseConstants
                .EVENTAGENT_STATS_PENDING_OUTGOING_TRANSACTIONS_COLUMN_NAME);
        filterOutgoing.setValue("0");
        filterOutgoing.setType(DatabaseFilterType.EQUAL);

        /** I create the two filters and add them to form a filter group. */
        List<DatabaseTableFilter> filters = new ArrayList<>();
        filters.add(filterIncoming);
        filters.add(filterOutgoing);

        List<DatabaseTableFilterGroup> filterGroups = new ArrayList<>();
        databaseTable.setFilterGroup(
            databaseTable.getNewFilterGroup(filters, filterGroups, DatabaseFilterOperator.AND));
        databaseTable.loadToMemory();

        record = databaseTable.getRecords().get(0);
        record.setIntegerValue(
            BitcoinCryptoNetworkDatabaseConstants.EVENTAGENT_STATS_EXECUTION_NUMBER_COLUMN_NAME,
            currentExecutionNumber + 1);
        record.setStringValue(
            BitcoinCryptoNetworkDatabaseConstants.EVENTAGENT_STATS_LAST_EXECUTION_DATE_COLUMN_NAME,
            getCurrentDateTime());

        databaseTable.updateRecord(record);
      }
    } catch (CantLoadTableToMemoryException e) {
      throwLoadToMemoryException(e, databaseTable.getTableName());
    } catch (CantInsertRecordException | CantUpdateRecordException e) {
      StringBuilder outputMessage =
          new StringBuilder("There was an error inserting or modifying a record. The record is:");
      outputMessage.append(System.lineSeparator());
      outputMessage.append(XMLParser.parseObject(record));

      throw new CantExecuteDatabaseOperationException(
          CantExecuteDatabaseOperationException.DEFAULT_MESSAGE,
          e,
          outputMessage.toString(),
          "database issue");
    }
  }
  /**
   * Method that list the all entities on the data base. The valid value of the key are the att of
   * the <code>WalletPublisherMiddlewareDatabaseConstants</code>
   *
   * @param filters
   * @return List<ImageMiddlewareImpl>
   * @throws CantReadRecordDataBaseException
   */
  public List<Image> findAll(Map<String, Object> filters) throws CantReadRecordDataBaseException {

    if (filters == null || filters.isEmpty()) {

      throw new IllegalArgumentException("The filters are required, can not be null or empty");
    }

    List<Image> list = null;
    List<DatabaseTableFilter> filtersTable = new ArrayList<>();

    try {

      /*
       * 1- Prepare the filters
       */
      getDataBase().openDatabase();
      DatabaseTable walletPublishedMiddlewareInformationTable = getDatabaseTable();

      for (String key : filters.keySet()) {

        DatabaseTableFilter newFilter =
            walletPublishedMiddlewareInformationTable.getEmptyTableFilter();
        newFilter.setType(DatabaseFilterType.EQUAL);
        newFilter.setColumn(key);
        newFilter.setValue((String) filters.get(key));

        filtersTable.add(newFilter);
      }

      /*
       * 2 - load the data base to memory with filters
       */
      walletPublishedMiddlewareInformationTable.setFilterGroup(
          filtersTable, null, DatabaseFilterOperator.OR);
      walletPublishedMiddlewareInformationTable.loadToMemory();

      /*
       * 3 - read all records
       */
      List<DatabaseTableRecord> records = walletPublishedMiddlewareInformationTable.getRecords();

      /*
       * 4 - Create a list of ImageMiddlewareImpl objects
       */
      list = new ArrayList<>();
      list.clear();

      /*
       * 5 - Convert into ImageMiddlewareImpl objects
       */
      for (DatabaseTableRecord record : records) {

        /*
         * 5.1 - Create and configure a  ImageMiddlewareImpl
         */
        ImageMiddlewareImpl walletPublishedMiddlewareInformation = constructFrom(record);

        /*
         * 5.2 - Add to the list
         */
        list.add(walletPublishedMiddlewareInformation);
      }

    } catch (CantLoadTableToMemoryException cantLoadTableToMemory) {

      StringBuffer contextBuffer = new StringBuffer();
      contextBuffer.append(
          "Database Name: " + WalletPublisherMiddlewareDatabaseConstants.DATA_BASE_NAME);

      String context = contextBuffer.toString();
      String possibleCause = "The data no exist";
      CantReadRecordDataBaseException cantReadRecordDataBaseException =
          new CantReadRecordDataBaseException(
              CantDeleteRecordDataBaseException.DEFAULT_MESSAGE,
              cantLoadTableToMemory,
              context,
              possibleCause);
      throw cantReadRecordDataBaseException;
    } catch (DatabaseNotFoundException e) {

      // Register the failure.
      StringBuffer contextBuffer = new StringBuffer();
      contextBuffer.append(
          "Database Name: " + WalletPublisherMiddlewareDatabaseConstants.DATA_BASE_NAME);

      String context = contextBuffer.toString();
      String possibleCause = "The database no exist";
      CantReadRecordDataBaseException cantReadRecordDataBaseException =
          new CantReadRecordDataBaseException(
              CantDeleteRecordDataBaseException.DEFAULT_MESSAGE, e, context, possibleCause);
      throw cantReadRecordDataBaseException;

    } catch (CantOpenDatabaseException e) {

      // Register the failure.
      StringBuffer contextBuffer = new StringBuffer();
      contextBuffer.append(
          "Database Name: " + WalletPublisherMiddlewareDatabaseConstants.DATA_BASE_NAME);

      String context = contextBuffer.toString();
      String possibleCause = "The database no exist";
      CantReadRecordDataBaseException cantReadRecordDataBaseException =
          new CantReadRecordDataBaseException(
              CantDeleteRecordDataBaseException.DEFAULT_MESSAGE, e, context, possibleCause);
      throw cantReadRecordDataBaseException;

    } catch (Exception e) {

      // Register the failure.
      StringBuffer contextBuffer = new StringBuffer();
      contextBuffer.append(
          "Database Name: " + WalletPublisherMiddlewareDatabaseConstants.DATA_BASE_NAME);

      String context = contextBuffer.toString();
      String possibleCause = "Other problems";
      CantReadRecordDataBaseException cantReadRecordDataBaseException =
          new CantReadRecordDataBaseException(
              CantDeleteRecordDataBaseException.DEFAULT_MESSAGE, e, context, possibleCause);
      throw cantReadRecordDataBaseException;
    }

    /*
     * return the list
     */
    return list;
  }
  /**
   * Method that list the all entities on the data base. The valid value of the key are the att of
   * the <code>CommunicationNetworkServiceDatabaseConstants</code>
   *
   * @return All FermatMessage.
   * @throws CantReadRecordDataBaseException
   * @see CommunicationNetworkServiceDatabaseConstants
   */
  public List<FermatMessage> findAll(Map<String, Object> filters)
      throws CantReadRecordDataBaseException {

    if (filters == null || filters.isEmpty()) {

      throw new IllegalArgumentException("The filters are required, can not be null or empty");
    }

    List<FermatMessage> list = null;
    List<DatabaseTableFilter> filtersTable = new ArrayList<>();

    try {

      /*
       * 1- Prepare the filters
       */
      DatabaseTable networkIntraUserTable = getDatabaseTable();

      for (String key : filters.keySet()) {

        DatabaseTableFilter newFilter = networkIntraUserTable.getEmptyTableFilter();
        newFilter.setType(DatabaseFilterType.EQUAL);
        newFilter.setColumn(key);
        newFilter.setValue((String) filters.get(key));

        filtersTable.add(newFilter);
      }

      /*
       * 2 - load the data base to memory with filters
       */
      networkIntraUserTable.setFilterGroup(filtersTable, null, DatabaseFilterOperator.OR);
      networkIntraUserTable.loadToMemory();

      /*
       * 3 - read all records
       */
      List<DatabaseTableRecord> records = networkIntraUserTable.getRecords();

      /*
       * 4 - Create a list of FermatMessage objects
       */
      list = new ArrayList<>();
      list.clear();

      /*
       * 5 - Convert into FermatMessage objects
       */
      for (DatabaseTableRecord record : records) {

        /*
         * 5.1 - Create and configure a  FermatMessage
         */
        FermatMessage incomingTemplateNetworkServiceMessage = constructFrom(record);

        /*
         * 5.2 - Add to the list
         */
        list.add(incomingTemplateNetworkServiceMessage);
      }

    } catch (CantLoadTableToMemoryException cantLoadTableToMemory) {

      // Register the failure.
      StringBuffer contextBuffer = new StringBuffer();
      contextBuffer.append(
          "Database Name: " + CommunicationNetworkServiceDatabaseConstants.DATA_BASE_NAME);

      String context = contextBuffer.toString();
      String possibleCause = "The data no exist";
      CantReadRecordDataBaseException cantReadRecordDataBaseException =
          new CantReadRecordDataBaseException(
              CantReadRecordDataBaseException.DEFAULT_MESSAGE,
              cantLoadTableToMemory,
              context,
              possibleCause);
      throw cantReadRecordDataBaseException;
    }

    /*
     * return the list
     */
    return list;
  };
  public BigDecimal getHeldFunds(String walletPublicKey, String actorPublicKey)
      throws CantGetHeldFundsException {
    List<DatabaseTableRecord> records;
    BigDecimal heldFunds = new BigDecimal(0);
    BigDecimal unheldFunds = new BigDecimal(0);

    List<DatabaseTableFilter> filtersTable = new ArrayList<>();
    DatabaseTableFilter walletFilter, actorFilter;
    DatabaseTable table =
        this.database.getTable(CashMoneyWalletDatabaseConstants.TRANSACTIONS_TABLE_NAME);

    walletFilter = getEmptyTransactionsTableFilter();
    walletFilter.setColumn(
        CashMoneyWalletDatabaseConstants.TRANSACTIONS_WALLET_PUBLIC_KEY_COLUMN_NAME);
    walletFilter.setValue(walletPublicKey);
    walletFilter.setType(DatabaseFilterType.EQUAL);
    filtersTable.add(walletFilter);

    actorFilter = getEmptyTransactionsTableFilter();
    actorFilter.setColumn(
        CashMoneyWalletDatabaseConstants.TRANSACTIONS_ACTOR_PUBLIC_KEY_COLUMN_NAME);
    actorFilter.setValue(actorPublicKey);
    actorFilter.setType(DatabaseFilterType.EQUAL);
    filtersTable.add(actorFilter);

    table.setFilterGroup(filtersTable, null, DatabaseFilterOperator.AND);

    try {
      table.loadToMemory();
      records = table.getRecords();
    } catch (CantLoadTableToMemoryException e) {
      errorManager.reportUnexpectedPluginException(
          Plugins.BITDUBAI_CSH_WALLET_CASH_MONEY,
          UnexpectedPluginExceptionSeverity.DISABLES_SOME_FUNCTIONALITY_WITHIN_THIS_PLUGIN,
          e);
      throw new CantGetHeldFundsException(
          CantGetHeldFundsException.DEFAULT_MESSAGE,
          e,
          "getHeldFunds",
          "Cant load table into memory");
    }

    for (DatabaseTableRecord record : records) {
      if (record
          .getStringValue(
              CashMoneyWalletDatabaseConstants.TRANSACTIONS_TRANSACTION_TYPE_COLUMN_NAME)
          .equals(TransactionType.HOLD.getCode()))
        heldFunds.add(
            new BigDecimal(
                record.getStringValue(
                    CashMoneyWalletDatabaseConstants.TRANSACTIONS_AMOUNT_COLUMN_NAME)));
      else if (record
          .getStringValue(
              CashMoneyWalletDatabaseConstants.TRANSACTIONS_TRANSACTION_TYPE_COLUMN_NAME)
          .equals(TransactionType.UNHOLD.getCode()))
        unheldFunds.add(
            new BigDecimal(
                record.getStringValue(
                    CashMoneyWalletDatabaseConstants.TRANSACTIONS_AMOUNT_COLUMN_NAME)));
    }
    heldFunds = heldFunds.subtract(unheldFunds);

    if (heldFunds.compareTo(new BigDecimal(0)) < 0)
      throw new CantGetHeldFundsException(
          CantGetHeldFundsException.DEFAULT_MESSAGE,
          null,
          "Held funds calculates to a negative value",
          "Unheld funds are higher than held funds, invalid table state");

    return heldFunds;
  }