/**
   * This method check whether the customer has good credit standing.
   *
   * @param firstName
   * @param lastName
   * @param phoneNumber
   * @return True or False for success and failure respectively
   */
  public Boolean isCreditOK(String firstName, String lastName, String phoneNumber) {
    List<Loan> loanList = loanMap.get(firstName.charAt(0));
    if (loanList != null) {
      Iterator<Loan> iterator = loanList.iterator();

      while (iterator.hasNext()) {
        Loan loan = iterator.next();
        Customer account = loan.getAccount();

        if (firstName.equals(account.getFirstName())
            && lastName.equals(account.getLastName())
            && phoneNumber.equals(account.getPhoneNumber())) {
          if (account.getCreditLimit() > 0) {
            return true;
          } else {
            return false;
          }
        }
      }
    }

    return true;
  }
  /**
   * This method approves or rejects a loan request.
   *
   * @param accountNumber
   * @param password
   * @param loanAmount
   * @return success/failure
   */
  @Override
  public boolean getLoan(String bank, String accountNumber, String password, int loanAmount) {

    // This add log information to the log file
    try {
      blockingQueue.put(
          new Date()
              + ": AccountNumber:"
              + accountNumber
              + " has initiated a loan request for "
              + loanAmount
              + " at "
              + bankName);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    Customer customerAccount = getAccount(accountNumber, password);
    String loanId = null;
    int port1 = 0;
    int port2 = 0;

    if (customerAccount == null) {
      return false;
    }

    if (bankName.equals("RBC")) {
      port1 = Configuration.UDP_SERVER_2_PORT;
      port2 = Configuration.UDP_SERVER_3_PORT;
    } else if (bankName.equals("TD")) {
      port1 = Configuration.UDP_SERVER_1_PORT;
      port2 = Configuration.UDP_SERVER_3_PORT;
    } else if (bankName.equals("BMO")) {
      port1 = Configuration.UDP_SERVER_1_PORT;
      port2 = Configuration.UDP_SERVER_2_PORT;
    }

    boolean isCreditGood =
        Boolean.parseBoolean(
                creditCheckUDP(
                    customerAccount.getFirstName(),
                    customerAccount.getLastName(),
                    customerAccount.getPhoneNumber(),
                    port1))
            && Boolean.parseBoolean(
                creditCheckUDP(
                    customerAccount.getFirstName(),
                    customerAccount.getLastName(),
                    customerAccount.getPhoneNumber(),
                    port2));

    if (!isCreditGood) {
      return false;
    }

    if (customerAccount != null) {

      if (customerAccount.getCreditLimit() >= loanAmount) {
        // Updating the new credit limit for customer

        customerAccount.setCreditLimit(customerAccount.getCreditLimit() - loanAmount);

        Loan loan = new Loan();

        synchronized (loanCounter) {
          loanId = accountNumber.charAt(0) + "" + loanCounter.incrementAndGet();
          loan.setLoanId(loanId);
        }

        loan.setLoanAmount(loanAmount);

        Date date = new Date();
        if (loanAmount < 2000) {
          date.setMonth(date.getMonth() + 12);
        } else {
          date.setMonth(date.getMonth() + 24);
        }
        loan.setLoanDueDate(date);
        loan.setAccount(customerAccount);

        // Store the loan in loanMap, synchronized block is present in
        // saveLoan
        saveLoan(loanId, loan);

        updateAccountMap(customerAccount);

        /* System.out.println(accountMap); */

        return true;
      }
    }

    // System.out.println(accountMap);

    return false;
  }
  /**
   * This method transfers loan from one bank to another.
   *
   * @param loanId
   * @param currentBank
   * @param otherBank
   * @param transferStatus
   */
  @Override
  public boolean transferLoan(String loanId, String currentBank, String otherBank) {

    int portNumber = 0;

    if (otherBank.equalsIgnoreCase("RBC")) {
      portNumber = Configuration.UDP_SERVER_1_PORT;
    } else if (otherBank.equalsIgnoreCase("TD")) {
      portNumber = Configuration.UDP_SERVER_2_PORT;
    } else if (otherBank.equalsIgnoreCase("BMO")) {
      portNumber = Configuration.UDP_SERVER_3_PORT;
    }

    List<Loan> loanList = loanMap.get(loanId.charAt(0));

    Customer customer = null;

    if (loanList != null) {
      Iterator<Loan> loanIterator = loanList.iterator();

      Loan loan = null;

      while (loanIterator.hasNext()) {
        loan = loanIterator.next();

        if (loan.getLoanId().equals(loanId)) {

          customer = loan.getAccount();

          SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
          String loanDueDate = sdf.format(loan.getLoanDueDate());

          String message =
              transferLoanUDP(
                  customer.getFirstName(),
                  customer.getLastName(),
                  customer.getEmailId(),
                  customer.getPhoneNumber(),
                  customer.getPassword(),
                  loan.getLoanAmount(),
                  loanDueDate,
                  portNumber);
          if (message.equalsIgnoreCase("Success")) {

            // Note: Here iterator is pointing to a loanlist that's
            // why I have used synchronized block on loanlist and
            // not on iterator
            synchronized (loanList) {
              loanIterator.remove();
            }
            customer.setCreditLimit(customer.getCreditLimit() + loan.getLoanAmount());
            updateAccountMap(customer);

            return true;
          }
          break;
        }
      }
    }

    return false;
  }
  /**
   * This method opens a bank account
   *
   * @param bankName
   * @param firstName
   * @param lastName
   * @param emailId
   * @param phoneNumber
   * @param password
   * @return accountNumber
   */
  @Override
  public String openAccount(
      String bank,
      String firstName,
      String lastName,
      String emailId,
      String phoneNumber,
      String password) {

    accountCount++;

    if (accountCount == 3) {
      return "Anunay";
    }
    System.out.println("1");
    try {
      blockingQueue.put(
          new Date()
              + ": "
              + firstName
              + " "
              + lastName
              + " has initiated a request to open an account at "
              + bank);
    } catch (InterruptedException e) {
      System.out.println(e.getMessage());
      e.printStackTrace();
    }

    Customer account = new Customer();

    account.setFirstName(firstName);
    account.setLastName(lastName);
    account.setEmailId(emailId);
    account.setPhoneNumber(phoneNumber);
    account.setPassword(password);
    account.setCreditLimit(1000);

    String accountNo = null;
    synchronized (counter) {
      System.out.println("test1");
      int accountSequence = counter.incrementAndGet();

      accountNo = firstName.charAt(0) + "" + accountSequence;
      // counter.set(new AtomicInteger(accountSequence));
      account.setAccountNumber(accountNo);
    }

    List<Customer> accountList = accountMap.get(accountNo.charAt(0));
    System.out.println("test2");
    if (accountList == null) {
      System.out.println("test3");
      accountList = new ArrayList<Customer>();
    } else {
      Iterator<Customer> accountIterator = accountList.iterator();
      System.out.println("test4");
      while (accountIterator.hasNext()) {
        Customer acct = accountIterator.next();

        if ((acct.getFirstName()).equals(firstName)
            && (acct.getLastName().equals(lastName))
            && (acct.getEmailId()).equals(emailId)) {

          return "Already-" + acct.getAccountNumber();
        }
        System.out.println("test5");
      }
    }

    synchronized (accountList) {
      System.out.println("test6");
      accountList.add(account);
      accountMap.put(firstName.charAt(0), accountList);
      System.out.println("test7");
    }
    System.out.println("test8");
    return accountNo;
  }