var ModelListModule = Class.create({

    /**
     * initialize()
     * @param makeList Comma delimited string of makes
     */
    initialize: function() {
        this.currentlyHovered = null;
        this.wantToShow = null;
        this.filtersModal = 'filters-modal';
        this.addressModal = 'address-modal';
        this.modalOverlay = 'modal-overlay';
        this.filtersList = new Array();

        var modelBrowser = $('model-browser');

        /* Attach the event listeners */
        $('make-change').observe('click', this.changeFiltersHandler.bindAsEventListener(this));
        $('rss').observe('click', this.rssDialogHandler.bindAsEventListener(this));
        modelBrowser.observe('click', this.modelBrowserClickHandler.bindAsEventListener(this));
        modelBrowser.observe('mouseover', this.nowAvailableHoverHandler.bindAsEventListener(this));
        document.observe('mouseout', this.nowAvailableHoverOutHandler.bindAsEventListener(this));

        this.adjustNowAvailable();

        var zipCookie = this.zipCheckForCookie();
        if (zipCookie) {
            $('address-zip').value = zipCookie;
        }

    },

    adjustNowAvailable: function() {
        var csDimensions = $('coming-soon').getDimensions();
        var naDimensions = $('now-available').getDimensions();
        if (csDimensions.height > naDimensions.height) {
            $('released').setStyle({height: (csDimensions.height - 30) + 'px'});
        }
    },

    showChangeMakeGraphic: function() {
        var floaterTitle = 'These vehicles are sorted by make. Change your options below to see others.';
        var floater = new Element('div', {id: 'change-make-floater', title: floaterTitle}).setOpacity(0.0);
        $('make-change').insert({after: floater});
        floater.clonePosition($('make-change'), {setWidth: false, setHeight: false});
        var t = setTimeout('new Effect.Appear($("change-make-floater"), { duration: 0.4, from: 0.0, to: 1.0 })', 1000);
        var u = setTimeout('new Effect.Fade($("change-make-floater"), {duration: 0.4, from: 1.0, to: 0.0})', 4500);

    },

    /**
     * changeFiltersHandler()
     * Presents the user with the list of makes available to filter on.
     * @param e The click event from the user clicking the change link
     */
    changeFiltersHandler: function(e) {
        e.stop();
        this.createModalOverlay();
        var filtersContent = $(this.filtersModal).remove();
        filtersContent.clonePosition($('currently-viewing'), {setWidth: false, setHeight: false, setLeft: false}).setStyle({left: '140px'});
        $(this.modalOverlay).insert({after: filtersContent});
        $('page-container').setStyle({position:"relative"});
        new Effect.Appear(this.modalOverlay, { duration: 0.4, from: 0.0, to: 0.8 });
        new Effect.Appear(this.filtersModal, { duration: 0.4, from: 0.0, to: 1.0 });
        this.filtersReset();
        this.addFiltersModalEvents();
    },

    createModalOverlay: function() {
        var myHeight = $$('body').reduce().getHeight();
        if (myHeight < document.viewport.getHeight()) {
            myHeight = document.viewport.getHeight();
        }
        var overlay = new Element('div', {id: this.modalOverlay}).setOpacity(0.0).setStyle({height: myHeight + "px"});
        $('page-container').insert(overlay);
    },

    filtersReset: function() {
        this.filtersList = [];
        this.filtersGetSelected();
        //this.filtersPushSelected();
        this.filtersCheckSelected();
        this.createFilterMakesText();
    },

    filtersGetSelected: function() {
        var params = window.location.href.split('?')[1];
        params = (params != null) ? params.split('&') : [];
        var paramsLength = params.length;
        for (var i = 0; i < paramsLength; ++i) {
            var thisParam = params[i];
            var param = thisParam.split('=');
            if (thisParam.include('make1')) {
                this.filtersList[0] = unescape(param[1]);
            }
            if (thisParam.include('make2')) {
                this.filtersList[1] = unescape(param[1]);
            }
            if (thisParam.include('make3')) {
                this.filtersList[2] = unescape(param[1]);
            }
        }
    },

    filtersCheckSelected: function() {
        var inputBoxes = $$('#' + this.filtersModal + ' input');
        var inputBoxesLength = inputBoxes.length;
        var filtersLength = this.filtersList.length;
        var thisInput;

        for (var i = 0; i < inputBoxesLength; ++i) {
            thisInput = inputBoxes[i];
            thisInput.checked = false;
        }
        for (var i = 0; i < inputBoxesLength; ++i) {
            thisInput = inputBoxes[i];
            for (var j = 0; j < filtersLength; ++j) {
                if (thisInput.value == this.filtersList[j]) {
                    thisInput.checked = true;
                }
            }
        }
    },

    addFiltersModalEvents: function() {
        $(this.filtersModal).observe('click', function(e) {
            var el = e.element();
            var filtersError = $('filters-error');

            if (el.type == 'checkbox') {
                var numFilters = this.filtersList.length;
                if ((numFilters == 3) && el.checked) {
                    el.checked = false;
                    filtersError.setStyle({display: 'block'});
                } else if ((numFilters < 3) && el.checked) {
                    this.filtersList.push(el.id);
                    this.createFilterMakesText();
                } else if (!el.checked) {
                    this.filtersList = this.filtersList.without(el.id);
                    this.createFilterMakesText();
                    filtersError.setStyle({display: 'none'});
                }
            }
            if ((el.className == 'button cancel') || (el.id == 'filters-cancel')) {
                e.stop();
                this.removeModal(this.filtersModal);
            }
            if ((el.className == 'button ok') || (el.id == 'filters-ok')) {
                if (this.filtersList.length) {
                    this.createFiltersModalUrl();
                } else {
                    e.stop();
                    this.removeModal(this.filtersModal);
                }
            }
        }.bindAsEventListener(this));
    },

    createFiltersModalUrl: function() {
        var makes = this.filtersList;
        var makesLength = this.filtersList.length;
        var url = '';
        //E3 event needs make= for 1st make
        url='&make='+makes[0];
        for (var i = 0; i < makesLength; i++) {
            var thisMake = makes[i];
            url += '&make' + [i + 1] + '=' + thisMake;
        }
        var filterOk = $('filters-ok');
        filterOk.href = filterOk.href + url + '&filter=USER';
    },

    createFilterMakesText: function() {
        var makesId = $('filters-makes');
        var makes = this.filtersList;
        var makesLength = this.filtersList.length;
        var text = 'Selected Makes:';
        for (var i = 0; i < makesLength; i++) {
            if ((i > 0) && (makesLength > 1)) {
                text += ' and';
            }
            text += ' <strong>' + makes[i] + '</strong>';
        }
        if ((makesLength > 0) && (makesLength < 3)) {
            var makesLeft = (3 - makesLength);
            text += ' (select ' + makesLeft + ' more)';
        }
        makesId.setStyle({display: 'block'});
        makesId.update(text);
    },

    addressHandler: function(element, address) {
        this.createModalOverlay();
        var addressContent = $(this.addressModal).remove();
        $(this.modalOverlay).insert({after: addressContent});
        var position = Position.cumulativeOffset($(element));
        var leftOffsetAmount = ($(element).up('span.fyc')) ? "150" : ""; // DEF_30542
        var addressDims = addressContent.getDimensions();
        addressContent.setStyle({left: (position.left - leftOffsetAmount) + 'px', top: ((position.top - addressDims.height) + 20) + 'px'});
        new Effect.Appear(this.modalOverlay, { duration: 0.4, from: 0.0, to: 0.8 });
        var zipCookie = this.zipCheckForCookie();
        if (zipCookie) {
            $('address-zip').value = zipCookie;
        }
        this.updateAddressContent(element, address);
        this.addAddressModalEvents();
        new Effect.Appear(this.addressModal, { duration: 0.4, from: 0.0, to: 1.0, afterFinish: this.setAddressFocus });
    },

    updateAddressContent: function(element, address) {
        if (address == 'address') {
            $('address-search').href = $(element).href;
            $('address-message').update('Please enter your ZIP code to see if this vehicle is available in your area.');
            $('label-zip').show();
            $('address-zip').show();
            $('address-search').show();
            $('address-cancel').show();
            $('address-ok').hide();
        } else {
            $('address-message').update('Unfortunately, there is currently no additional information available for this vehicle. Please check back soon.');
            $('address-ok').show();
            $('label-zip').hide();
            $('address-zip').hide();
            $('address-cancel').hide();
            $('address-search').hide();
        }
    },

    addAddressModalEvents: function() {
        $(this.addressModal).observe('click', function(e) {
            var el = e.element();

            if ((el.className == 'button search') || (el.id == 'address-search')) {
                e.stop();
                this.zipProcess();
            }
            if ((el.className == 'button cancel') || (el.id == 'address-cancel') || (el.className == 'button ok') || (el.id == 'address-ok')) {
                e.stop();
                $('address-error').hide();
                this.removeModal(this.addressModal);
            }
        }.bindAsEventListener(this));

        $(this.addressModal).down('form').observe('submit', function(e) {
            var el = e.element();
            e.stop();
            this.zipProcess();
        }.bindAsEventListener(this));
    },

    setAddressFocus: function() {
        var thisInput = $('address-zip');
        if (thisInput.style.display == 'none') {
            return;
        }
        thisInput.focus();
    },

    zipCheckForCookie: function() {
        var c = document.cookie.split(';');
        var cLength = c.length;
        var cName = 'USER';
        for (var i = 0; i < cLength; i++) {
            var thisC = c[i];
            if (thisC.include(cName)) {
                return this.zipGetFromCookie(thisC);
            }
        }
        return null;
    },

    zipGetFromCookie: function(cookie) {
        var c = cookie.split('=');
        var cValue = unescape(c[1]).split('=')[1];
        return cValue;
    },

    zipProcess: function() {
        var zip = $F('address-zip');
        var zipLength = zip.length;
        if ((zip == undefined) || (zip == '') || (zipLength < 5)) {
            $('address-error').show();
        }

        this.zipValidateWithMarket(zip);
    },

    zipValidateFormat: function(zip) {
        var zipRegex = /^\d{5}$/;
        return zipRegex.test(zip);
    },

    zipValidateWithMarket: function (zip) {
        if (zip == null) {
            return;
        }
        var url = "/ac-servlets/research/compare/ctr/validateZipAgainstMarket?zip=" + zip + "&callingFunction=zipValidator";
        var options = {method: "get", onSuccess: this.zipEvaluateStatus};
        new Ajax.Request(url, options);
    },

    zipEvaluateStatus: function(data) {
        // Verify parameters.
        if (data == null) {
            return;
        }
        var result = data.responseText.evalJSON();
        var zip = result.zip;
        if (zip == '') {
            $('address-error').show();
            return;
        }
        document.cookie = 'USER=' + 'zip=' + zip + '; path=/';
        var distance = '&distance=25';
        var urlZip = '&address=' + zip;
        window.location = $('address-search').href + distance + urlZip;
    },

    removeModal: function(modalId) {
        new Effect.Fade(this.modalOverlay, {duration: 0.4, from: 0.8, to: 0.0});
        new Effect.Fade(modalId, {duration: 0.4, from: 1.0, to: 0.0});
        $(modalId).stopObserving('click');
        if ($(this.modalOverlay)) {
            $(this.modalOverlay).remove();
        }
    },

    /**
     * rssDialogHandler()
     * Presents the user with the dialog containing the RSS url
     * @param e The click event from the user clicking the change link
     */
    rssDialogHandler: function(e) {
        e.stop();
        var el = e.element();

        var containing = new Element("div", {id: 'rss-box'});
        var text = new Element("p").update("Enter the following URL into your RSS feed reader to subscribe to the AutoTrader.com New Model Showcase.");
        var url = new Element("input", {type: 'text', value: el.href});
        containing.insert({top: text}).insert({bottom: url});
        var dialog = new DialogBox(320, 120, containing);
        $('lightBox-close').down('.lightBox-closebutton').setStyle({background: 'transparent url(/img/btn/btn_ok_40x21.gif) no-repeat scroll left top'});
    },

    /**
     * modelBrowserClickHandler()
     * Handles all clicks that occur within div#model-browser
     */
    modelBrowserClickHandler: function(e) {
        var el = e.element();

        if (el.hasClassName('close-x')) {
            /* Hide the hover box on featured models */
            e.stop();
            this.hideElement();
        }
        if (el.className == 'inventory-yes') {
            e.stop();
            this.addressHandler(el.id, 'address');
        }
        if (el.className == 'inventory-no') {
            e.stop();
            this.addressHandler(el.id, 'none');
        }
        if (el.hasClassName('hover-oem-link')) {
            /* BILogUtil and throwAsis were not playing nicely, now they are */
            e.stop();
            var biArray = el.down('.oemmis').title.split(',');
            BILogUtil.Redirector(el.href, biArray, true, ['width=1000', 'height=560', 'resizable=yes', 'menubar=yes', 'titlebar=yes', 'toolbar=yes']).send();
        }
        if(el.hasClassName('clickThruURL')) {
            var asisSrc = el.previous('span.clickThruURL').title;
            if (asisSrc && typeof asisSrc == 'string') {
                var asis = new Image();
                asis.src = asisSrc;
            }
        }


    },

    /**
     * nowAvailableHover()
     * Displays the hover box for the now available models
     */
    nowAvailableHover: function(el) {
        /* clear the timer that got us here */
        this.clearEventTimer();
        if (this.currentlyHovered != null) {
            this.hideElement();
        }
        if (el.down()) {
            this.currentlyHovered = el.down();
            this.currentlyHovered.clonePosition(el.up(),{setWidth: false, setHeight: false, offsetLeft: -2, offsetTop: -2});
            /* this is ugly but IE6 seems to have issues using throwAsis with the timeout - some tags were not being logged */
            var url = encodeURI(el.down('div.hoverasis').getAttribute("title"));
            new Effect.Appear(this.currentlyHovered, {duration: 0.4, from: 0.0, to: 1.0});
            //ASIS MUST BE BELOW THIS LINE FOR IE6
            //DEF 23955 - improper cacheKill / redundant code.
            this.throwAsis(url);
        }
    },

    /**
     * nowAvailableHoverHandler()
     * Handles hover events on div#now-available
     */
    nowAvailableHoverHandler: function(e) {
        var el = e.element();
        /* Do we even care about this mouse over? */
        if (el.hasClassName('featured-overlay')) {
            /* Yes, Are we still over the same element? */
            if (el == this.wantToShow) {
                /* Yes, we can show the element */
                this.nowAvailableHover(el);
                return true;
            }

            if (this.wantToShow != null) {
                /* We are over a featured element, but its not the one to be shown, so we need to clear the timeout */
                this.clearEventTimer();
            }

            /* No, we cannot show the element-it needs to be queued to be shown after the delay */
            this.setEventTimer(e, 0.6);


        } else if (el.hasClassName('hover-state') || el.up("div").hasClassName('hover-state')) {
            /* We're over a hover state, nothing to see here */
            return true;
        } else {
            /* No, but we need to see if it came from one we do care about and cancel that one */
            var relatedTarget = (e.relatedTarget) ? e.relatedTarget : e.fromElement;
            Element.extend(relatedTarget);
            if (relatedTarget == this.wantToShow) {
                this.clearEventTimer();
            }
            /* we're not over a hover state, or feature, so hide anything that's shown */
            if (this.currentlyHovered) {
                this.hideElement();
            }
        }
    },

    /**
     * setEventTimer()
     * Sets up a delay timer for mouseover effects
     * @param e The event object to be passed to the timeout function
     * @param delay The time (seconds) to delay before sending the event through again
     */
    setEventTimer: function(e, delay) {
        this.wantToShow = e.element();
        var nowAvailableHoverHandler = this.nowAvailableHoverHandler.bind(this, e);
        this._t = window.setTimeout(nowAvailableHoverHandler, (delay * 1000));
    },

    /**
     * clearEventTimer()
     * Handles the situation when a user has moused over then out of an element before the allotted
     * timeframe to pop up a dialog has expired. This will clear that function from running.
     */
    clearEventTimer: function() {
        this.wantToShow = null;
        window.clearTimeout(this._t);
    },

    /**
     * hideElement()
     * Hides the this.currentlyHovered element
     */
    hideElement: function() {
        new Effect.Fade(this.currentlyHovered, {duration: 0.3, from: 1.0, to: 0.0});
        this.currentlyHovered = null;
    },

    /**
     * nowAvailableHoverOutHandler()
     * Handles hover events on div#now-available
     */
    nowAvailableHoverOutHandler: function(e) {
        var el = e.element();
        /* Do we even care about this mouse out? */
        if (el.hasClassName('hover-state')) {
            /* Is there a timer currently in progress? */
            if (this.wantToShow != null) {
                /* Yes, defer to the mouseover handler */
                return false;
            } else {
                /* No, but we also need to know if we moused over a child */
                var relatedTarget = (e.relatedTarget) ? e.relatedTarget : e.toElement;
                Element.extend(relatedTarget);
                if (typeof relatedTarget.up("div") != "undefined") {
                    if (relatedTarget.up("div").hasClassName('hover-state')) {
                        /* We moused over a child of the hover state, we don't need to do anything here */
                        return false;
                    } else {
                        /* No, we need to do the hiding */
                        this.hideElement();
                    }
                } else {
                    /* We've hit the document root, hide the element */
                    this.hideElement();
                }
            }
        }
    },

    getRandomNumber: function(url) {
        return new Date().getTime();
    },

    /**
     * throwAsis()
     * Request an asis tag without affecting the page
     */
    throwAsis: function(url) {
        if (!url) {
            return;
        }
        url = encodeURI(url);
        var seperator = (url.indexOf("?") != -1) ? "&" : "?";
        var img = new Image();
        img.src = url + seperator + "cacheKill=" + this.getRandomNumber()
    },


    /**
     * throwOemAsis()
     * Request an oem provided asis ktag without affecting the page
     */
    throwOemAsis: function(url) {
        var asisTag = url;
        if (asisTag != '') {
            asisTag += 'ord=' + this.getRandomNumber();
            this.throwAsis(asisTag);
        }
    }

});
