﻿/***** Absorption Rate Code *****/
/*****  absorptionRate.js   *****/

/** absorptionRate Object Declaration and Definitions **/
function absorptionRate(result, price, uid, miles, lowPrice, highPrice, lat, lng) {
    this.result = result;
    this.activeListings = result[0];
    this.soldListings = result[1];
    this.averageSold = result[2];
    this.absorpRate = result[3];
    this.avgCost = result[4];
    this.avgDays = result[5];
    this.activeListingsYearAgo = result[6];
    this.soldListingsYearAgo = result[7];
    this.avgSoldYearAgo = result[8];
    this.absorpRateYearAgo = result[9];
    this.avgCostYearAgo = result[10];
    this.avgDaysYearAgo = result[11];
    this.price = price;
    this.uid = uid;
    this.miles = miles;
    this.lowPrice = lowPrice;
    this.highPrice = highPrice;
    this.lat = lat;
    this.lng = lng;
}

absorptionRate.prototype = {
    // Returns the result array
    getResultArray: function() { return this.result; },
    
    // Returns the number of active listings 
    getActiveListings: function() { return this.activeListings; },
    
    // Returns the number of sold listings
    getSoldListings: function() { return this.soldListings; },
    
    // Returns the avg number of sales over last 3 months
    getAvgSales: function() { return this.averageSold; },
    
    // Returns the absorption rate
    getAbsorptionRate: function() { return this.absorpRate; },
    
    // Returns the avg cost of the sold properties
    getAvgCost: function() { return this.avgCost; },
    
    // Returns the avg days listings are on the market
    getAvgDays: function() { return this.avgDays; },
    
    // Returns the number active listings from one year ago
    getActiveListingsYearAgo: function() { return this.activeListingsYearAgo; },
    
    // Returns the number of sold listings from one year ago
    getSoldListingsYearAgo: function() { return this.soldListingsYearAgo; },
    
    // Returns the average number of sold listings per month from one year ago
    getAvgSalesYearAgo: function() { return this.avgSoldYearAgo; },
    
    // Returns the absorption rate from one year ago
    getAbsorptionRateYearAgo: function() { return this.absorpRateYearAgo; },
    
    // Returns the avg cost of the sold properties from one year ago
    getAvgCostYearAgo: function() { return this.avgCostYearAgo; },
    
    // Returns the avg days listings were on the market one year ago
    getAvgDaysYearAgo: function() { return this.avgDaysYearAgo; },
    
    // Returns the list price of the property
    getPrice: function() { return this.price; },
    
    // Returns the uid of the property
    getUID: function() { return this.uid; },
    
    // Sets the number of miles to include in the range for the absorption rate
    setMiles: function(miles) { this.miles = miles; },
    
    // Returns the number of miles used to calculate the absorption rate    
    getMiles: function() { return this.miles; },
    
    // Sets the price range to use when calculation the absorption rate
    setPriceRange: function(priceRange) { this.priceRange = priceRange; },
    
    // Returns the price range used to calculate the absorption rate
    getPriceRange: function() { return this.priceRange; },
    
    // Sets the low price of the absorption rate
    setLowPrice: function(lowPrice) { this.lowPrice = lowPrice; },
    
    // Returns the low price of the absorption rate
    getLowPrice: function() { return this.lowPrice; },
    
    // Sets the high price of the absorption rate
    setHighPrice: function(highPrice) { this.highPrice = highPrice; },
    
    // Returns the high price of the absorption rate
    getHighPrice: function() { return this.highPrice; },
    
    // Sets the lat and lng of the absorption rate
    setLatLng: function(lat, lng) {
        this.lat = lat;
        this.lng = lng;
    },
    
    // Returns the lat of the absorption rate
    getLat: function() { return this.lat; },
    
    // Returns the lng of the absorption rate
    getLng: function() { return this.lng; },
    
    // Returns the address of the property
    getPropInfo: function() {
        if (this.result.length >= 21)  {
            var street = this.result[15] + ' ' + this.result[16];
            var city = this.result[17];
            var zip = this.result[18];
            if (zip.length > 5) zip = zip.substring(0, 5);
            var price = 'Price: ' + formatCurrency(this.price);
            return street + "<br />" + city + ", TX " + zip + '<br />' + price; 
        }
        return 'no address found.'
    }
}
/** End absorptionRate Object Declaration and Definitions **/ 


