/**
 * $Id: browse-cars.js,v 1.0 2008/4/29 17:33:07 jnapier Exp $
 *
 * This file holds all "browse-cars" specific functionality, whether
 * new features or modified pre-existing functions.
 * 
 * @note This file is dependent on prototype and DWR
 */

/* Container for "Browse Cars" specific functionality */
var BrowseCars =
{
    /**
     * Add listeners to observe both the zip form and the zip input itself.
     * On the page load, if the input has a value, try to validate it. On the
     * input keyup, if the value is an invalid zip code, set the background
     * color to a light red. On the form submit, if the zip input value is
     * an invalid zip code, alert the user and cancel the request.
     *
     * @returns BrowseCars (object)
     */
    attachFormListeners : function ()
    {
        Event.observe(window, "load", function ()
        {
            if ($("zip").value != "")
                BrowseCars.Validator.validateZip($("zip").value);
            Event.observe("zip", "keyup", function ()
            {
                BrowseCars.Validator.validateZip($("zip").value);
            });
            Event.observe("zip-search", "submit", function (e)
            {
                Event.stop(e);
                if (BrowseCars.Validator.Zip.isValid())
                    BrowseCars.Rewrite("zip-search").execute();
            });
        });
        return this;
    },

    /**
     * Extrapolate all form fields, match them against a syntax expression, and forward the
     * user to the rewritten URL. This function is specifically for the zip forms on browse
     * cars, to prevent sending the user to a page like "index.jsp?location=30223&condition=new"
     *
     * @example BrowseCars.Rewrite(0).execute()
     *
     * @note This function will most oftenly be called statically. The argument accepted should
     *       equivicate to the captured form's index, rather than identifier or name.
     *
     * @param formIndex (int)
     *
     * @returns BrowseCars.Rewrite (object)
     */
    Rewrite : function ()
    {
        var args = new Array(),
            i,
            object;

        /* Object container to be returned */
        object =
        {
            /**
             * String representation of desired syntax match. Keywords should
             * exist inside brackets "[]" and always be plain text. All
             * characters NOT contained in brackets will be literally translated
             * over into the returned string.
             */
            syntax : "/find/[condition-][make-][model-]cars-for-sale[-city][-location].jsp",

            /* Array comprised of all form elements */
            params : new Array (),

            /* Rewritten URL */
            url : null,

            /**
             * Prepare object for execution
             *
             * @param Arguments inherited from Rewrite()
             *
             * @note This function should not be explicitly called. Rather, any
             * arguments that need to be passed through __constructor should be
             * directly referenced via the "Rewrite" call.
             *
             * @returns BrowseCars.Rewrite (object)
             */
            __constructor : function ()
            {
                var formIndex, i, items;

                if ((formIndex = arguments[0]) !== false && document.forms[formIndex] && document.forms[formIndex].length > 0)
                    for (i=0; i<(items = document.forms[formIndex].elements).length; i++)
                        this.params.push({key : items[i].name, value : items[i].value});

                return this;
            },

            /**
             * Create mod_rewrite compatible URL based on syntax and match and return
             * the built string.
             *
             * @returns Url (string)
             */
            buildUrl : function ()
            {
                var i,
                    regexp,
                    syntax = this.syntax,
                    value;

                for (i=0; i<this.params.length; i++)
                {
                    value = this.params[i].value
                            .replace(/^\s*/, "").replace(/\s*$/, "")
                            .replace(/-/g, "_")
                            .replace(/\s+/g, "+")
                            .replace(/\&/g, "and");
                    regexp = new RegExp("\\[(-?)"+this.params[i].key+"(-?)\\]", "gi");
                    syntax = syntax.replace(regexp, "$1"+value+"$2");
                }

                return (this.url = syntax.replace(/\[-?[a-zA-Z0-9\]]+-?\]/gi, ""));
            },

            /**
             * Build URL, relocate user to desired page and cancel form request
             *
             * @returns Boolean (false)
             */
            execute : function ()
            {
                this.buildUrl();
                window.top.location.href = this.url;
                return false;
            }
        };

        /* Consolidate all arguments into an array */
        for (i=0; i<arguments.length; i++)
            args.push(arguments[i]);

        /* Return the prepared object */
        return object.__constructor(args.join(", "));
    },

    /* Parent container for form input validation */
    Validator :
    {
        /* Zip code validation object */
        Zip :
        {
            /* True if zip entered is valid, false otherwise */
            passed : false,

            /* Zip to test (String) */
            zip : null,

            /**
             * Set zip property
             *
             * @param zip (string)
             * @returns Zip (object)
             */
            setZip : function ()
            {
                this.zip = (arguments[0]) ? arguments[0] : null;
                return this;
            },

            /**
             * Callback used for MarketManager validation results. If the zip
             * entered is valid, set the hidden "city" input to the returned
             * city for the associated zip. If not, set the input background
             * to red and set passed to false.
             *
             * @param data
             */
            callback : function ()
            {
                var city, cityArr, data, e;

                try
                {
                    if ((data = arguments[0]) && data.zipCode != null)
                    {
                        BrowseCars.Validator.Zip.passed = true;
                        $("zip").style.backgroundColor = "";
                        if(data.city != null)
                            $('zip-search')['city'].value = data.city.toLowerCase().replace(/^\s+|\s+$/g, '').replace(/^(.)|\s(.)/g, function ($1) {
                                return $1.toUpperCase();
                            });
                    }
                    else
                    {
                        BrowseCars.Validator.Zip.passed = false;
                        document.getElementById("zip").style.backgroundColor = "#FFB7B7";
                    }
                }
                catch (e) {}
            },

            /**
             * Start running zip validation. If the zip is invalid, set the
             * input background color to a light red and set the passed
             * property to false. Otherwise, revert the baczkground color
             * and set passed to true.
             */
            execute : function ()
            {
                var e, i;

                try
                {
                    if (this.zip != null && this.zip != "" && this.zip.match(/^\d{5}$/) && this.zip != "00000")
                    {
                        MarketManager.getMarketByZipCode(this.zip, this.callback);
                    }
                    else
                    {
                        this.passed = false;
                        document.getElementById("zip").style.backgroundColor = "#FFB7B7";
                    }

                    return null;
                }
                catch (e) {}
            },

            /**
             * If passed is not true, alert the user
             *
             * @note This method should only be called upon a form submittal
             *
             * @returns passed (bool)
             */
            isValid : function ()
            {
                if (!this.passed)
                    alert("We're sorry; we couldn't find the ZIP code you entered.");

                return this.passed;
            }
        },

        /**
         * Direct reference and substitute constructor for BrowseCars.Validator.Zip
         * object
         *
         * @param zip (string)
         *
         * @returns null, Boolean (false)
         */
        validateZip : function () {
            return this.Zip.setZip(arguments[0]).execute();
        }
    }
}