/// <reference path="/js/jquery-1.4.4-vsdoc.js" />

/*! NV Forms v3 <http://nvinteractive.co.nz>
Copyright (c) NV Interactive
	
References:
jquery-1.x.js
h5f.nv.js
plugins.js (for window.log 
		
Release Notes:
3.5 - Replaced placeholder code with h5f functionality
	- Removed hacky "fixes" stuff
	- Now using window.log from plugins.js // paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
	- Removed custom classes, now rely on [type=xxx] selectors
3.1 - Renamed references to watermark as placeholder to match html5
	- Refactored placeholder code
3.0.2 Watermark class no longer added for fields with no watermark
3.0.1 Fixed default button behaviour for multiple forms when enterkey is pressed.
3.0 rewrote as a jquery plugin
*/



//
// create closure
//
(function ($) {

    //
    // Constants
    //
    var _errorMessages = {
        patternMismatch: "That doesn't look like the right type of data",
        valueMissing: "This is a required field",
        rangeUnderflow: "Too small",
        rangeOverflow: "Too big"
    }


    //
    // NV Extended controls hack;
    // Assumes that the dom has loaded
    //
    $(".field").each(function () {
        var i = $(":input", this);
        var m = $(this).metadata().h5f;
        i.attr(m);

        if (m && m["data-type"]) {
            var t = m["data-type"];
            i.wrap("<div class='convert-type'></div>");
            var n = i.parent().html().replace(/ type=[\"\'][^\'\"]*[\'\"]/, ' type="' + t + '"');
            //var n = i.clone(true).attr("type", t);
            i.parent().replaceWith($(n));
        }
    });


    //
    // plugin definition
    //
    $.fn.nvforms = function (options) {
        
        // build main options before element iteration
        var opts = $.extend({}, $.fn.nvforms.defaults, options);

        // iterate and reformat each matched element
        return this.each(function () { processform(this, opts) });
    };


    //
    // define and expose our format function
    //
    processform = function (element, opts) {

        $this = $(element);


        //Apply H5F to parent form
        $form = $this.closest("form");
        if (!$form.data("H5Fprocessed")) {
            H5F.setup($form.get(0)); //Do we need to check that this has already been applied?
            $form.data("H5Fprocessed", "true");
        }

        // build element specific options
        var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
        o.form = $this;

        //Merge options with defaults
        o.errorMessages = $.extend({}, _errorMessages, o.errorMessages);

        //Ensure submitButton is jQuery objects
        if (o.submitButton)
            var submitButton = $(o.submitButton);
        else
            var submitButton = $("input[type=submit]", $this); //Default submit button

        //Add another separate form
        if (o.add)
            $this = $this.add($(o.add));

        //Disable submit or default button for invalid form
        if (o.disableSubmitForInvalid) {
            if (!$this.isValid())
                submitButton.attr("disabled", true);

            //Re-enable submit or default button when valid state changes
            $this.bind("validstatechange", function (e) {
                if ($(this).isValid())
                    submitButton.removeAttr("disabled");
                else
                    submitButton.attr("disabled", true)
            });
        }



        //Set original value for text fields
        $(":text, :password", $this).each(function () {
            var t = $(this);
            t.data("originalvalue", t.h5fval());
        });


        //select input contents on focus
        $(":text, :password", $this).focus(function () { this.select() });


        //Handle submit button clicks
        submitButton.click(function (e) { submit(e, o) });

        //If default button is not [type=submit] then manually handle keypress enter events
        //if( submitButton.attr("type") != "submit" ){
        //add keypress events to submit form
        $(":text, :password", $this).bind( "keydown", {options: o, submitButton: submitButton}, keydown );
        //}


        //Custom class animation for inputs with showvalid
        //TODO: customise this
        $("input[data-showvalid]", $this).bind("validstatechange", showvalid);

        //Error messages
        o.initialiseErrors($this);

        $this
			.delegate(":input.error, :input.required", o.showErrorOn, function (e) {

			    //Combine default messages with custom per field

			    //var messages = $.extend( {}, o.errorMessages, $(this).data("errormessages") );
			    var messages = o.errorMessages;

			    var message;
			    for (var j in messages) {
			        message = this.validity[j] ? $(this).data(j) || messages[j] : message;
			    }

			    o.onError(this, message, e);
			})
            .delegate(":input", o.hideErrorOn, hideError);

    };

    showvalid = function (e) {
        if ($(this).data("validstate.currentstate"))
            $(this).addClass("valid-custom").removeClass("valid-custom", 2000);
        else
            $(this).removeClass("valid-custom");
    }


    keydown = function (e) {

        var t = $(e.target);

        if (e.which == 13) {
            //trigger a default button click
            e.preventDefault();
			if(e.data.options.enterkeySubmits)
				e.data.submitButton.click();
			return;
        }

        if (e.which == 27 && t.is(":text")) {
            t.val(t.data("originalvalue"));
        }


    }

    submit = function (e, o) {

        //Get form from options object
        var form = o.form;

        //Validate form
        if (o.validateOnSubmit && !form.isValid(true)) {
            o.onInvalidSubmit();
            e.preventDefault();
            return;
        }

        var f = form.closest("form");

        //Use a dummy form
        if (o.useDummyForm) {
            createDummyForm(o, form);
            e.preventDefault();
            return;
        }

        //Set method and action
        f.attr({
            action: o.action || f.attr("action"),
            method: o.method || f.attr("method"),
            target: o.tartget || f.attr("target")
        });
        //e.preventDefault();
        //f.submit();

        if (o.cancelSubmit) e.preventDefault();
    }


    createDummyForm = function (o, f) {

        var form = $("<form />");
        form.attr({
            action: o.action,
            method: o.method,
            target: o.target
        }).css("visibility: hidden");

        var inputs;
        if (o.includeButtonsInDummyForm)
            var inputs = $(":input", f);
        else
            var inputs = $(":input:not([type=button],[type=submit])", f);

        inputs.each(function (index) {
            var t = $(this);
            var input = $("<input type='hidden' />")
				.attr({
				    name: t.data("name") || t.attr("name")
				})
				.val(t.h5fval())
				.appendTo(form);
        });

        form.appendTo($("body"));

        if (o.cancelSubmit) return;
        form.submit();
    }


    createQuery = function (a, f) {
        var query = a + "?";

        $(":input", f).each(function (index) {
            query += index != 0 ? "&" : "";
            query += $(this).attr("name") + "=" + encodeURI($(this).val());
        });

        return query;
    }


    //
    // Error message defaults
    //
    initialiseErrors = function (context) {
        //Setup poshytips for validation fields
        $(':input:not([type=submit],[type=button])', context).poshytip({
            className: 'tip-twitter',
            content: 'This is a required field',
            alignTo: 'target',
            alignX: 'inner-left',
            offsetX: 0,
            offsetY: 5,
            showTimeout: 50,
            showOn: 'none'
        });
    }

    showError = function (field, message, e) {
        $(field).data("poshytip").opts.content = message;
        $(field).poshytip('show');
    }

    hideError = function (e) {
        $(this).poshytip('hide');
    }

    //
    // plugin defaults
    //
    $.fn.nvforms.defaults = {
        submitButton: null,
        validateOnSubmit: true,
        onInvalidSubmit: function () { alert("There was a problem with some of the fields.") },
        disableSubmitForInvalid: true,
        method: "post",
        action: undefined,
        target: undefined,
        useDummyForm: false,
        includeButtonsInDummyForm: false,
        errorMessages: {}, //Will get merged with defaults
        initialiseErrors: initialiseErrors, // function(context)
        onError: showError, // function( triggerfield, errormessage )
        onHideError: hideError, // function(event) standard jQuery event arguments
        showErrorOn: 'mouseover', // jQuery events on target field
        hideErrorOn: 'mouseout focus', // jQuery events on target field
        add: undefined, //Add another, separate, container to the form.
		enterkeySubmits: true, // controls default behaviour of enter key
        cancelSubmit: false //Use to debug

    };
    //
    // end of closure
    //
})(jQuery);




// Custom value function - allows for h5f placeholders

//Custom properties
jQuery.fn.extend({
	
	h5fval: function() {

		var $this = $(this[0]);
		
		if( $this.hasClass("placeholder") )	return "";
		
		return $this.val();
		
	}
	
});

