Link to home
Start Free TrialLog in
Avatar of Tom Knowlton
Tom KnowltonFlag for United States of America

asked on

ArrayList not storing a NEW object each time I call Add( ) but a reference instead?

Do ArrayLists sometimes not work properly?  Are there known bugs, or am I just not using it properly?

I have some ArrayLists I am using to store class objects, on the order of 50+ class objects per ArrayList.

Later, I loop through them, and I am getting output...but not what I expected.  One of the values I access is the balance due.  It is almost always zero.

It is almost as if the Add(  ) method for the ArrayList is not adding a NEW  object each time....but overwriting it or just storing the address to the object instead of the physical object itself (along with the data).  That is the only thing that seems to explain what I am seeing happen.

Is this "normal" --  and how do I get past this problem?

I can't explain it any better than this.


Below I'll paste the DLL code as well as the demo app that uses the DLL








SOURCE CODE DUMP:




DLL code:

//Changes made on 31 July, 2007
//-Created parent class for both Heloc and Mortgage classes, which they now inherit from.  
//-I did this so I could more easily distribute new changes that apply to both classes.
//
//=====


//rename this to anything OTHER than "debug" in order to turn-off the reporting to the Output window
#define debug

using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;

namespace Driven
{

    //I wrote this class in an attempt to NOT have to write
    //System.Diagnostics.Debug.WriteLine(  )    EVERY SINGLE TIME  that I wanted some debug output
    public class DebugOut
    {
        #region Constructors
        public DebugOut()
        { }
        #endregion

        #region dOut
        public static void dOut(string message)
        {
            //My intent is to only output debug statements if the conditional define is set to "debug"
            #if debug
            System.Diagnostics.Debug.WriteLine(message);
            #endif
        }
        #endregion
    }


    //Parent class for Heloc and Mortgage classes
    //Has Amortization Period support (enumerations)
    public class CommonFinancedItems
    {
        private AmortizationPeriodType _amortType;

        //Used to tag specific Mortgage or Heloc objects with specific integer Month tag, if needed
        //This is for seeing data for specific months...
        public int _monthTag;

        public CommonFinancedItems()
        {
        }

        #region enums

        public enum AmortizationPeriodType : int
        {
            Weekly = 52,
            BiWeekly = 24,
            Monthly = 12
        }
        public AmortizationPeriodType AmortPeriod
        {
            get
            {
                return _amortType;
            }
            set
            {
                _amortType = value;
            }
        }

        #endregion

    }



    //This class represents a Home Equity Line of Credit (Heloc)
    //Inheirts from CommonFinancedItems so that it can have support
    //for Amortization Periods    
    public class Heloc : CommonFinancedItems
    {
        #region Variables

        //Events that this class can raise
        public event EventHandler HelocAmountOwedIsZero;
        public event EventHandler HelocAmountOwed;
        public event EventHandler BothPaidOff;
        public event EventHandler HelocError;

        //internal variables
        //Most are declared public for now (to ease in debugging)
        //But later on should be declared private and accessed via Properties (setters and getters)
        public int _helocReapplicationIntervalInMonths = 18;
        public double _helocAmountOwed;
        public double _helocTotalAmountAvailableNoRestrictionsEnforced;
        public double _helocAmountAllowed;
        public double _helocInterestRate;
        public double _helocMonthlyBills;
        public string ErrorMessage;        
        private DebugOut dbg = new DebugOut();

        #endregion

        #region Constructors
        //Used to initialize the internal variables for the Heloc class
        //Also note that the events are initialized to null
        public Heloc(double amountOwed, double initialAmountAvailable, double interestRate, double monthlyBills, Mortgage m)
        {
            _helocAmountOwed = amountOwed;
            this._helocTotalAmountAvailableNoRestrictionsEnforced = initialAmountAvailable;
            _helocInterestRate = interestRate;
            _helocMonthlyBills = monthlyBills;

            this.HowMuchToApplyToMortgage(m);
            HelocAmountOwedIsZero = null;
            HelocAmountOwed = null;
            BothPaidOff = null;
            HelocError = null;
        }
        #endregion
               
        #region HowMuchToApplyToMortgage
       
       
        //Used to determine how much of the available Heloc balance we can
        //apply to the Mortgage
        //
        //Notice a Mortgage object is passed in...so we can determine total equity, since
        //the Heloc amount available is a function of the total equity in the home
        public double HowMuchToApplyToMortgage(Mortgage m)
        {
            //Per my discussion with Kevin, we want to hold in reserve
            // ( do not spend ) about twice the monthly bills amount
            //This provides a cushion in case people run into financial troubles for
            //a month or two
            double safetyBuffer = 2 * this._helocMonthlyBills;

            //This is what is returned from the method...initialized to zero
            double amountToApply = 0;

            //If the safety buffer (described above) is greater than the
            //total available equity (set elsewhere in another method)
            //then raise an error and fire the HelocError event
            if (safetyBuffer > this._helocTotalAmountAvailableNoRestrictionsEnforced)
            {
                if (HelocError != null)
                {
                    this.ErrorMessage = "Equity must exceed safety buffer.  Calculation STOPPED";
                    //raise the event...
                    HelocError(this, null);
                }
            }
           
            //If the amount we have available is greater than the remaining mortgage balance, then
            //just PAY OFF THE MORTGAGE
            if (this._helocTotalAmountAvailableNoRestrictionsEnforced >= m._mortAmountOwed)
            {
                amountToApply = m._mortAmountOwed;
                this._helocAmountAllowed = amountToApply;
            }
            else //Otherise, make a big payment using the amount available - the saftety buffer
            {
                if (this._helocTotalAmountAvailableNoRestrictionsEnforced > safetyBuffer)
                {
                    this._helocAmountAllowed = this._helocTotalAmountAvailableNoRestrictionsEnforced - safetyBuffer;
                }
                else
                {
                    this._helocAmountAllowed = 0;
                }

                amountToApply = this._helocAmountAllowed - this._helocAmountOwed;
            }

            if (amountToApply < 0)
            {
                amountToApply = 0;
            }

            //Some debug output to determine if the process is working correctly
            Driven.DebugOut.dOut("");
            Driven.DebugOut.dOut("                         TOTAL TECHNICALLY AVAILABLE:  " + this._helocTotalAmountAvailableNoRestrictionsEnforced.ToString());
            Driven.DebugOut.dOut("                                              BUFFER:  " + safetyBuffer.ToString());
            Driven.DebugOut.dOut("                                             ALLOWED:  " + this._helocAmountAllowed.ToString());
            Driven.DebugOut.dOut("                  SUGGESTED AMOUNT TO USE FROM HELOC:  " + amountToApply.ToString());
            Driven.DebugOut.dOut("                                      CURRENTLY OWED:  " + this._helocAmountOwed.ToString());
            Driven.DebugOut.dOut("");
     

            return amountToApply;

        }
        #endregion


        #region CheckDebtStatus
        //Whenver this is called we ask the Heloc object "Do you owe anything?"
        //Depending on the answer, we raise the appropriate event
        //
        //Notice we pass-in a mortgage object so we can check the balance on the mortgage as well
        //--this is needed if we are to ever finish processing
        public void CheckDebtStatus(Mortgage m)
        {
            //are both the heloc and the mortgage paid off?
            if ((this._helocAmountOwed <= 0.0) && (m._mortAmountOwed <= 0.0))
            {
                if (BothPaidOff != null)
                {
                    //raise the event...
                    BothPaidOff(this, null);
                }
            }
            else if (this._helocAmountOwed > 0.0) // Is a Heloc balance still owed?
            {
                if (HelocAmountOwed != null)
                {
                    //raise the event...
                    HelocAmountOwed(this, null);
                }
            }
            else if(this._helocAmountOwed <= 0.0)  // has the Heloc balance been paid-off???
            {
                if (HelocAmountOwedIsZero != null)
                {
                    //raise the event...
                    HelocAmountOwedIsZero(this, null);
                }
            }
           
        }
        #endregion


