public static LinkedList<ReconciliationTransaction> reconcileTransactionList(LinkedList<ReconcilableTransaction> transactions) {

        Stack<AtmWithdrawalTransaction> atmStack = new Stack();
        Stack<CashPurchaseTransaction> cashStack = new Stack();
        LinkedList<ReconciliationTransaction> reconciliations = new LinkedList<ReconciliationTransaction>();

        // Sort by ReconcilableTransaction.compareTo
        Collections.sort(transactions);

        // After sorting, the older transactions should be placed at the bottom of the respective stacks
        for (ReconcilableTransaction transaction: transactions){

            if(transaction.getType() == TransactionType.ATM){

                atmStack.push((AtmWithdrawalTransaction) transaction);

            } else {
                // If this is not CASH type, something has gone wrong
                assert transaction.getType() == TransactionType.CASH;

                cashStack.push((CashPurchaseTransaction) transaction);

            }

        }

        while (!atmStack.isEmpty() && !cashStack.isEmpty()){

            ReconciliationTransaction reconciliation = null;

            // Retrieve the most recent cash transaction
            CashPurchaseTransaction cashTransaction  = cashStack.peek();
            // Retrieve the most recent atm transaction
            AtmWithdrawalTransaction atmTransaction  = atmStack.peek();

            // Only reconcile if most recent cash transaction is more recent than the most recent atm transaction
            if(cashTransaction.compareTo(atmTransaction) > 0 ){

                // Create reconciliation object and perform reconciliation processing
                reconciliation =  new ReconciliationTransaction(cashTransaction, atmTransaction);

                // Update with post-reconciliation transaction amounts
                cashTransaction = reconciliation.getCashPurchaseTransaction();
                atmTransaction  = reconciliation.getAtmWithdrawalTransaction();

                // This is where the magic happens
                // Pop consumed transactions from the top of their respective stacks
                // NOTE: If this application were multi-threaded, these stacks would have to be thread-safe
                if(cashTransaction.getAmount() == 0){
                    cashStack.pop();
                }
                if(atmTransaction.getAmount() == 0){
                    atmStack.pop();
                }

                reconciliations.add(reconciliation);

            } else {
                // We pop the atm if newest atm transaction is more recent than newest cash transaction
                // If we were receiving Real-Time data, the implementation here would be more complex
                atmStack.pop();
                continue;
            }

        }

        // If any cash transactions remain, create reconciliation record with no parent
        while (!cashStack.isEmpty()){
            CashPurchaseTransaction cashTransaction  = cashStack.pop();
            ReconciliationTransaction reconciliation = new ReconciliationTransaction(cashTransaction);

            reconciliations.add(reconciliation);

        }

        return reconciliations;

    }