/** Variables **/
var theAbsorptionRate = null; // Will be the absorptionRate object.

/* Constant Variables */
var DEFAULT_MILES = 1;
var MAX_MILEAGE = 5;
var LEFT_POS_ZERO = -2;
var LEFT_POS_ELEVEN = 385;
var IE_DIFFERENCE = 15;
var IE7_OFFSET = 16;
/* End Constant Variables */
/** End Variables **/

/** Functions **/
/**
 * Function calcAbsorpByUID(uid)
 * Sets byLatLng to false and calls the webservice to calculate the absorption rate based on the uid.
 * @param uid - The UID of the property the user was visiting.
 */
function calcAbsorpByUID(uid) { 
    openModalPopup();
    byLatLng = false;
    if ((theAbsorptionRate == null) || (theAbsorptionRate == 'undefined')) { // If this is the first time to calculate the absorption rate.
        wsListing.calcAbsorptionRateByUID(uid, DEFAULT_MILES, -1, -1, showAbsorptionRate, failureToCalcAbsorptionRate)
    } else if (theAbsorptionRate.getUID() == uid) { // If the absorption rate already exists for this property, recalculate it with new data.
        wsListing.calcAbsorptionRateByUID(uid, theAbsorptionRate.getMiles(), theAbsorptionRate.getLowPrice(), theAbsorptionRate.getHighPrice(), showAbsorptionRate, failureToCalcAbsorptionRate)
    }
}

/**
 * Function calcAbsorptionRateByLatLng(lat, lng)
 * Sets byLatLng to true and calls the webservice to calculate the absorption rate based on a given latitude and longitude.
 * @param lat - The latitude to be used for the absorption rate calculation.
 * @param lng - The longitude to be used for the absorption rate calculation.
 */
function calcAbsorptionRateByLatLng(lat, lng) {
    openModalPopup();
    byLatLng = true;
    if ((theAbsorptionRate == null) || (theAbsorptionRate == 'undefined')) { // If this is the first time to calculate the absorption rate.
        wsListing.calcAbsorptionRate(DEFAULT_MILES, -1, -1, lat, lng, showAbsorptionRate, failureToCalcAbsorptionRate);
    } else { // If the absorption rate already exisits for this property, recalculate it with the new data.
        wsListing.calcAbsorptionRate(theAbsorptionRate.getMiles(), theAbsorptionRate.getLowPrice(), theAbsorptionRate.getHighPrice(), lat, lng, showAbsorptionRate, failureToCalcAbsorptionRate);
    }
}

/**
 * Function mileChanged(miles)
 * Called when a user selects a mileage on the absorption rate popup.
 * Will call wsListing.absorptionRate to calculate the absorption rate of the selected property based on the selected mileage and price range.
 */
function mileChanged() {
    openModalPopup();
    setMarkIntMiles(absorpMilesDDL.options[absorpMilesDDL.selectedIndex].value);
    if ((theAbsorptionRate == null) || (theAbsorptionRate == 'undefined')) { // If the absorption rate does not exist, call the webservice with default parameters - Should never occur.
        if (byLatLng) {
            wsListing.calcAbsorptionRate(absorpMilesDDL.options[absorpMilesDDL.selectedIndex].value, -1, -1, getMapLat(), getMapLng(), showAbsorptionRate, failureToCalcAbsorptionRate);
        } else {
            wsListing.calcAbsorptionRateByUID(uid, absorpMilesDDL.options[absorpMilesDDL.selectedIndex].value, -1, -1, showAbsorptionRate, failrueToCalcAbsorptionRate)
        }
    } else { // If the absorption rate does exist, update it's mileage radius and call functions to recalculate it.
        theAbsorptionRate.setMiles(absorpMilesDDL.options[absorpMilesDDL.selectedIndex].value);
        if (byLatLng) {
            calcAbsorptionRateByLatLng(theAbsorptionRate.getLat(), theAbsorptionRate.getLng()); 
        } else { 
            calcAbsorpByUID(theAbsorptionRate.getUID()); 
        }
    }   
    return false;
}