        #region MakeHelocPayment
        //Pretty self-explanatory...this makes a payment on the Heloc balance owed
        //The parameter passed in is the amount of the payment
        public void MakeHelocPayment(double helocPayment)
        {            
            //If we owe on the Heloc, then let's make a payment on it...
            if (this._helocAmountOwed > 0.0)
            {
                double periodInterestPayment;                

                //calculate interest payment
                periodInterestPayment = this._helocAmountOwed * (this._helocInterestRate / (int)this.AmortPeriod);

                //is the amount owed on the heloc less than the payment amount?
                if ((this._helocAmountOwed + periodInterestPayment) < helocPayment)
                {
                    //If so, then pay-off the Heloc NOW!
                    this._helocAmountOwed = 0.0;
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  Heloc was just paid-off!!!");
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut("");
                }
                else  // just make a normal Heloc payment
                {
                    this._helocAmountOwed = (this._helocAmountOwed + periodInterestPayment) - helocPayment;
                    Driven.DebugOut.dOut("Heloc payment of " + helocPayment.ToString() + " was made, Heloc amount owed is:  " + this._helocAmountOwed.ToString());
                }                
            }          
        }
        #endregion
               
        #region ReturnHomeEquity
        //When called this sets the internal variable for "Total Amount of Equity"
        //This calculation is performed by looking at the original amount owing and
        //subtracting the current amount owed.
        //The difference should be the total available equity
        public double ReturnHomeEquity(Driven.Mortgage m)
        {
            return m._mortOriginalAmountOwed - m._mortAmountOwed;
        }
        #endregion



        #region RenewHelocTotalAmountAvailableNoRestrictions

        //This method is used to determine if the Amount Available for the Heloc can be increased
        //I seem to think this happens about every 18 months?
        public void RenewHelocTotalAmountAvailableNoRestrictions(double numberOfMonthsAccrued, Driven.Mortgage m)
        {
            //Update available Heloc credit line every XX months...
            if ((numberOfMonthsAccrued % this._helocReapplicationIntervalInMonths) == 0)
            {
                this._helocTotalAmountAvailableNoRestrictionsEnforced = ReturnHomeEquity(m);
                Driven.DebugOut.dOut("");
                Driven.DebugOut.dOut("");
                Driven.DebugOut.dOut("");
                Driven.DebugOut.dOut("                                  THE HELOC WAS RENEWED (" + numberOfMonthsAccrued.ToString() + "  MONTHS SINCE INCEPTION)");
                Driven.DebugOut.dOut("");
                Driven.DebugOut.dOut("");
                Driven.DebugOut.dOut("");
            }            
        }
        #endregion


        #region HelocReadyToPayDownMortgageBasedOnPercentageLeft
        //This method is called (returns true if ready to pay down) in order to
        //determine if the amountOwed has been paid-down sufficiently to allow us to make
        //yet another BIG down payment on the Mortgage Principal again
        //
        //This is determined by a Percentage Paydown "Trigger"
        //For example, if 10% is owing and the Percentage Paydown Trigger is 10%...then we can pay down again.
        public bool HelocReadyToPayDownMortgageBasedOnPercentageLeft(double percentageCEILINGLeftOfTotalBalance, Driven.Mortgage m)
        {
            //initialize to false...assume we are not going to be ready to pay down
            bool readyToPayDown = false;        

            double ThreshholdMoneyAmount = this._helocAmountAllowed * percentageCEILINGLeftOfTotalBalance;

            if ((this._helocAmountOwed <= ThreshholdMoneyAmount) && (m._mortAmountOwed > 0.0))
            {
                //As is my custom...some Debug Output to show that we are doing this and why
                //We can check the numbers to see if they reflect accurately the logic that is in place

                //only gets set to true if the conditions were met above...
                readyToPayDown = true;
                Driven.DebugOut.dOut("/////////////////////////////////////////////////////////");
                Driven.DebugOut.dOut("/////////////////////////////////////////////////////////");
                Driven.DebugOut.dOut("");
                Driven.DebugOut.dOut("READY TO PAY DOWN MORTGAGE USING HELOC AGAIN.");
                Driven.DebugOut.dOut("PAYDOWN ONLY WHEN THIS MUCH IS OWED (OR LESS):  " + ThreshholdMoneyAmount.ToString("F"));
                Driven.DebugOut.dOut("                                HOW MUCH OWED:  " + this._helocAmountOwed.ToString("F"));
                Driven.DebugOut.dOut("/////////////////////////////////////////////////////////");
                Driven.DebugOut.dOut("/////////////////////////////////////////////////////////");
            }

            return readyToPayDown;
        }
        #endregion
    }


















    //This class represents your Mortgage, a Mortgage, any Mortgage...
    //Inheirts from CommonFinancedItems so that it can have support
    //for Amortization Periods
    public class Mortgage : CommonFinancedItems
    {
        #region Variables

        //Events that this class can raise
        public event EventHandler MortAmountOwedIsZero;
        public event EventHandler MortAmountOwed;
        public event EventHandler BothPaidOff;
               
        //Internal variables
        //Declared public for now to help with debugging
        //but later on...should be declared private and modified
        //using setters and getters (Properities)
        public double _mortOriginalAmountOwed;
        public double _mortAmountOwed;        
        public double _mortInterestRate;
        public double _interestAccrued;
        private DebugOut dbg = new DebugOut();
        #endregion
               
        #region Constructors
               

        //Initializes the Mortgage object
        public Mortgage(double amountOwed, double interestRate)
        {
            //initialize mortgage object...
            _mortOriginalAmountOwed = amountOwed;
            _mortAmountOwed = amountOwed;            
            _mortInterestRate = interestRate;
           
            //set events to null...
            MortAmountOwedIsZero = null;
            MortAmountOwed = null;
            BothPaidOff = null;
        }
        #endregion

        #region CheckDebtStatus
        //Asks the Mortgage object:  "Do you owe any money?"
        //If so...raise the correct event!
        //
        //Notice a Heloc object is passed-in so we can determine if anything is still oweing
        //on the Heloc as well...
        public void CheckDebtStatus(Heloc h)
        {
            //Are both the Mortgage and the Heloc paid-off now???
            if ((h._helocAmountOwed <= 0.0) && (this._mortAmountOwed <= 0.0))
            {
                if (BothPaidOff != null)
                {
                    //raise the event...
                    BothPaidOff(this, null);
                }
            }
            else if (this._mortAmountOwed > 0.0) //Mortgage still owes something
            {
                if (MortAmountOwed != null)
                {
                    //raise the event...
                    MortAmountOwed(this, null);
                }
            }
            else if (this._mortAmountOwed <= 0.0)  //Mortgage is paid-off now!!
            {
                //raise the event...
                if (MortAmountOwedIsZero != null)
                {
                    MortAmountOwedIsZero(this, null);
                }
            }            
        }
        #endregion

