/**
   * performs the read operation for both Read-Write and Read-Only Transactions
   *
   * @param transactionID
   * @param variable
   * @param typeOfTransaction
   */
  private void read(String transactionID, int variable, int typeOfTransaction) {
    Transaction transactionForReading = this.currentTransactions.get(transactionID);
    if (typeOfTransaction == Constants.RO) { // for read only transaction
      boolean hasItBeenRead = false;
      for (int i = 1; i <= Constants.SITES && !hasItBeenRead; i++) {
        Site tempSite = sites.get(i);
        if (tempSite.isDown()) {
          // site is down
          // Do not do anything, go to next site
        } else {
          // site is not down
          ArrayList<Variable> variablesInTempSite = (ArrayList<Variable>) tempSite.getVariables();
          for (int j = 0; j < variablesInTempSite.size(); j++) {
            if (variablesInTempSite.get(j).getID() == variable
                && variablesInTempSite.get(j).getAvailableForRead()) {
              // variable we are looking for found in tempSite and they are available for reading
              // We have parse the VariableHistory of this Variable and choose the correct value
              ArrayList<VariableHistory> history =
                  (ArrayList<VariableHistory>) variablesInTempSite.get(j).getHistoricalData();
              int currentMax = -1; // time counter
              int maxIndex = -1; // index in the ArrayList which has max
              for (int k = 0; k < history.size(); k++) {
                if (history.get(k).getTime() > currentMax
                    && history.get(k).getTime() < transactionForReading.getStartTime()) {
                  maxIndex = k;
                  currentMax = history.get(k).getTime();
                }
              }
              if (maxIndex != -1) {
                hasItBeenRead = true;
                System.out.println("The value that is read is " + history.get(maxIndex).getValue());
                Operation op = new Operation(0, variable, 0, Constants.OP_READ);
                transactionForReading.insertOperation(op);
              }
            }
          }
        }
      }
      if (hasItBeenRead == false) {
        // variable could not be read for any site so this operation has to wait
        System.out.println(transactionID + "(R,x" + variable + ") has to wait");
        Operation op = new Operation(0, variable, 0, Constants.OP_READ);
        insertToWaitList(op, transactionID);
      }
    } else { // for read-write transaction

      if (this.doesThisTransactionAlreadyHaveReadLockOnVariable(transactionForReading, variable)) {
        // transaction already has a read lock on variable at some site
        int index = -1;
        for (int q = 1; q <= Constants.SITES; q++) {
          if (!this.sites.get(q).isDown()) {
            if (this.sites
                .get(q)
                .lockInfo
                .doesThisTableContainLockWith(variable, transactionID, Constants.RL)) {
              index = q;
            }
          }
        }
        ArrayList<Variable> varsInSite = (ArrayList<Variable>) this.sites.get(index).getVariables();
        Variable var = varsInSite.get(0);
        for (int m = 0; m < varsInSite.size(); m++) {
          if (varsInSite.get(m).getID() == variable) {
            var = varsInSite.get(m);
          }
        }
        System.out.println("The value that is read is " + var.getValue());
      } else {
        // the transaction does not have a read lock on this variable
        boolean hasItBeenRead = false;
        for (int i = 1; i <= Constants.SITES && !hasItBeenRead; i++) {
          Site tempSite = sites.get(i);
          if (tempSite.isDown()) {
            // site is down
            // Do not do anything
          } else {
            // site is not down
            ArrayList<Variable> variablesInTempSite = (ArrayList<Variable>) tempSite.getVariables();
            for (int j = 0; j < variablesInTempSite.size(); j++) {
              if (variablesInTempSite.get(j).getID() == variable
                  && variablesInTempSite.get(j).getAvailableForRead()) {
                // variable we are looking for found in tempSite and they are available for
                // reading(in term of recovery)
                if (tempSite.lockInfo.canWeGetReadLockOnVariable(variable, transactionID)) {
                  // we can get read lock on the variable
                  if (tempSite.lockInfo.doesThisTableContainLockWith(
                      variable, transactionID, Constants.WL)) {
                    // this transaction has a write lock on the this variable at this site
                    hasItBeenRead = true;
                    Variable currentVariable = tempSite.getVariableWithID(variable);
                    Operation op = new Operation(0, variable, 0, Constants.OP_READ);
                    transactionForReading.insertOperation(op);
                    transactionForReading.sitesAccessed.add(i);
                    System.out.println(
                        "The value that is read is " + currentVariable.getCurrValue());
                    // value read is the current value because transaction already has read lock on
                    // the variable
                  } else {
                    // this transaction does not have a write lock on this variable
                    hasItBeenRead = true;
                    tempSite.lockInfo.addLock(variable, transactionID, Constants.RL);
                    Variable currentVariable = tempSite.getVariableWithID(variable);
                    Operation op = new Operation(0, variable, 0, Constants.OP_READ);
                    transactionForReading.insertOperation(op);
                    transactionForReading.sitesAccessed.add(i);
                    transactionForReading.addLockToAlreadyLocked(variable, Constants.RL);
                    System.out.println("The value that is read is " + currentVariable.getValue());
                  }
                } else {
                  // this is the variable that we want to lock
                  // but we can't get a read lock on it
                  // so implement wait-die
                  hasItBeenRead = true;
                  ArrayList<Lock> tempList = tempSite.lockInfo.getAllLocksForVariable(variable);
                  Lock writeLock = tempList.get(0);
                  String tidWithWriteLock = writeLock.getTransactionId();
                  String tidWithoutWriteLock = transactionID;
                  boolean answer = isAbort(tidWithWriteLock, tidWithoutWriteLock);
                  if (answer == false) {
                    // This operation has to wait
                    this.putThisTransactionIntoWaitListingOfTransactionThatHaveLock(
                        transactionID, variable);
                    Operation op = new Operation(0, variable, 0, Constants.OP_READ);
                    insertToWaitList(op, transactionID);
                    System.out.println(transactionID + "(R,x" + variable + ") has to wait");
                  }
                }
              }
            }
          }
        }
        if (hasItBeenRead == false) {
          // variable could not be read for any site so this operation has to wait
          Operation op = new Operation(0, variable, 0, Constants.OP_READ);
          insertToWaitList(op, transactionID);
          System.out.println(transactionID + "(R,x" + variable + ") has to wait");
        }
      }
    }
  }