/**
 * Function priceRangeChanged(priceRange)
 * Called when a user selects a priceRange on the absorption rate popup.
 * Will call wsListing.absorptionRate to calculate the absorptoin rate of the selected property based on the selected mileage and price range.
 */
function priceChanged() {
    if (ddlPriceMin.options[ddlPriceMin.selectedIndex].value < ddlPriceMax.options[ddlPriceMax.selectedIndex].value) { // Only update page when min < max
        openModalPopup();
        if ((theAbsorptionRate == null) || (theAbsorptionRate == 'undefined')) { // If the absorptrion rate does not exist, call the webservice with default parameters - Should never occur.
            if (byLatLng) {
                wsListing.calcAbsorptionRate(DEFAULT_MILES, ddlPriceMin.options[ddlPriceMin.selectedIndex].value, ddlPriceMax.options[ddlPriceMax.selectedIndex].value, getMapLat(), getMapLng(), showAbsorptionRate, failureToCalcAbsorptionRate);
            } else {
                wsListing.calcAbsorptionRateByUID(uid, DEFAULT_MILES, ddlPriceMin.options[ddlPriceMin.selectedIndex].value, ddlPriceMax.options[ddlPriceMax.selectedIndex].value, showAbsorptionRate, failrueToCalcAbsorptionRate)
            }
        } else { // If the absorption rate does exist, update the prices and call functions to recalculate it
            theAbsorptionRate.setLowPrice(ddlPriceMin.options[ddlPriceMin.selectedIndex].value);
            theAbsorptionRate.setHighPrice(ddlPriceMax.options[ddlPriceMax.selectedIndex].value);
            if (byLatLng) {
                calcAbsorptionRateByLatLng(theAbsorptionRate.getLat(), theAbsorptionRate.getLng()); 
            } else {
                calcAbsorptionRateByUID(theAbsorptionRate.getUID()); 
            }
        }   
    }
    return false;
}

/**
 * Function showAbsorptionRate(result)
 * Called upon successfull competion of the webservices to calculate the absorption rate.
 * Will load all data returned and display it to the user.  Does the majority of all display/hide info to the user.
 * @param result - the array of absorption rate data returned from the webservice.
 */