        #region CalcNormalTermNoHelocApplied
        //This just does a straight amortization with no Heloc "pay down" involved at all...
        //Payment amount is passed-in...
        //Usually what will happen is a seperate and distinct Mortgage object will be declared
        //and ONLY this methodw would be called.
        //In other words...this method would never be called in conjunction with a Mortgage object
        //that was participating in a Heloc pay-down program at the same time.
        public void CalcNormalTermNoHelocApplied(double paymentAmount)
        {
            while (this._mortAmountOwed > 0.0)
            {
                this.MakeMortgagePayment(paymentAmount);
            }
        }
        #endregion


        #region MakeMortgagePayment
        //Call this method to make a mortgage payment
        //Payment amount is passed in...
        public void MakeMortgagePayment(double mortPayment)
        {
            double periodInterestPayment = 0;

            //calculate the monthly interest
            periodInterestPayment = this._mortAmountOwed * (this._mortInterestRate / (int)this.AmortPeriod);
           
            //to calculate interest saved
            _interestAccrued += periodInterestPayment;
           
            //Only make a payment if there is still money owed...
            if (this._mortAmountOwed > 0.0)
            {                
                //If the amount owed is less than or equal to the payment amount, then pay-off the loan
                if ((this._mortAmountOwed + periodInterestPayment) <= mortPayment)
                {
                    //Some debug output to verify this happened
                    this._mortAmountOwed = 0.0;
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  Mortgage has been paid-off completely!!!!!!!");
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut("");
                }
                else  //otherwise just make a normal payment
                {

                    //For debug / reporting purposes
       
                    Driven.DebugOut.dOut("");
                    Driven.DebugOut.dOut("Previous mortgage balance owed (" + this._mortAmountOwed.ToString() + " + " + periodInterestPayment.ToString() + "):  " + (this._mortAmountOwed + periodInterestPayment));
                    Driven.DebugOut.dOut("Mortgage payment made:  " + mortPayment.ToString());

                    //add monthly interest to entire amount owing, then pay on THAT
                    this._mortAmountOwed = (this._mortAmountOwed + periodInterestPayment) - mortPayment;

                    Driven.DebugOut.dOut("After payment, now mortgage balance is now:  " + this._mortAmountOwed.ToString());
                }
            }      

        }
        #endregion

    }// end of Mortgage class  








    //INTENT:  This class is the class that instantiates both the Mortgage and Heloc objects
    //and then runs them through their paces!
    public class DrivenExpert
    {
        #region Variables        

        //Heloc object to be used throughout the various class methods
        public Heloc _heloc;

        //Mortgage object to be used throughout the various class methods
        public Mortgage _mortgage;

        //SPECIAL Mortgage object that does not take advantage of the Heloc pay down
        public Mortgage _mortgageNoHeloc;

        //How many mortgage payments have been made?
        private int _mortPaymentsAccrued = 0;
        //How many heloc payments have been made?
        private int _helocPaymentsAccrued = 0;
        //When this percentage of the Heloc balance is remaining ... do another pay-down
        public double _payDownPercentageTrigger;
        //Accumulates the amortized heloc payments as they accrue
        //For example, if you are making weekly payments, they would accrue in this variable
        private double _helocPaymentGradualAccrual;
        //Boolean which says "the correct number of amortized payments have been made on the Heloc
        //now you can pay on the Mortgage"
        private bool _timeToPayMortgageNow = true;
        //Mortgage payment amount
        public double _monthlyMortPay;
        //Amortized heloc payment (divided into weekly, biweekly or Monthly payments)
        public double _helocAmortizedPayment;
        //Monthly amount for our use (pre-amortization)
        private double _originalHelocMonthlyPaymentAmount;

        //For the down line bonus program - the amount to add to our discretionary income
        private double _downLineAccrualAmount;
        //MAX amount that we can spend
        private double _downLineAccrualCeiling;
        //How often to add the down line bonus to the discretionary income
        private int _downLineIncIntervalInMonths;
        //Keeps track of how much we have added to the discretionariy income so far
        //using the bonus amount
        private double _downLineAccrualAmountAccumulator;
       
        //Internal declaration of the Driven.CommonFinancedItem class
        //Used to set the Amortization period
        public Driven.CommonFinancedItems _commonFinancedItem;

        //Used to store Mortgage objects as needed for showing specific mortgage information for a
        //particular month
        public ArrayList _specificMortMonths = new ArrayList();

        //Used to store Heloc bjects as needed for showing specific heloc information for a
        //particular month
        public ArrayList _specificHelocMonths = new ArrayList();


        //Used for debug output
        private DebugOut dbg = new DebugOut();        

        #endregion

        #region Constructors
        //Initialized the DrivenExpert object
        public DrivenExpert(double mortAmountOwed,
            double mortInterestRate,
            double monthlyMortPay,
            double helocAmountOwed,
            double helocAmountAvailable,
            double helocInterestRate,
            double helocMonthlyBills,
            double helocPayment,
            double helcoPayDownPercentageTrigger)
        {
            _monthlyMortPay = monthlyMortPay;
            _helocAmortizedPayment = helocPayment;
            _originalHelocMonthlyPaymentAmount = helocPayment;
            _payDownPercentageTrigger = helcoPayDownPercentageTrigger;
            _commonFinancedItem = new CommonFinancedItems();
            _mortgage = new Mortgage(mortAmountOwed, mortInterestRate);
            _mortgageNoHeloc = new Mortgage(mortAmountOwed, mortInterestRate);            
            _heloc = new Heloc(helocAmountOwed, helocAmountAvailable, helocInterestRate, helocMonthlyBills, _mortgage);


            //sign-up for the events we want to be notified of

            //We want to be notified when either Mortgage or Heloc are still owing
            _heloc.HelocAmountOwed += new EventHandler(this.FinancedItemOwing);
            _mortgage.MortAmountOwed += new EventHandler(this.FinancedItemOwing);

            //We want to be notified when either Mortgage or Heloc are paid-off
            _heloc.HelocAmountOwedIsZero += new EventHandler(this.FinancedItemIsZero);
            _mortgage.MortAmountOwedIsZero += new EventHandler(this.FinancedItemIsZero);

            //We want to be notified when BOTH Mortgage AND Heloc are paid-off
            _heloc.BothPaidOff += new EventHandler(this.BothPaidOff);
            _mortgage.BothPaidOff += new EventHandler(this.BothPaidOff);
        }
        #endregion      
               
        #region Properties

        //Used to set the Down Line Bonus program variables
        public double DownLineAccrualAmount
        {
            set
            {
                _downLineAccrualAmount = value;
            }
        }

        public double DownLineAccrualCeiling
        {
            set
            {
                _downLineAccrualCeiling = value;
            }
        }

        public int DownLineIncIntervalInMonths
        {
            set
            {
                _downLineIncIntervalInMonths = value;
            }
        }


        //If Monthly, the multiplier is 1
        //If BiWeekly, the multiplier is 2
        //If Weekly, the multipler is 4.33(repeating)
        public double HelocAmortizationPeriodMultiplier
        {
            get
            {
                double AmortPeriodDivisor = (int)this._heloc.AmortPeriod;
                double divisor = 12;
                return AmortPeriodDivisor / divisor;              
            }
        }

        //Return Heloc months accrued (reflect amortization period)
        public double HelocMonthsAccrued
        {
            get
            {
                double months = this._helocPaymentsAccrued / this.HelocAmortizationPeriodMultiplier;
                return months;
            }            
        }

        //Return Mortgage months accrued (reflect amortization period)
        public int MortgageMonthsAccrued
        {
            get
            {
                int AmortPeriodDivisor = (int)Driven.CommonFinancedItems.AmortizationPeriodType.Monthly;
                int divisor = 12;
                int months = this._mortPaymentsAccrued / (AmortPeriodDivisor / divisor);
                return months;
            }            
        }
        #endregion


        //This method gets called when the BothPaid event gets raised in either the Heloc or the Mortgage class
        public void BothPaidOff(object sender, EventArgs e)
        {
            Driven.DebugOut.dOut(sender.ToString() + " says DONE, amount owing is zero on both accounts");
        }

        #region GetOutOfDebt
        //As I have inidicated elsewhere...this method call does all the work
        //It is the workhorse of the DrivenExpert class
        public void GetOutOfDebt()
        {
            //Set the amortization period for the mortgage object (usually monthly)
            _mortgage.AmortPeriod = Driven.CommonFinancedItems.AmortizationPeriodType.Monthly;

            //Set the amortization period for the Heloc object (Weekly, BiWeekly or Monthly)
            _heloc.AmortPeriod = this._commonFinancedItem.AmortPeriod;

            //Initialize the Accumulator to the heloc amortized payemnt (not amortized at this point)
            _downLineAccrualAmountAccumulator = _helocAmortizedPayment;

            //Set the Heloc Amortized Payment (Weekly, BiWeekly, or Monthly)
            this.SetNewHelocAmortizedPayment();
           
            //Start the ball rolling by asking the _mortgage object if it owes anything
            //The answer needs to be yes (of course it should be, since we want to pay down the mortgage)
            _mortgage.CheckDebtStatus(_heloc);
            //Same thing for the Heloc object
            _heloc.CheckDebtStatus(_mortgage);


            //By this point we are DONE....output the debug results
            double mma = this.MortgageMonthsAccrued;
            double hma = this.HelocMonthsAccrued;
            Driven.DebugOut.dOut("Months to pay-off Mort:  " + mma.ToString());
            Driven.DebugOut.dOut("Months to pay-off Heloc:  " + hma.ToString());
            Driven.DebugOut.dOut("Months to pay-off Both:  " + (Math.Min(mma, hma) + (Math.Max(mma, hma) - Math.Min(mma, hma))));
        }


        //This method is used to set the Amortized payment amount for the Heloc
        public void SetNewHelocAmortizedPayment()
        {
            //downLineAccrualAmountAccumulator cannot surpass the CELING ... if so make
            //it EQUAL to the ceiling amount
            if (_downLineAccrualAmountAccumulator >= this._downLineAccrualCeiling)
            {
                _downLineAccrualAmountAccumulator = this._downLineAccrualCeiling;

                //Throw an exeception if the CELING is set to ZERO for some reason...
                //this does not make sense
                if (_downLineAccrualAmountAccumulator == 0)
                {
                    Driven.DebugOut.dOut("Error; downLineAccrualCeiling is zero");
                    throw new Exception("downLineAccrualCeiling is zero");
                }
            }

            //Set the _heloc amortized payment using the accumulator amount divided by the amortization period multiplier
            //since _helocAmortizedPayment is internal, no need to return anything
            _helocAmortizedPayment = _downLineAccrualAmountAccumulator / this.HelocAmortizationPeriodMultiplier;
        }


        //Used to calculate interest saved by using the Heloc pay down program
        //This is done by generating two mortgage objects...one that uses the heloc and one that does not
        //then subtracting the difference between the interest accrued under the two programs
        public double CalcInterestSaved()
        {
            try
            {
                _mortgageNoHeloc.AmortPeriod = Driven.CommonFinancedItems.AmortizationPeriodType.Monthly;

                _mortgageNoHeloc.CalcNormalTermNoHelocApplied(_monthlyMortPay);

                return this._mortgageNoHeloc._interestAccrued - this._mortgage._interestAccrued;
            }
            catch (Exception ee)
            {
                Driven.DebugOut.dOut("Error in the CalcInterestSaved( ) method:  " + ee.Message.ToString());
                throw new Exception("An error occured in CalcInterestSaved( ) method" + ee.Message.ToString());
            }
        }

        #endregion
               