function showAbsorptionRate(result) {
    openModalPopup();
    loading();
    absorpPnl.style.display = 'block';
    
    // When data has been successfully returned
    if (result != null) { 
        // Create or update the absorption rate object
        createAbsorptionRate(result);
        
        // Update the map and show/hide property info if we are getting data based on a uid
        if (!byLatLng) { // If the result is determined by a property's UID
            var latLng = new Array(theAbsorptionRate.getLat(), theAbsorptionRate.getLng());
            latLngUpdated(latLng);
            showPropInfo();
        } else {
            var latLng = new Array(theAbsorptionRate.getLat(), theAbsorptionRate.getLng());
            latLngUpdated(latLng);
            hidePropInfo();
        }
                
        // When an absorption rate has been calculated
        if (theAbsorptionRate.getAbsorptionRate() != -2) { 
            // Set the data for the chart/graph
            absorpActiveLbl.innerHTML = "Current active listings: " + theAbsorptionRate.getActiveListings();
            absorpSoldLbl.innerHTML =  "Avg homes off market per month: " + theAbsorptionRate.getAvgSales();
            if (theAbsorptionRate.getAbsorptionRate() > 11) absorpRateLbl.innerHTML = "= Absorption Rate: " + 11 + "+ months";
            else absorpRateLbl.innerHTML = "= " + theAbsorptionRate.getAbsorptionRate() + " month absorption rate"; 
            
            // Set the location of the marker on the graph
            setMarker();
            
            // Set the data for the current averages
            currentAbsorpInfo.innerHTML = "Average price of sold properties: " + formatCurrency(theAbsorptionRate.getAvgCost());
            currentAbsorpInfo.innerHTML += "<br />Average number of days properties have been on the market: " + theAbsorptionRate.getAvgDays();
            
            // Set the data for the one year ago content
            if (theAbsorptionRate.getAbsorptionRateYearAgo() == -2) { 
                // do nothing 
            } else {
                yearAgoAbsorpInfo.innerHTML = "Absorption Rate: ";
                if (theAbsorptionRate.getAbsorptionRateYearAgo() > 11) yearAgoAbsorpInfo.innerHTML += 11 + "+ months";
                else yearAgoAbsorpInfo.innerHTML += theAbsorptionRate.getAbsorptionRateYearAgo() + " months";
                yearAgoAbsorpInfo.innerHTML += "<br />Active listings 1 year ago: " + theAbsorptionRate.getActiveListingsYearAgo();
                yearAgoAbsorpInfo.innerHTML += "<br />Average price of sold properties 1 year ago: " + formatCurrency(theAbsorptionRate.getAvgCostYearAgo());
                yearAgoAbsorpInfo.innerHTML += "<br />Average number of days properties have been on the market: " + theAbsorptionRate.getAvgDaysYearAgo();
            }
            
            // Display the data
            absorpDiv.style.display = 'block'; 
            absorpInfoDiv.style.display = 'block';
            absorpTable.style.display = 'inline';
            
            if (theAbsorptionRate.getAvgSales() <= 4) { // When there have been 4 or fewer sales in the given mileage and price range
                showInfoMsg();
            }
        } else if (theAbsorptionRate.getAbsorptionRate() == -2) { // When there have been no sales in the given mileage and price range
            absorpDiv.style.display = 'none';
            absorpInfoDiv.style.display = 'none';
            noLoadLbl.style.display = 'block';
        } 
    }
    closeModalPopup();
}

/**
 * Function failureToCalcAbsorptionRate()
 * Called when wsListing.absorptionRate does not successfully return data.
 * Will deisplay the unable to load data message.
 */
function failureToCalcAbsorptionRate() {
    absorpDiv.style.display = 'none';
    absorpInfoDiv.style.display = 'none';
    noLoadLbl.style.display = 'block';
    closeModalPopup();
}

/** 
 * Function loading()
 * A helper method called by mileChanged and priceRangeChanged to display the loading img and hide everything else.
 */
function loading() {
    noLoadLbl.style.display = 'none';
    absorpInfoLbl.style.display = 'none';
}

/** 
 * Function showPropInfo() 
 * Displays the propertyInfo div and calls theAbsorptionRate.getPropInfo() to display all information about the property the user was viewing.
 */
function showPropInfo() {
    propertyInfoDiv.style.display = 'block';
    propDetailsDiv.innerHTML = theAbsorptionRate.getPropInfo();
}

/**
 * Function hidePropInfo()
 * Hides the propertyInfo div and removes all informtion from the propDetails div.
 */
function hidePropInfo() {
    propertyInfoDiv.style.display = 'none';
    propDetailsDiv.innerHTML = ' ';
}

/**
 * Function createAbsorptionRate(result)
 * If an absorptionRate object already exists, it will create a temp absorptionRate rate object with the new result, and exisiting miles and price range
 * and then set theAbsorptionRate = tmp.  Else it will create a new absorptionRate as theAbsorptionRate.
 * @param result - An array returned by the webservice with the active listings, sold listings, absorption rate and property uid.
 */