        #region FinancedItemOwing
        //This method gets called when the Mortgage Or the Heloc objects OWE SOMETHING
        public void FinancedItemOwing(object sender, EventArgs e)
        {
            //First thing we want to do is determine if a Heloc pay down is possible
            bool canPayDownBasedUponPercentageLeft = _heloc.HelocReadyToPayDownMortgageBasedOnPercentageLeft(this._payDownPercentageTrigger, _mortgage);

            //If it is the Mortgage Object that raised the event ("Mortgage is saying, 'I owe something still'")
            //AND it is time to make a mortgage payment again (based upon the number of heloc payments each month)
            //If those conditions are both true...then make a payment
            if (sender is Driven.Mortgage && _timeToPayMortgageNow)
            {
                //Since a mortgage payment is due ... can we use the Heloc to pay down a big chunk
                //of the principal?
                if (canPayDownBasedUponPercentageLeft)
                {
                    //Determine how big of a chunk we can apply to the principal
                    double tempHowMuchToApply = this._heloc.HowMuchToApplyToMortgage(_mortgage);
                    this._heloc._helocAmountOwed += tempHowMuchToApply;
                    _mortgage.MakeMortgagePayment(this._monthlyMortPay + tempHowMuchToApply);
                    _mortPaymentsAccrued++;


                    //Store the current information for the month in question
                    //  as the Mort Payments Accrued increments, this represents ONE month.
                    _mortgage._monthTag = _mortPaymentsAccrued;
                    _heloc._monthTag = _mortPaymentsAccrued;  //otherwise we won't get an even month
                    this._specificMortMonths.Add(this._mortgage);
                    this._specificHelocMonths.Add(this._heloc);


                    Driven.DebugOut.dOut("Mort Month:  " + this._mortPaymentsAccrued.ToString());



                    //down line accrual
                    if (this.MortgageMonthsAccrued % this._downLineIncIntervalInMonths == 0)
                    {
                        Driven.DebugOut.dOut("OLD Amortized amount:  " + this._helocAmortizedPayment.ToString());

                        _downLineAccrualAmountAccumulator += _downLineAccrualAmount;
                        SetNewHelocAmortizedPayment();
                        //see about not having to fully qualify this:
                        Driven.DebugOut.dOut("DONE setting new amortized amount now...");
                        Driven.DebugOut.dOut("NEW Amortized amount:  " + this._helocAmortizedPayment.ToString());
                    }


                    //Let's see if the Heloc object still OWES anything
                    _heloc.CheckDebtStatus(_mortgage);                    
                }
                else //Otherwise, just make a regular mortgage payment...
                {
                    _mortgage.MakeMortgagePayment(this._monthlyMortPay);
                    _mortPaymentsAccrued++;
                    Driven.DebugOut.dOut("Mort Month:  " + this._mortPaymentsAccrued.ToString());



                    //Store the current information for the month in question
                    //  as the Mort Payments Accrued increments, this represents ONE month.
                    _mortgage._monthTag = _mortPaymentsAccrued;
                    _heloc._monthTag = _mortPaymentsAccrued;  //otherwise we won't get an even month
                    this._specificMortMonths.Add(this._mortgage);
                    this._specificHelocMonths.Add(this._heloc);




                    //down line accrual bonus
                    if (this.MortgageMonthsAccrued % this._downLineIncIntervalInMonths == 0)
                    {
                        Driven.DebugOut.dOut("OLD Amortized amount:  " + this._helocAmortizedPayment.ToString());

                        _downLineAccrualAmountAccumulator += _downLineAccrualAmount;
                        SetNewHelocAmortizedPayment();
                        //see about not having to fully qualify this:
                        Driven.DebugOut.dOut("DONE setting new amortized amount now...");
                        Driven.DebugOut.dOut("NEW Amortized amount:  " + this._helocAmortizedPayment.ToString());
                    }

                    //Let's see if the Heloc object still OWES anything
                    _heloc.CheckDebtStatus(_mortgage);
                 
                }                
            }
            else if(sender is Driven.Mortgage && !_timeToPayMortgageNow)//  Mortgage:  I OWE SOMETHING, BUT IT'S NOT TIME TO MAKE A PAYMENT YET
            {
                //Even though it's not time to make a payment....we still need to also check the Heloc
                //to see if IT owes something right now...
                _heloc.CheckDebtStatus(_mortgage);
            }

            if (sender is Driven.Heloc) //Heloc object says:  "I OWE SOMETHING"
            {
                //If Mortgage is paid-off, then we can use our discretionary income to make
                //a much BIGGER payment now...
                if (_mortgage._mortAmountOwed == 0.0)
                {
                    _heloc.MakeHelocPayment(this._helocAmortizedPayment + this._monthlyMortPay);                    
                }
                else  //otherwise, just make a regular payment (amortized payment)
                {
                    _heloc.MakeHelocPayment(this._helocAmortizedPayment);                    
                }
               

                //Another payment was made...
                _helocPaymentsAccrued++;    
           
                //We just made another amortized payment                
                _helocPaymentGradualAccrual += this._helocAmortizedPayment;


                //When our amortized payments are equal to or greater than our
                //Montly discretionary income...then we can make a mortgage payment
                //and the accumulator zeros-out
                if (_helocPaymentGradualAccrual >= _originalHelocMonthlyPaymentAmount)
                {
                    _timeToPayMortgageNow = true;
                    _helocPaymentGradualAccrual = 0.0;
                }
                else
                {
                    _timeToPayMortgageNow = false;
                }            
               
                //check to see if we can increase the amount of the Heloc (about every 18 months)
                _heloc.RenewHelocTotalAmountAvailableNoRestrictions(this.HelocMonthsAccrued, _mortgage);
                Driven.DebugOut.dOut("Heloc Month:  " + this.HelocMonthsAccrued.ToString());

                //Now that we're done with the Heloc processing...let's check on Mortgage to see if it is
                //still OWING something
                _mortgage.CheckDebtStatus(_heloc);                
               
            }            
        }
        #endregion
               

       
        #region FinancedItemIsZero
        //Event that gets called when either Heloc or Mort is zero
        public void FinancedItemIsZero(object sender, EventArgs e)
        {
            Driven.DebugOut.dOut("Financed Item is Zero.  Sender is:  " + sender.ToString());

            //if sender is Mortgage then Mortgage owing is $0
            //if sender is Heloc then Heloc owing is $0
           
            if (sender is Driven.Mortgage)
            {
                Driven.DebugOut.dOut("Mortgage payment should be applied to Heloc, since Mortgage owing is now:  " + _mortgage._mortAmountOwed.ToString());
               
                _heloc.CheckDebtStatus(_mortgage);            
            }

            if (sender is Driven.Heloc)
            {
                //This line was added because...during debugging we could manage to
                //pay-off the Heloc without setting the "pay mortgage now" to TRUE
                //This has to happen regardless of if another amortized payment was pending on the Heloc
                //(would have normally been pending when the Heloc was paid-off, that is)
                this._timeToPayMortgageNow = true;

                //Ask the Morgage object is it is still OWING something
                _mortgage.CheckDebtStatus(_heloc);
            }

        }
        #endregion        

    }//end of DrivenExpert class

}//end of namespace driven





==============================
==============================


demo app (windows form) that uses the DLL:


//This code is for the Windows Form that I have been using to test
//the DrivenExpert class

//A series of text boxes have been placed on the form to gather the various
//pieces of information that is needed to exercise the DrivenExpert class.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplicationDrivenTestBed
{
    public partial class Form1 : Form
    {
        //delcare the DrivenExpert object
        private Driven.DrivenExpert de;

        //set to true if the Text Boxes need to be cleared
        //usually due to an error...
        private bool _needToClearBoxes = false;

        public Form1()
        {
            //As you know, .NET provides this, I didn't write it
            InitializeComponent();
        }

        public bool PassedValidation()
        {
            double month_inc = Double.Parse(this.textBoxMonthlyIncome.Text);
            double month_bills = Double.Parse(this.textBoxMonthlyBills.Text);
            double mort_pay = Double.Parse(this.textBoxMonthlyMortgagePayment.Text);

            double out_pay = month_bills + mort_pay;

            bool passedInspection = true;

            if (month_inc < out_pay)
            {
                MessageBox.Show("Your monthly out pay exceeds your income");
                passedInspection = false;
            }

            return passedInspection;
        }

        private void buttonCalculate_Click(object sender, EventArgs e)
        {
            //A series of variables to collect information from the Window Form text boxes
            double oma = Double.Parse(textBoxOrigMortAmount.Text);
            double omr = Double.Parse(this.textBoxOrigMortRate.Text);
            double ihb = Double.Parse(this.textBoxInitialHelocBalance.Text);
            double ihr = Double.Parse(this.textBoxHelocRate.Text);
            double di = Double.Parse(this.textBoxDiscretionaryIncome.Text);
            double mb = Double.Parse(this.textBoxMonthlyBills.Text);
            double mmp = Double.Parse(this.textBoxMonthlyMortgagePayment.Text);
            double pdpt = Double.Parse(this.textBoxHelocPayDownPercentageTrigger.Text);
            //recently added to support down line bonus every few months
            double dlaa = Double.Parse(this.textBoxDownLineBonus.Text);
            double dlac = Double.Parse(this.textBoxDownLineBonusCeiling.Text);
            int dliiim = Int32.Parse(this.textBoxBonusAccrualIntervalInMonths.Text);
           

            //Now that we have gathered the needed information (above) ... we can initialize
            //the DrivenExpert object and pass in the values into the constructor

            //First we need to pass some simple validation to make sure that income is not less
            //than the outflow
            if (PassedValidation())
            {
                de = new Driven.DrivenExpert(oma, omr, mmp, 0, ihb, ihr, mb, di, pdpt);



                //Since I already deployed the DLL for integration by Eric,
                //I decided to implement these as properties instead of changing the
                //parameter count of the constructor

                //...I suppose I could just overload the Constructor and be just fine
                //adding in these 3 variables (so they can get initialized as well?
                de.DownLineAccrualAmount = dlaa;
                de.DownLineAccrualCeiling = dlac;
                de.DownLineIncIntervalInMonths = dliiim;

                //Here...I set the Amortization Period using an object of type
                // Driven.CommonFinancedItems, which contains the amortization enumeration

                //NOTE...both the Heloc class and Mortgage class now inherit from Driven.CommonFinancedItem
                //I plan to explain why elsewhere, but the short answer is I needed amortization period support
                //in both the Heloc and Mortgage classes, and creating a parent for them both seemed to be the
                //easiest way to do this (kind of backwards, I know;  originally, the Heloc and Mortgage classes did
                //not have a parent class.
                de._commonFinancedItem.AmortPeriod = ReturnChosenAmortType(this.comboBoxAmortizationPeriod.Text);


                //Here I am signing-up for the HelocError event
                //Mortgage class needs this as well!  So much to do, so little time...
                de._heloc.HelocError += new EventHandler(this.ErrorOccurred);

                //This small little method call is actually the CRUX of how the
                //DrivenExpert class does it's "magic"
                //It is THIS call that does all the work.
                de.GetOutOfDebt();



                //Okay....now that we're done calculating everything via the call to
                //  de.GetOutOfDebt(); ----  now it is time for some OUTPUT of our results:

                //Display how many months it takes to pay-off the Heloc
                this.textBoxHowLongToPayOffHeloc.Text = de.HelocMonthsAccrued.ToString();

                //Display how many months it takes to pay-off the Mortgage (using the Heloc to pay-down
                //the Mortgage Principal the whole time, of course...
                this.textBoxHowLongToPayOffMortgage.Text = de.MortgageMonthsAccrued.ToString();

                //Convert the amount of months it took to pay off the Heloc into YEARS
                double years = de.HelocMonthsAccrued / 12.0;

                //Display the number of months (with years in parentheses) to pay off BOTH the mortgage and heloc both
                //As I understand it...it should always take longer to pay-off the Heloc
                this.textBoxHowLongToPayOffMortgageAndHeloc.Text = de.HelocMonthsAccrued.ToString() + " months (" + years.ToString("F") + " years)";

                //Display the interest saved using the Heloc "program"
                this.textBoxInterestSavedUsingHeloc.Text = de.CalcInterestSaved().ToString("F");

                //Display the interest accrued while paying-off the Mortgage WITHOUT USING the Heloc pay down program
                this.textBoxInterestOwedWithoutHeloc.Text = de._mortgageNoHeloc._interestAccrued.ToString("F");

                //Display the amount of interest accrued while paying-off the Mortgage USING the Heloc pay down program
                this.textBoxInterestOwedUsingHeloc.Text = de._mortgage._interestAccrued.ToString("F");


                //If the Heloc class raised an error, clear the text boxes
                //notice that we reset the boolean afterwards, so we're ready for the next error
                if (this._needToClearBoxes)
                {
                    this.ClearResultsBoxes();
                    this._needToClearBoxes = false;
                }


                //SKIP THIS, NOT NEEDED
                //used while debugging...just leaving it here for grins
                //a good way to verify that the Amort Period got set I guess
                //MessageBox.Show(de.HelocAmortizationPeriodMultiplier.ToString());

            }

        }


        //Okay, this method is responsible for displaying in the DataGrid
        //the "spread" of values using a different "Percentage Trigger" each time
        //By "Percentage Trigger" I mean the percentage value which represents
        //how much is left owing on the Heloc before another pay down can happen
        //
        //So ".10" means that  when 10% of the total balance owed is remaning to be paid...another pay down can happen
        private void buttonCalcPercentageSpread_Click(object sender, EventArgs e)
        {

            //Clear the datagrid because we're getting ready to use it
            this.dataGridViewResults.Rows.Clear();

            //An ArrayList object used to collect the data as it is generated and saved to each string array
            System.Collections.ArrayList ar = new System.Collections.ArrayList();

            //Declar the array of percentages
            double[] percentageArray = new double[9];

            //initialize it
            percentageArray[0] = .10;
            percentageArray[1] = .20;
            percentageArray[2] = .30;
            percentageArray[3] = .40;
            percentageArray[4] = .50;
            percentageArray[5] = .60;
            percentageArray[6] = .70;
            percentageArray[7] = .80;
            percentageArray[8] = .90;


            //Now, loop through N times where N is the length of the array above
            //Each time through we are using a new "Percentage Trigger" value (10% left THRU 90% left)
            for (int i = 0; i < percentageArray.Length; i++)
            {

                //Just like we did for the Calculate button, now we need to gather data for use
                //by the "Calculate Spread" functionality
                double oma = Double.Parse(textBoxOrigMortAmount.Text);
                double omr = Double.Parse(this.textBoxOrigMortRate.Text);
                double ihb = Double.Parse(this.textBoxInitialHelocBalance.Text);
                double ihr = Double.Parse(this.textBoxHelocRate.Text);
                double di = Double.Parse(this.textBoxDiscretionaryIncome.Text);
                double mb = Double.Parse(this.textBoxMonthlyBills.Text);
                double mmp = Double.Parse(this.textBoxMonthlyMortgagePayment.Text);
                double pdpt = percentageArray[i];
               
                //recently added support for the down line bonus program
                double dlaa = Double.Parse(this.textBoxDownLineBonus.Text);
                double dlac = Double.Parse(this.textBoxDownLineBonusCeiling.Text);
                int dliiim = Int32.Parse(this.textBoxBonusAccrualIntervalInMonths.Text);
               

                //Declare and initialize the "tempde" DrivenExpert object
                Driven.DrivenExpert tempde = new Driven.DrivenExpert(oma, omr, mmp, 0, ihb, ihr, mb, di, pdpt);

                //Set the amortization period using an object of type
                // Driven.CommonFinancedItems, which contains the amortization enumeration

                tempde._commonFinancedItem.AmortPeriod = ReturnChosenAmortType(this.comboBoxAmortizationPeriod.Text);

                //Set the properties for the Down Line bonus program
                tempde.DownLineAccrualAmount = dlaa;
                tempde.DownLineAccrualCeiling = dlac;
                tempde.DownLineIncIntervalInMonths = dliiim;

                //We want to sign-up for the HelocError in case we get an Error
                tempde._heloc.HelocError += new EventHandler(this.ErrorOccurred);
               

                //Just like in the Calcute Button event handler....here is where
                //we do ALL the work...where the "magic" happens in the DrivenExpert class
                tempde.GetOutOfDebt();


                //Here we are collecting the Interest Saved, Interest Normal (no Heloc) and Interest Using Heloc
                double interestSaved = tempde.CalcInterestSaved();
                double interestNormal = tempde._mortgageNoHeloc._interestAccrued;
                double interestHeloc = tempde._mortgage._interestAccrued;

                //We want to know how many years it takes to pay-off both the Heloc and Mortgage
                //Which is usually however long it takes to pay-off the Heloc
                double years = tempde.HelocMonthsAccrued / 12.0;


                //Here is where we create a new array of strings to hold our values
                string[] newrow = new string[] {
                    pdpt.ToString(),
                    tempde.HelocMonthsAccrued.ToString() + " (" + years.ToString("F") + " years)",
                    interestNormal.ToString("F"),
                    interestHeloc.ToString("F"),
                    interestSaved.ToString("F")};

                //Store results to an ArrayList (will loop through it later to get the results)
                //For now we are just gathering information ONLY
                ar.Add(newrow);
            }

            //Add results to data grid...
            //After this for loop runs you will see the results displayed in the datagrid
            for(int i = 0; i < ar.Count; i++)
            {
                this.dataGridViewResults.Rows.Add(((string[])ar[i]));
            }


            //Highlight the columns of interest in the data grid
            this.dataGridViewResults.Columns[0].DefaultCellStyle.BackColor = Color.Aqua;
            this.dataGridViewResults.Columns[1].DefaultCellStyle.BackColor = Color.Aqua;
            this.dataGridViewResults.Columns[4].DefaultCellStyle.BackColor = Color.Aqua;


            //If an error occurred in the Heloc class, we want to clear the results
            //notice, we reset the boolean so we are ready for the next error
            if(this._needToClearBoxes)
            {
                this.ClearResultsBoxes();
                this._needToClearBoxes = false;
            }
        }

        #region ClearResultsBoxes
        //This method clears the Text Boxes AND the DataGrid (the one which displays the percentage spread)
        public void ClearResultsBoxes()
        {
            //Clear the TextBoxes that show the results
            this.textBoxHowLongToPayOffHeloc.Text = "";
            this.textBoxHowLongToPayOffMortgage.Text = "";
            this.textBoxHowLongToPayOffMortgageAndHeloc.Text = "";
            this.textBoxHowMuchToApplyToMortgage.Text = "";
            this.textBoxInterestOwedUsingHeloc.Text = "";
            this.textBoxInterestOwedWithoutHeloc.Text = "";
            this.textBoxInterestSavedUsingHeloc.Text = "";

            //Clear the datagrid...
            this.dataGridViewResults.Rows.Clear();
        }
        #endregion


        #region ErrorOccurred
        //This is the Event Handler for any errors that are raised
        public void ErrorOccurred(object sender, EventArgs e)
        {
            //Right now, only the Heloc class is raising these kinds of errors
            if(sender is Driven.Heloc)
            {
                //Show the error message
                MessageBox.Show(((Driven.Heloc)sender).ErrorMessage);

                //The boolean tracks "globally" the need to clear the results due to an error
                _needToClearBoxes = true;                
            }

            //If this line is not run, the error will never go away
            ((Driven.Heloc)sender).HelocError -= new EventHandler(this.ErrorOccurred);

        }
        #endregion

 
        //This method was written to support the Drop Down Box that has the Amortization Period Types
        //It would be nice at some future time to set the Amortization Period Type directly using the
        //Drop down
        //Until that day...I'm using this to do it
        private Driven.CommonFinancedItems.AmortizationPeriodType ReturnChosenAmortType(string chosenItem)
        {
            if (chosenItem == "Weekly")  //I know, I know...yucky to hard-code this
            {
                return Driven.CommonFinancedItems.AmortizationPeriodType.Weekly;
            }

            if (chosenItem == "BiWeekly")
            {
                return Driven.CommonFinancedItems.AmortizationPeriodType.BiWeekly;
            }

            return Driven.CommonFinancedItems.AmortizationPeriodType.Monthly;
        }

        private void buttonShowSpecificMonths_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < de._specificMortMonths.Count; i++)
            {
                Driven.DebugOut.dOut("MORTGAGE");
                Driven.DebugOut.dOut("Month:  " + ((Driven.Mortgage)de._specificMortMonths[i])._monthTag.ToString());
                Driven.DebugOut.dOut("Balance:  " + ((Driven.Mortgage)de._specificMortMonths[i])._mortAmountOwed.ToString());
                Driven.DebugOut.dOut("Interest Accrued:  " + ((Driven.Mortgage)de._specificMortMonths[i])._interestAccrued.ToString());
            }

            for (int i = 0; i < de._specificHelocMonths.Count; i++)
            {
                Driven.DebugOut.dOut("HELOC");
                Driven.DebugOut.dOut("Month:  " + ((Driven.Heloc)de._specificHelocMonths[i])._monthTag.ToString());
                Driven.DebugOut.dOut("Balance:  " + ((Driven.Heloc)de._specificHelocMonths[i])._helocAmountOwed.ToString());
                //Driven.DebugOut.dOut("Interest Accrued:  " + ((Driven.Heloc)de._specificHelocMonths[i]).._interestAccrued.ToString());
            }

            MessageBox.Show("Done");

        }

        private void buttonRefresh_Click(object sender, EventArgs e)
        {
            double month_inc = Double.Parse(this.textBoxMonthlyIncome.Text);
            double month_bills = Double.Parse(this.textBoxMonthlyBills.Text);
            double mort_pay = Double.Parse(this.textBoxMonthlyMortgagePayment.Text);

            double out_pay = month_bills + mort_pay;

            if (PassedValidation())
            {
                double discretionaryInc = month_inc - out_pay;

                this.textBoxDiscretionaryIncome.Text = discretionaryInc.ToString("F");
            }
        }    

    }//End of Form1 class

}//End of WindowsApplicationDrivenTestBed Namespac
Avatar of Tom Knowlton
Tom Knowlton
Flag of United States of America image