function createAbsorptionRate(result) {
    if ((theAbsorptionRate != null) && (theAbsorptionRate != 'undefined')) { // If the absorption rate does exist 
        theAbsorptionRate.setLowPrice(ddlPriceMin.options[ddlPriceMin.selectedIndex].value);
        theAbsorptionRate.setHighPrice(ddlPriceMax.options[ddlPriceMax.selectedIndex].value);
        if (byLatLng) { // If we are calculating it by lat and lng
            var tmp = new absorptionRate(result, false, false, theAbsorptionRate.getMiles(), theAbsorptionRate.getLowPrice(), theAbsorptionRate.getHighPrice(), result[13], result[14]);
            theAbsorptionRate = tmp;
        } else { // If we are calculating it by UID
            var tmp = new absorptionRate(result, result[12], result[20], result[19], theAbsorptionRate.getLowPrice(), theAbsorptionRate.getHighPrice(), result[13], result[14]);
            theAbsorptionRate = tmp;
        }
    } else if (byLatLng) { // If it does not exist and calculating by lat and lng
        theAbsorptionRate = new absorptionRate(result, false, false, result[12], ddlPriceMin.options[ddlPriceMin.selectedIndex].value, ddlPriceMax.options[ddlPriceMax.selectedIndex].value, result[13], result[14]);
    } else if (!byLatLng) { // If it does not exist and calculating by UID
        theAbsorptionRate = new absorptionRate(result, result[12], result[20], result[19], ddlPriceMin.options[ddlPriceMin.selectedIndex].value, ddlPriceMax.options[ddlPriceMax.selectedIndex].value, result[13], result[14]);
    }
}

/**
 * Function showInfoMsg()
 * A helper method used to set the text of absorpInfoLbl depending on the user selections of mileage and price range.  Will then display the text.
 */
function showInfoMsg() {
    if (theAbsorptionRate.getMiles() < MAX_MILEAGE) { // If  mileage can be increased
        absorpInfoLbl.innerHTML = '*Not enough sales in this area to determine a meaningful statistic,<br />please try increasing the mileage.';
    } else {
        absorpInfoLbl.innerHTML = '*Not enough sales in this area to determine a meaningful statistic.';
    }
    absorpInfoLbl.style.display = 'block';
}

/**
 * Function setMarker()
 * A helper method to set the number of pixels the left style attribute of absorpMarker to display the marker on the graph.
 * Check if user is in IE7, if so add an offset of 6px;
 */
function setMarker() {
    var left = 0;
    if ((theAbsorptionRate.getAbsorptionRate() >= 0) && (theAbsorptionRate.getAbsorptionRate() <= 11)) { // If the rate is between 0 and 11
        var pxPerMonth = (LEFT_POS_ELEVEN - LEFT_POS_ZERO) / 11;
        var pxToMove = theAbsorptionRate.getAbsorptionRate() * pxPerMonth;
        left = LEFT_POS_ZERO + pxToMove;
    } else if (theAbsorptionRate.getAbsorptionRate() > 11) { // If the rate is greater than 11, plot the marker at 11
        left = LEFT_POS_ELEVEN;
    } else { // If the rate is less than 0, show 0 on the graph
        left = LEFT_POS_ZERO;
    }       
    
    // Determine if using IE 7 - If using IE7, offset pixels by IE7_OFFSET
    var browser = navigator.userAgent.toLowerCase();
    var index = browser.indexOf('msie');
    if (index > 0) { 
        left -= IE_DIFFERENCE;
        index += 5;
        var version = browser.substring(index, index + 3);
        if (version == '7.0') left += IE7_OFFSET; 
    } 
    
    absorpMarker.style.left = left + 'px';
}

/** 
 * Function formatCurrency(num)
 * Formats the given number to currency without decimals.
 * @param num - The value to be formatted.
 */
function formatCurrency(num) {
    num = num.toString().replace(/\$|\,/g,'');
    if(isNaN(num)) num = "0";
    sign = (num == (num = Math.abs(num)));
    num = Math.floor(num*100+0.50000000001);
    num = Math.floor(num/100).toString();
    for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
    num = num.substring(0,num.length-(4*i+3))+','+
    num.substring(num.length-(4*i+3));
    return (((sign)?'':'-') + '$' + num);
}
/** End Functions **/