ASKER

Here is where I ADD the objects to the ArrayList:


        public void FinancedItemOwing(object sender, EventArgs e)
        {
            //First thing we want to do is determine if a Heloc pay down is possible
            bool canPayDownBasedUponPercentageLeft = _heloc.HelocReadyToPayDownMortgageBasedOnPercentageLeft(this._payDownPercentageTrigger, _mortgage);

            //If it is the Mortgage Object that raised the event ("Mortgage is saying, 'I owe something still'")
            //AND it is time to make a mortgage payment again (based upon the number of heloc payments each month)
            //If those conditions are both true...then make a payment
            if (sender is Driven.Mortgage && _timeToPayMortgageNow)
            {
                //Since a mortgage payment is due ... can we use the Heloc to pay down a big chunk
                //of the principal?
                if (canPayDownBasedUponPercentageLeft)
                {
                    //Determine how big of a chunk we can apply to the principal
                    double tempHowMuchToApply = this._heloc.HowMuchToApplyToMortgage(_mortgage);
                    this._heloc._helocAmountOwed += tempHowMuchToApply;
                    _mortgage.MakeMortgagePayment(this._monthlyMortPay + tempHowMuchToApply);
                    _mortPaymentsAccrued++;


                    //Store the current information for the month in question
                    //  as the Mort Payments Accrued increments, this represents ONE month.
                    _mortgage._monthTag = _mortPaymentsAccrued;
                    _heloc._monthTag = _mortPaymentsAccrued;  //otherwise we won't get an even month
                    this._specificMortMonths.Add(this._mortgage);
                    this._specificHelocMonths.Add(this._heloc);


                    Driven.DebugOut.dOut("Mort Month:  " + this._mortPaymentsAccrued.ToString());



                    //down line accrual
                    if (this.MortgageMonthsAccrued % this._downLineIncIntervalInMonths == 0)
                    {
                        Driven.DebugOut.dOut("OLD Amortized amount:  " + this._helocAmortizedPayment.ToString());

                        _downLineAccrualAmountAccumulator += _downLineAccrualAmount;
                        SetNewHelocAmortizedPayment();
                        //see about not having to fully qualify this:
                        Driven.DebugOut.dOut("DONE setting new amortized amount now...");
                        Driven.DebugOut.dOut("NEW Amortized amount:  " + this._helocAmortizedPayment.ToString());
                    }


                    //Let's see if the Heloc object still OWES anything
                    _heloc.CheckDebtStatus(_mortgage);                    
                }
                else //Otherwise, just make a regular mortgage payment...
                {
                    _mortgage.MakeMortgagePayment(this._monthlyMortPay);
                    _mortPaymentsAccrued++;
                    Driven.DebugOut.dOut("Mort Month:  " + this._mortPaymentsAccrued.ToString());



                    //Store the current information for the month in question
                    //  as the Mort Payments Accrued increments, this represents ONE month.
                    _mortgage._monthTag = _mortPaymentsAccrued;
                    _heloc._monthTag = _mortPaymentsAccrued;  //otherwise we won't get an even month
                    this._specificMortMonths.Add(this._mortgage);
                    this._specificHelocMonths.Add(this._heloc);




                    //down line accrual bonus
                    if (this.MortgageMonthsAccrued % this._downLineIncIntervalInMonths == 0)
                    {
                        Driven.DebugOut.dOut("OLD Amortized amount:  " + this._helocAmortizedPayment.ToString());

                        _downLineAccrualAmountAccumulator += _downLineAccrualAmount;
                        SetNewHelocAmortizedPayment();
                        //see about not having to fully qualify this:
                        Driven.DebugOut.dOut("DONE setting new amortized amount now...");
                        Driven.DebugOut.dOut("NEW Amortized amount:  " + this._helocAmortizedPayment.ToString());
                    }

                    //Let's see if the Heloc object still OWES anything
                    _heloc.CheckDebtStatus(_mortgage);
                 
                }                
            }
            else if(sender is Driven.Mortgage && !_timeToPayMortgageNow)//  Mortgage:  I OWE SOMETHING, BUT IT'S NOT TIME TO MAKE A PAYMENT YET
            {
                //Even though it's not time to make a payment....we still need to also check the Heloc
                //to see if IT owes something right now...
                _heloc.CheckDebtStatus(_mortgage);
            }

            if (sender is Driven.Heloc) //Heloc object says:  "I OWE SOMETHING"
            {
                //If Mortgage is paid-off, then we can use our discretionary income to make
                //a much BIGGER payment now...
                if (_mortgage._mortAmountOwed == 0.0)
                {
                    _heloc.MakeHelocPayment(this._helocAmortizedPayment + this._monthlyMortPay);                    
                }
                else  //otherwise, just make a regular payment (amortized payment)
                {
                    _heloc.MakeHelocPayment(this._helocAmortizedPayment);                    
                }
               

                //Another payment was made...
                _helocPaymentsAccrued++;    
           
                //We just made another amortized payment                
                _helocPaymentGradualAccrual += this._helocAmortizedPayment;


                //When our amortized payments are equal to or greater than our
                //Montly discretionary income...then we can make a mortgage payment
                //and the accumulator zeros-out
                if (_helocPaymentGradualAccrual >= _originalHelocMonthlyPaymentAmount)
                {
                    _timeToPayMortgageNow = true;
                    _helocPaymentGradualAccrual = 0.0;
                }
                else
                {
                    _timeToPayMortgageNow = false;
                }            
               
                //check to see if we can increase the amount of the Heloc (about every 18 months)
                _heloc.RenewHelocTotalAmountAvailableNoRestrictions(this.HelocMonthsAccrued, _mortgage);
                Driven.DebugOut.dOut("Heloc Month:  " + this.HelocMonthsAccrued.ToString());

                //Now that we're done with the Heloc processing...let's check on Mortgage to see if it is
                //still OWING something
                _mortgage.CheckDebtStatus(_heloc);                
               
            }            
        }
Later on......here is where I output the contents of the ArrayList  (this happens in the Windows Form)


        private void buttonShowSpecificMonths_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < de._specificMortMonths.Count; i++)
            {
                Driven.DebugOut.dOut("MORTGAGE");
                Driven.DebugOut.dOut("Month:  " + ((Driven.Mortgage)de._specificMortMonths[i])._monthTag.ToString());
                Driven.DebugOut.dOut("Balance:  " + ((Driven.Mortgage)de._specificMortMonths[i])._mortAmountOwed.ToString());
                Driven.DebugOut.dOut("Interest Accrued:  " + ((Driven.Mortgage)de._specificMortMonths[i])._interestAccrued.ToString());
            }

            for (int i = 0; i < de._specificHelocMonths.Count; i++)
            {
                Driven.DebugOut.dOut("HELOC");
                Driven.DebugOut.dOut("Month:  " + ((Driven.Heloc)de._specificHelocMonths[i])._monthTag.ToString());
                Driven.DebugOut.dOut("Balance:  " + ((Driven.Heloc)de._specificHelocMonths[i])._helocAmountOwed.ToString());
                //Driven.DebugOut.dOut("Interest Accrued:  " + ((Driven.Heloc)de._specificHelocMonths[i]).._interestAccrued.ToString());
            }

            MessageBox.Show("Done");

        }
Avatar of Bob Learned
Tom,

You have got to stop putting up all the code, it is just confusing.  We need to find a way to show just the pertinent code.

Normally, this occurs if you don't create a new object using the 'new' keyword, but reuse the same object.

Bob
ASKER CERTIFIED SOLUTION
Avatar of Gary Davis
Gary Davis
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Gary:

I think you are right....that must be what I am doing.....and looking at my code....that  IS what I am doing.

Perhaps I can delare a "temp" object of the same time, assign the "global" (internal) copy to it....and then add the "temp" object to the ArrayList?
This does not seem to help:


 //Store the current information for the month in question
                    //  as the Mort Payments Accrued increments, this represents ONE month.
                    Driven.Mortgage tempm;
                    tempm = _mortgage;
                    Driven.Heloc temph;
                    temph = _heloc;
                    tempm._monthTag = _mortPaymentsAccrued;
                    temph._monthTag = _mortPaymentsAccrued;
                    _mortgage._monthTag = _mortPaymentsAccrued;
                    _heloc._monthTag = _mortPaymentsAccrued;  //otherwise we won't get an even month
                    this._specificMortMonths.Add(tempm);
                    this._specificHelocMonths.Add(temph);
Bob:

I'm sorry...I'll stop posting my entire source and I'll just try and post the relevant code.

I guess I don't know what will be relevant.
This is a case of Too Much Information!!!  Plus, it scares a lot of people off.  Who wants to read through all that code?  Also, there is a significant amount of scrolling required.

Bob
This creates a reference pointer, not a clone:

    temph = _heloc;

Bob
> Perhaps I can delare a "temp" object of the same time, assign the "global" (internal) copy to
> it....and then add the "temp" object to the ArrayList?

Yes.

This example instantiates the object and has to be done at the appropriate time. Then you can add it to the ArrayList.

 _mortgage = new Mortgage(mortAmountOwed, mortInterestRate);

Gary
How would I change this code so that I create a seperate "clone" or distinct copy of the _mortgage object?

//Store the current information for the month in question
                    //  as the Mort Payments Accrued increments, this represents ONE month.
                    Driven.Mortgage tempm;
                    tempm = _mortgage;
                    Driven.Heloc temph;
                    temph = _heloc;
                    tempm._monthTag = _mortPaymentsAccrued;
                    temph._monthTag = _mortPaymentsAccrued;
                    _mortgage._monthTag = _mortPaymentsAccrued;
                    _heloc._monthTag = _mortPaymentsAccrued;  //otherwise we won't get an even month
                    this._specificMortMonths.Add(tempm);
                    this._specificHelocMonths.Add(temph);
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Please show me how the new code would look given your instructions:

1) Create a new object, and copy the values.

2) Implement ICloneable.

3) Add _heloc to the the ArrayList instead of a temporary copy.


Did you still want that information?

Bob
TheLearnedOne:

Did you still want that information?

===========

If it's not too much to ask....please.

I ended-up going a different route, for now....but it would still be nice to have your solution.
1) Create new and copy:

    Driven.Heloc temph = new Driven.Heloc();
    temph = _heloc._helocAmountOwed;

...

2) ICloneable:

    Base class for cloning an object in C#
    http://www.codeproject.com/csharp/cloneimpl_class.asp

    There are some who think that you should create your own Copy method, instead of implementing ICloneable.

3) this._specificHelocMonths.Add(_heloc);

Bob
The problem with #1 is that you have to explicitly specify properties, and if you add a property, then you could forget to add the property to the Clone method.

Bob
Thanks for posting your solution.