﻿$.fn.reverse = [].reverse;

$.easing.elasout = function(x, t, b, c, d) {
	var s=1.70158;var p=0;var a=c;
	if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
	if (a < Math.abs(c)) { a=c; var s=p/4; }
	else var s = p/(2*Math.PI) * Math.asin (c/a);
	return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
};

$.easing.jswing             = jQuery.easing.jswing;
$.easing.def                = jQuery.easing.def;

$.easing.easeInQuad         = jQuery.easing.easeInQuad;
$.easing.easeInCubic        = jQuery.easing.easeInCubic;
$.easing.easeInQuart        = jQuery.easing.easeInQuart;
$.easing.easeInQuint        = jQuery.easing.easeInQuint;
$.easing.easeInSine         = jQuery.easing.easeInSine;
$.easing.easeInExpo         = jQuery.easing.easeInExpo;
$.easing.easeInCirc         = jQuery.easing.easeInCirc;
$.easing.easeInElastic      = jQuery.easing.easeInElastic;
$.easing.easeInBack         = jQuery.easing.easeInBack;
$.easing.easeInBounce       = jQuery.easing.easeInBounce;

$.easing.easeOutQuad        = jQuery.easing.easeOutQuad;
$.easing.easeOutCubic       = jQuery.easing.easeOutCubic;
$.easing.easeOutQuart       = jQuery.easing.easeOutQuart;
$.easing.easeOutQuint       = jQuery.easing.easeOutQuint;
$.easing.easeOutSine        = jQuery.easing.easeOutSine;
$.easing.easeOutExpo        = jQuery.easing.easeOutExpo;
$.easing.easeOutCirc        = jQuery.easing.easeOutCirc;
$.easing.easeOutElastic     = jQuery.easing.easeOutElastic;
$.easing.easeOutBack        = jQuery.easing.easeOutBack;
$.easing.easeOutBounce      = jQuery.easing.easeOutBounce;

$.easing.easeInOutQuad      = jQuery.easing.easeInOutQuad;
$.easing.easeInOutCubic     = jQuery.easing.easeInOutCubic;
$.easing.easeInOutQuart     = jQuery.easing.easeInOutQuart;
$.easing.easeInOutQuint     = jQuery.easing.easeInOutQuint;
$.easing.easeInOutSine      = jQuery.easing.easeInOutSine;
$.easing.easeInOutExpo      = jQuery.easing.easeInOutExpo;
$.easing.easeInOutCirc      = jQuery.easing.easeInOutCirc;
$.easing.easeInOutElastic   = jQuery.easing.easeInOutElastic;
$.easing.easeInOutBack      = jQuery.easing.easeInOutBack;
$.easing.easeInOutBounce    = jQuery.easing.easeInOutBounce;

var socialCircle = {
    testimonialVideosHelper: {
        // socialCircle.testimonialVideosHelper.init ();
        //
        init: function (testimonialVideosJson) {
            function loadVideo(playerUrl, autoplay) {
                var url = playerUrl + '&enablejsapi=1&rel=0&hd=1&border=0&fs=1&showsearch=0&showinfo=1&autoplay=' + (autoplay ? 1 : 0);
                swfobject.embedSWF(
                    url, 'popupPlayer', vidWidth, vidHeight, '8.0.0', false,
                    false,
                    {
                        allowfullscreen: 'true',
                        wmode: 'transparent',
                        allowScriptAccess: 'always'
                    }
                );
            }

            var nextVideoIndex = 1;    // 1-based
            var videoBatchSize = 50;   // must be no larger than 50

            var videoDataOrig;
            var videoOrderData = [];
            var videoData = [];
            var tooltipData = [];
            var videoCount = 0;
            var easing1 = "swing";
            var easing2 = "easeOutExpo";
            var videos, testimonials, doc, wnd, mask, popup, popupInner, titleBar, popupText, popupClose, testimonialsWrapper;
            var duration1 = 250;
            var duration2 = 125;

            function wireUpTestimonials() {
                var scrollExtent = 120 * 6;

                var prevScrollConfig = {
                    duration: duration1,
                    offset: { top: -0, left: -scrollExtent },
                    easing: easing1,
                    onAfter: function () {
                    }
                };
                var nextScrollConfig = {
                    duration: duration1,
                    offset: { top: 0, left: scrollExtent },
                    easing: easing1,
                    onAfter: function () {
                    }
                };

                testimonials.find('.nav.prev').click(function () {
                    var origPos = videos.scrollLeft();

                    videos.scrollTo(videos, prevScrollConfig);

                    var newPos = videos.scrollLeft();

                    //            if (origPos == newPos) {
                    //                videos.scrollTo (videos, prevScrollConfig);
                    //            }
                });

                testimonials.find('.nav.next').click(function () {
                    var origPos = videos.scrollLeft();

                    videos.scrollTo(videos, nextScrollConfig);

                    var newPos = videos.scrollLeft();
                });

                if (videoCount === 0) {
                    $('.testimonialsWrapper').addClass('hidden');
                }
            }


            var videos;

            var rowCount = 6;
            var colCount = 7;

            var thumbWidth = 120;
            var thumbHeight = 90;

            var vidWidth = 640;
            var vidHeight = 390;

            var rowMaxIndex = rowCount - 1;
            var colMaxIndex = colCount - 1;
            var pageSize = 2 * (rowCount - 1) + 2 * (colCount - 1);

            var curPage = 0;
            var pageCount = 0;

            function displayVideos() {

                // show the current (first) page
                //
                buildDom();

                wireUpTestimonials();
            }

            var popupFullSize = {
                width: 640,
                height: 420
            };
            var popupSmallSize = {
                width: 50,
                height: 50
            };
            function centrePopup() {
                popup.css({
                    top: wnd.scrollTop() + (wnd.height() - popup.width()) / 2,
                    left: wnd.scrollLeft() + (wnd.width() - popup.height()) / 2
                });
            }
            function randBelow(upperBound) {
                return Math.floor(Math.random() * upperBound);
            }
            function showMask(callback) {
                mask.css({ width: wnd.width(), height: doc.height() });
                mask.fadeIn(duration2, callback);
                mask.fadeTo(duration2, 0.82);
            }
            function hideMask(callback) {
                mask.css({ width: wnd.width(), height: doc.height() });
                mask.fadeOut(duration2, callback);
                mask.fadeTo(duration2, 0);
            }
            function hidePopup() {
                var targetProps = {
                    width: popupSmallSize.width,
                    height: popupSmallSize.height
                };
                var animProps = {};

                switch (randBelow(4)) {
                    case 0:
                        animProps["top"] = -popupFullSize.height - 50;
                        break;
                    case 1:
                        animProps["left"] = wnd.width() + 50;
                        break;
                    case 2:
                        animProps["top"] = wnd.height() + 50;
                        break;
                    case 3:
                        animProps["left"] = -popupFullSize.width - 50;
                        break;
                };
                popup.animate(animProps, {
                    duration: duration1,
                    easing: easing1,
                    complete: function () {
                        popup.addClass('hidden');
                        popup.css({ display: "" });
                        hideMask();
                        titleBar.addClass('hidden');
                    },
                    step: function () {
                    },
                    queue: false
                });
            }
            function openVideoInPopup(entry) {
                showMask(function () {
                    popupInner.css({
                        width: 0,
                        height: 0
                    });

                    centrePopup();

                    var targetProps = {
                        width: popupFullSize.width,
                        height: popupFullSize.height
                    };

                    popup.fadeIn(250);
                    popupInner.animate(targetProps, {
                        duration: duration1,
                        easing: easing1,
                        complete: function () {
                            titleBar.removeClass('hidden');
                            popupText.text(entry.title);
                            loadVideo(entry.playerUrl, true);
                        },
                        step: function () {
                        },
                        queue: false
                    });
                    popup.animate({
                        left: "-=" + (popupFullSize.width - popupSmallSize.width) / 2,
                        top: "-=" + (popupFullSize.height - popupSmallSize.height) / 2
                    }, {
                        duration: duration1,
                        easing: easing1,
                        complete: function () {
                        },
                        step: function () {
                        },
                        queue: false
                    });
                });
            }

            function buildDom() {

                var videosHtml = [];

                for (var videoIndex = 0; videoIndex < videoCount; videoIndex++) {
                    var entry = videoOrderData[videoIndex];

                    videosHtml.push(
                        '<span class="vidThumb"',
                        ' videoIndex="',
                        videoIndex,
                        '">',
                        '<img width="',
                        thumbWidth,
                        '" height="',
                        thumbHeight,
                        '" src="',
                        entry.thumbnailUrl, '" />',
                        '</span>'
                    );
                }

                videos.html(videosHtml.join(''));


                videos.find('.vidThumb').click(function () {
                    var thumb = $(this);
                    var videoIndex = thumb.attr('videoIndex');
                    var entry = videoOrderData[videoIndex];

                    openVideoInPopup(entry);
                }).tooltip(socialCircle.domHelper.applyTooltipDefaults({
                    bodyHandler: function () {
                        var thumb = $(this);
                        var videoIndex = Number(thumb.attr('videoIndex'));
                        var thumbHtml = tooltipData[videoIndex];

                        if (!thumbHtml) {
                            var entry = videoOrderData[videoIndex];

                            thumbHtml = [
                                "<table><tr><td colspan='2' class=\'vidTitle\'>",
                                videoIndex + 1,
                                ") ",
                                entry.title,
                                "</td></tr>",
                                "<tr><td colspan='2'><span class='label'>published:&nbsp;",
                                (new Date(parseInt(entry.publishDate))).toDateString(),
                                "</span></td></tr>",
                                "</table>"
                            ];

                            thumbHtml = thumbHtml.join('');

                            tooltipData[videoIndex] = thumbHtml;
                        }

                        return thumbHtml;
                    }
                }));
            }

            function consumeJsonConfigData (result) {
                videoOrderData  = result.videoOrderData;
                videoCount      = videoOrderData.length;

                displayVideos();
            }

            function getVideoOrderData() {
                videos.html(
                    "<span class='ajaxMessage'>Loading...</span>"
                );

                $.ajax({
                    type: "POST",
                    async: false,
                    dataType: "json",
                    url: "testimonial-videos-async.asp",
                    data: ({
                        action: "getTestimonalVideosConfig"
                    }),
                    success: function (data, textStatus) {
                        if (data.success) {
                            consumeJsonConfigData(data);
                        }
                        else {
                        }
                    },
                    error: function (XMLHttpRequest, textStatus, errorThrown) {
                    }
                });
            }

            $(document).ready(function () {
                wnd = $(window);
                doc = $(document);
                testimonials = $('#testimonials');
                videos = $('#videos');
                mask = $('.mask');
                popup = $('.popup');
                popupInner = $('.popup .inner');
                titleBar = $('.popup .titleBar');
                popupText = titleBar.find('.text');
                popupClose = titleBar.find('.close');

                popupClose.click(function (e) {
                    e.preventDefault();

                    hidePopup();
                });

                mask.click(function () {
                    return false;
                });

                if (testimonialVideosJson) {
                    consumeJsonConfigData(testimonialVideosJson);
                }
                else {
                    getVideoOrderData();
                }
            });

            return openVideoInPopup;
        }
    },

    // -- fade helper from http://www.codylindley.com/blogstuff/js/jquery/# ---------------------------
    // [tweaked slightly]
    //
    fadeHelper: {
        easeInOut: function (minValue, maxValue, totalSteps, actualStep, powr) {
            var delta = maxValue - minValue;
            var stepp = minValue + (Math.pow(((1 / totalSteps) * actualStep), powr) * delta);

            return Math.ceil(stepp);
        },

        addFade: function () {
            addFadeToElem(this);
        },

        // socialCircle.fadeHelper.addFadeToElem (elem, config)
        //
        addFadeToElem: function (elem, config) {
            if (elem.jquery) {
                elem = elem.get(0);
            }
            if (!config) {
                config = {
            };
        }
        if (!config.fromCol) {
            config.fromCol = [0xff, 0xff, 0x40];
        }
        if (!config.toCol) {
            config.toCol = [0xff, 0xff, 0xff];
        }
        if (!config.finalCol) {
            config.finalCol = 'transparent';
        }
        if (!config.steps) {
            config.steps = 30;
        }
        if (!config.intervals) {
            config.intervals = 30;
        }
        if (!config.powr) {
            config.powr = 4;
        }
        socialCircle.fadeHelper.doBGFade(
	            elem,
	            config.fromCol,
	            config.toCol,
	            config.finalCol,
	            config.steps,
	            config.intervals,
	            config.powr
	        );
    },

    // socialCircle.fadeHelper.doBGFade
    doBGFade: function (elem, startRGB, endRGB, finalColor, steps, intervals, powr) {
        if (elem.bgFadeInt) {
            window.clearInterval(elem.bgFadeInt);
        }
        var easeInOut = socialCircle.fadeHelper.easeInOut;

        var actStep = 0;
        elem.bgFadeInt = window.setInterval(
	            function () {
	                elem.style.backgroundColor = "rgb(" +
			            easeInOut(startRGB[0], endRGB[0], steps, actStep, powr) + "," +
			            easeInOut(startRGB[1], endRGB[1], steps, actStep, powr) + "," +
			            easeInOut(startRGB[2], endRGB[2], steps, actStep, powr) +
	                ")";

	                actStep++;
	                if (actStep > steps) {
	                    elem.style.backgroundColor = finalColor;
	                    window.clearInterval(elem.bgFadeInt);
	                }
	            }, intervals
	        );
    }
},

// -- (end) fade helper from http://www.codylindley.com/blogstuff/js/jquery/# ---------------------








scrollHelper: {
    // socialCircle.scrollHelper.addScrollToHashLinks ($container, fnAfterScroll);
    //
    addScrollToHashLinks: function ($container, afterScroll) {
        $container.find('a').click(function () {
            var target = $(this.hash);

            $.scrollTo(target, {
                duration: 200,
                offset: { top: -60, left: 0 },
                easing: "easeOutExpo",
                onAfter: function () {
                    if (afterScroll) {
                        afterScroll(target);
                    }
                }
            });
            return false;
        });
    },

    // socialCircle.scrollHelper.hilightCol
    //
    hilightCol: [0xff, 0xff, 0xa0],

    // socialCircle.scrollHelper.scrollToAndHilight (target, [0xff, 0xff, 0xff]);
    //
    scrollToAndHilight: function (target, toColorArray) {
        toColorArray = toColorArray || [0x63, 0xc9, 0xff];

        $.scrollTo(target, {
            duration: 200,
            offset: { top: -60, left: 0 },
            easing: "easeOutExpo",
            onAfter: function () {
                (function () {
                    socialCircle.fadeHelper.addFadeToElem(target, {
                        fromCol: socialCircle.scrollHelper.hilightCol,
                        toCol: toColorArray,
                        finalCol: toColorArray
                    });
                })();
            }
        });
    },

    // socialCircle.scrollHelper.scrollContainerAndHilight (container, target, [0xff, 0xff, 0xff]);
    //
    scrollContainerAndHilight: function (container, target, toColorArray) {
        toColorArray = toColorArray || [0x63, 0xc9, 0xff];

        container.scrollTo(target, {
            duration: 200,
            offset: { top: -60, left: 0 },
            easing: "easeOutExpo",
            onAfter: function () {
                (function () {
                    socialCircle.fadeHelper.addFadeToElem(target, {
                        fromCol: socialCircle.scrollHelper.hilightCol,
                        toCol: toColorArray,
                        finalCol: toColorArray
                    });
                })();
            }
        });
    }
},



formHelper: {
    pleaseChoose: "-- please choose --",

    // socialCircle.formHelper.augmentCss ();
    //
    augmentCss: function () {
        // apply a class to checkbox and radio-button labels
        //
        $('label').each(function (index) {
            // only labels which are associated with checkboxes
            //
            var field = $(this);

            var targetId = field.attr('for');
            if (targetId) {
                $('#' + targetId + ':checkbox').each(function () {
                    field.addClass('checkboxLabel')
                });
                $('#' + targetId + ':radio').each(function () {
                    field.addClass('radioLabel')
                });
            }
        });
    },

    // socialCircle.formHelper.prepareLeeForm ()
    //
    prepareLeeForm: function () {
        $('.leeForm input[type=text], .leeForm input[type=password], .leeForm textarea').addClass('textField');
        $('.leeForm input[type=text], .leeForm input[type=password], .leeForm textarea, .leeForm select').not('.optionalField').addClass('requiredField');
        $('.leeForm .optGroup').not('.optionalField').addClass('requiredField');
        $('.leeForm .submit[disabled]').addClass('disabled');

        $('.leeForm input[type=radio], .leeForm input[type=checkbox]').addClass('checkableInput').addClass('styled');
        $('.leeForm label').not('.leeForm .optGroup label').filter(function (index) {
            // don't append a colon to labels associated with checkboxes
            //
            var field = $(this);
            var ok = true;

            //              if (field.attr ('tagName').toLowerCase () === "label") {
            var targetId = field.attr('for');
            if (targetId) {
                $('#' + targetId + ":checkbox").each(function () {
                    ok = false;
                });
            }
            //              }

            return ok;
        }).append(':');

        $('.requiredField').tooltip(socialCircle.domHelper.applyTooltipDefaults({
            bodyHandler: function () {
                var field = $(this);

                var thumbHtml = "";

                var errors = field.get(0).validationErrors;

                function addRow(msg) {
                    thumbHtml.push("<tr><td colspan='2'><span class='label'>");
                    thumbHtml.push(msg);
                    thumbHtml.push("</span></td>");
                }

                if (errors && errors.length > 0) {
                    thumbHtml = [
                            "<table>"
                        ];

                    for (var i = 0, len = errors.length; i < len; i++) {
                        addRow(errors[i].message);
                    }

                    thumbHtml.push("</table>");

                    thumbHtml = thumbHtml.join('');
                }

                return thumbHtml;
            }
        }));

        $('.leeForm input, .leeForm .optGroup *, .leeForm select, .leeForm textarea').not('.leeForm input[type=submit]').focus(function (e) {
            var field = $(this);

            field.addClass('selectedField');

            var optGroup = field.parents('.optGroup');

            if (optGroup.length >= 1) {
                $(optGroup[0]).addClass('selectedField');
            }
        }).blur(function (e) {
            var field = $(this);
            field.removeClass('selectedField');

            var optGroup = field.parents('.optGroup');
            if (optGroup.length >= 1) {
                $(optGroup[0]).removeClass('selectedField');
            }
        });

        $('.leeForm .optGroupSelAll').click(function (e) {
            var optGroup = $(this).parents('.optGroup');

            socialCircle.formHelper.setDescendantCheckboxesTo(optGroup, true);
            e.preventDefault();
        });

        $('.leeForm .optGroupSelNone').click(function (e) {
            var optGroup = $(this).parents('.optGroup');

            socialCircle.formHelper.setDescendantCheckboxesTo(optGroup, false);
            e.preventDefault();
        });

        socialCircle.formHelper.updateLabelsToShowRequiredFields();
    },

    // socialCircle.formHelper.updateLabelsToShowRequiredFields ()
    //
    updateLabelsToShowRequiredFields: function () {
        // remove the 'synthetic' elements generated to work around IE6's lack of :after
        //
        $('.requiredFieldLabel_after').remove();

        $('.leeForm .requiredField').each(function () {
            var field = $(this);

            // find the label in the first cell in the row
            //
            field.parents('tr').find('td:first label').addClass('requiredFieldLabel');
        });
        $('.leeForm .optionalField').each(function () {
            var field = $(this);

            // find the label in the first cell in the row
            //
            field.parents('tr').find('td:first label').removeClass('requiredFieldLabel');
        });

        // add 'synthetic' elements, generated to work around IE6's lack of :after
        //
        $('.requiredFieldLabel').each(function () {
            $(this).after(
                    $(document.createElement('span'))
                        .addClass('requiredFieldLabel_after')
                        .html("*")
                );
        });
    },

    // socialCircle.formHelper.trim (jqElem)
    //
    trim: function (jqElem) {
        var mayTrim = false;

        switch (jqElem.attr('tagName').toLowerCase()) {
            case 'input':
                switch (jqElem.attr('type').toLowerCase()) {
                    case 'password':
                    case 'text':
                        mayTrim = true;
                        break;
                }
                break;
            case 'textarea':
                mayTrim = true;
                break;

            default:
                if (jqElem.hasClass('optGroup')) {
                    jqElem.find('input[type=radio], input[type=checkbox]').each(function () {
                        // recursively trim fields within a group
                        //
                        socialCircle.formHelper.trim($(this));
                    });
                }
                break;
        }
        if (mayTrim) {
            var trimVal = jqElem.val();
            if (trimVal) {
                trimVal = jQuery.trim(trimVal);
            }
            jqElem.val(trimVal);
        }
    },

    // socialCircle.formHelper.hasValue (jqElem)
    //
    hasValue: function (jqElem) {
        var valueFound = false;

        switch (jqElem.attr('tagName').toLowerCase()) {
            case 'input':
                switch (jqElem.attr('type').toLowerCase()) {
                    case 'password':
                    case 'text':
                        valueFound = jqElem.val() != "";
                        break;
                    case 'checkbox':
                        valueFound = jqElem.attr('checked') != "";
                        break;
                    case 'radio':
                        valueFound = jqElem.attr('checked') != "";
                        break;
                }
                break;
            case 'textarea':
                valueFound = jqElem.val() != "";
                break;

            case 'select':
                valueFound = jqElem.val() != socialCircle.formHelper.pleaseChoose;
                break;

            default:
                if (jqElem.hasClass('optGroup')) {
                    jqElem.find('input[type=radio], input[type=checkbox]').each(function () {
                        // a single radio or checkbox checked within the group 
                        // may be interpreted as the group having value for validation purposes
                        //
                        if (socialCircle.formHelper.hasValue($(this))) {
                            valueFound = true;
                            return false;
                        }
                    });
                }
                break;
        }

        return valueFound;
    },

    // socialCircle.formHelper.validateFormFields (jqForm, config)
    //
    //
    // config is an optional object of the form:
    //  {
    //      // optional - maps an id to a validationFunc by id
    //      //
    //      validationHandlers: {
    //          formId1:    function (formField) { 
    //              return true if valid; or an object of the form:
    //              {
    //                  valid:      true or false,
    //                  message:    validation message
    //              }
    //          }, // validationFunc1
    //          formId2:    function (formField) { return true if valid... as previously; } // validationFunc2
    //      },
    //
    //      // optional - maps a form field to a validationFunc
    //      //
    //      getValidationHandler: function (formField) {
    //
    //          // determine which validation func to return, each of the form:
    //          //      function (formField) { 
    //                      return true if valid; or an object of the form:
    //                      {
    //                          valid:      true or false,
    //                          message:    validation message
    //                      }
    //          //      }
    //          //
    //          return somehowMapFormFieldToValidationFunc (formField);
    //      },
    // ----------------------------------------------------------------------------------------
    //      // optional - maps an id to a function which applies/removes a visual indicator
    //      // meaning 'failed validation'
    //      // e.g. if the field holding the data has been replaced by a rich editor or flash component.
    //      //
    //      validationFailureMarkerHandlers: {
    //          formId1:    function (formField, valid) { // show/hide marker dependent upon 'valid' flag },
    //          formId2:    function (formField, valid) { // show/hide marker dependent upon 'valid' flag }
    //      },
    //
    //      // optional - maps a form field to a validationFailureHandler
    //      //
    //      getValidationFailureMarkerHandler: function (formField, valid) {
    //          // show/hide marker dependent upon 'valid' flag
    //      }
    // ----------------------------------------------------------------------------------------
    //      // optional - maps an id to an action to take which indicates the validation-failure to the user
    //      //
    //      validationFailureHandlers: {
    //          formId1:    function (formField) { // do something to indicate validation failure },
    //          formId2:    function (formField) { // do something to indicate validation failure }
    //      },
    //
    //      // optional - maps a form field to a validationFailureHandler
    //      //
    //      getValidationFailureHandler: function (formField) {
    //          // do something to indicate validation failure for the formField
    //      }
    //  }
    //
    //  Note: both validationHandlers and getValidationHandler may be present - 
    //      if both specify validationFunctions for a particular field, the first to return a value validates the field.
    //
    //  same comment for validationFailureHandlers and getValidationFailureHandler - 
    //      the validationFailureHandlers-entry will take precendence
    //
    validateFormFields: function (jqForm, config) {
        var valid = true;
        var form = jqForm;
        var newlyFailedFields = [];

        form.find('.requiredField').each(function () {
            var field = $(this);

            field.get(0).validationErrors = [];

            var validationFuncs = [];

            if (
                    config &&
                    config.validationHandlers &&
                    field.attr('id') &&
                    config.validationHandlers[field.attr('id')]
                ) {
                validationFuncs.push(config.validationHandlers[field.attr('id')]);
            }


            if (
                    config &&
                    config.getValidationHandler &&
                    config.getValidationHandler(field)
                ) {
                validationFuncs.push(config.getValidationHandler(field));
            }

            validationFuncs.push(function (jqElem) {
                var hasValue = socialCircle.formHelper.hasValue(jqElem);

                var result = {
                    valid: hasValue,
                    message: hasValue ? "Valid" : "Value required"
                };

                return result;
            });

            // trim the field's value
            //
            socialCircle.formHelper.trim(field);

            // test validity
            //
            var result = false, validationResult;
            for (var i = 0; i < validationFuncs.length; i++) {
                validationFunc = validationFuncs[i];

                validationResult = validationFunc(field);

                if (validationResult !== undefined && validationResult !== null) {
                    // break as soon as the field has been validated
                    result = validationResult;
                    break;
                }
            }

            if (typeof (result) !== 'object') {
                result = {
                    valid: result
                };
            }
            if (!result.message) {
                message = (result.valid ? "Valid" : "Value required")
            }


            // decide how absence of validity is to be demonstrated to the user
            //
            var markerFunc;
            if (
                    config &&
                    config.validationFailureMarkerHandlers &&
                    field.attr('id') &&
                    (markerFunc = config.validationFailureMarkerHandlers[field.attr('id')])
                ) { }
            else if (
                    config &&
                    config.getValidationFailureMarkerHandler &&
                    (markerFunc = config.getValidationFailureMarkerHandler(field))
                ) { }
            else {
                markerFunc = function (formField, result) {
                    if (result.valid) {
                        formField.removeClass('requiredFieldNeedsAttention');
                    }
                    else {
                        formField.addClass('requiredFieldNeedsAttention');
                        formField.get(0).validationErrors.push(result);
                    }
                };
            }

            // show a visual indicator to indicate validation failure/success
            //
            if (result.valid) {
                markerFunc(field, result);
            }
            else {
                newlyFailedFields.push(field)
                valid = false;
                markerFunc(field, result);
                //                  return false;;
            }
        });

        if (valid) {
        }
        else if (!valid) {
            // scroll the page to the first field which needs attention.
            // assumes that the relative vertical order of the form fields 
            // is the same as the definitions of those fields within the document
            //
            if (newlyFailedFields.length >= 1) {
                var field = $(newlyFailedFields[0]);

                var validationFailureHandler;

                if (
                        config &&
                        config.validationFailureHandlers &&
                        field.attr('id') &&
                        (validationFailureHandler = config.validationFailureHandlers[field.attr('id')])
                    ) { }
                else if (
                        config &&
                        config.getValidationFailureHandler &&
                        (validationFailureHandler = config.getValidationFailureHandler(field))
                    ) { }
                else {
                    validationFailureHandler = function (formField) {
                        window.setTimeout(function () {
                            $.scrollTo(formField, {
                                duration: 200,
                                offset: { top: -60, left: 0 },
                                onAfter: function () {
                                    window.setTimeout(function () { field.focus(); }, 0);
                                },
                                easing: "easeOutExpo"
                            });
                        }, 0);
                    }
                }

                validationFailureHandler(field);

                return false;
            }
        }

        return valid;
    },

    stringValidation: {
        // socialCircle.formHelper.stringValidation.isIntegerWithinRange (val, lower, upper);
        //
        // the string val holds an integer within the specified range (doubly-inclusive)
        //
        isIntegerWithinRange: function (val, lower, upper) {
            var valid = false;

            if (socialCircle.formHelper.stringValidation.isInteger(val)) {
                val = parseInt(val);

                valid = (val >= lower) && (val <= upper);
            }

            return valid;
        },

        // socialCircle.formHelper.stringValidation._re_isInteger;
        //
        // regex which ensures that the input string consists solely of a decimal integer
        //
        _re_isInteger: /^[0-9]+$/,


        // socialCircle.formHelper.stringValidation.isInteger (val);
        //
        // the string val holds an integer
        //
        isInteger: function (val) {
            var valid = !!val.match(socialCircle.formHelper.stringValidation._re_isInteger);

            return valid;
        }
    },

    // socialCircle.formHelper.setChildCheckboxesTo (container, checked)
    //
    // container is a jquery object
    // checked is boolean (true or false)
    //
    setDescendantCheckboxesTo: function (container, checked) {
        var checkboxes = container.find('input[type=checkbox]').each(function () {
            if (checked) {
                $(this).attr('checked', 'checked');
            }
            else {
                $(this).removeAttr('checked');
            }
        });
    },

    // socialCircle.formHelper.focusWhenReady (id);
    //
    focusWhenReady: function (id) {
        $(document).ready(function () {
            $('#' + id).focus();
        });
    },

    // socialCircle.formHelper.applyWatermark (config);
    //
    // config is an object of the form:
    //  {
    //      // specifiy the field in some way (this should really be a query plugin):
    //          fieldId:        "fieldId",
    //          selector:       "#blah .blah > etc",
    //          field:          <a field reference>,
    //
    //      text:           "watermark text",
    //      watermarkClass: "cssClasForWatermark"
    //  }
    //
    applyWatermark: function (config) {
        if (!config.watermarkClass) { config.watermarkClass = "watermark" }

        function setWatermark(field) {
            if (field.val() == "") {
                field.addClass(config.watermarkClass);
                field.val(config.text);
            }

            //	            $(window).unload (function () {
            //	                alert ("unloading: " + field.attr ('name'));
            //	                unsetWaterMark (field);
            //	            });
        }

        function unsetWatermark(field) {
            if (field.val() == config.text) {
                field.val("");
                field.removeClass(config.watermarkClass);
            }
        }

        var field = config.field || $(
                config.selector ? config.selector : ('#' + config.fieldId)
            );

        setWatermark(field);

        field.focus(function () {
            var field = $(this);

            unsetWatermark(field);
        }).blur(function () {
            var field = $(this);

            setWatermark(field);
        });
    },

    // socialCircle.formHelper._eventEditorsMarker;
    //
    _eventEditorsMarker: '<!-- event description -->',

    // socialCircle.formHelper.doEventEditorsSubmit (isEvent);
    //
    // validates the fields on the two pages which allow creation/editing of events - these should be centralised
    //
    doEventEditorsSubmit: function (isEvent, isNewTemplate, isTemplateClone, editTemplate, deleteTemplate) {

        var whatsOnHeaderValid = false;
        var whatsOnTextValid = false;
        if (isEvent === undefined) var isEvent = true;
        if (isNewTemplate === undefined) var isNewTemplate = false;

        function combinedWhatsOnValid() {
            return whatsOnHeaderValid && whatsOnTextValid;
        }

        // prepareForSubmit
        //
        var eventDescContent = eventDescEditor.getData();

        if (eventDescContent && eventDescContent.indexOf(socialCircle.formHelper._eventEditorsMarker) == -1) {
            eventDescEditor.setData(socialCircle.formHelper._eventEditorsMarker + eventDescContent);
        }
        else if (!eventDescContent) {
            eventDescEditor.setData(socialCircle.formHelper._eventEditorsMarker);
        }

        var whatsOnFieldValues = getWhatsOnFieldValues();

        $('#whatsOnHeaderField').val(whatsOnFieldValues.whatsOnHeader);
        $('#whatsOnTextField').val(whatsOnFieldValues.whatsOnText);
        $('#whatsOnFooterField').val(whatsOnFieldValues.whatsOnFooter);

        return socialCircle.formHelper.validateFormFields(
                $('#eventForm'), {
                    validationHandlers: {
                        'eventType': function (formField) {
                            // always valid - it's an optional field
                            //
                            return {
                                valid: true
                            };
                        },
                        'eventDesc': function (formField) {
                            var eventDescText = eventDescEditor.getData();

                            if (!!eventDescText) {
                                // the marker shouldn't be considered as text when checking for the presence of text
                                //
                                eventDescText = eventDescText.replace(socialCircle.formHelper._eventEditorsMarker, "");
                            }

                            return {
                                valid: !!eventDescText
                            };
                        },
                        'whatsOnHeaderField': function (formField) {
                            var whatsOnFieldValues = getWhatsOnFieldValues();
                            var featureWithinWhatsOn = $('#featureWithinWhatsOn').attr('checked');
                            var valid = !featureWithinWhatsOn || (
                                                                whatsOnFieldValues.whatsOnHeader != whatsOnDefaults.header &&
                                                                !!whatsOnFieldValues.whatsOnHeader
                                                            );

                            whatsOnHeaderValid = valid;

                            return {
                                valid: valid
                            };
                        },
                        'whatsOnTextField': function (formField) {
                            var whatsOnFieldValues = getWhatsOnFieldValues();
                            var featureWithinWhatsOn = $('#featureWithinWhatsOn').attr('checked');
                            var valid = !featureWithinWhatsOn || (
                                                                whatsOnFieldValues.whatsOnText != whatsOnDefaults.text &&
                                                                !!whatsOnFieldValues.whatsOnText
                                                            );

                            whatsOnTextValid = valid;

                            return {
                                valid: valid
                            };
                        },
                        'whatsOnFooterField': function (formField) {
                            // always valid - it's an optional field
                            //
                            return {
                                valid: true
                            };
                        }
                    },
                    getValidationHandler: function (formField) {
                        var validationHandler;

                        if (formField.attr('id') === 'templateName') {
                            validationHandler = function (formField) {
                                return {
                                    valid: isEvent || isTemplateClone || editTemplate || deleteTemplate || (isNewTemplate && $.trim(formField.val()) != ""),
                                    message: "Please enter a name for the new template"
                                };
                            };
                        }
                        else if (formField.attr('id') === 'templates') {
                            validationHandler = function (formField) {
                                return {
                                    valid: !isTemplateClone || !editTemplate || !deleteTemplate || formField.val() != "-1",
                                    message: "There are no templates defined"
                                };
                            };
                        }
                        else if (isNewTemplate || isTemplateClone || editTemplate || deleteTemplate) {
                            validationHandler = function (formField) {
                                return {
                                    valid: true
                                };
                            };
                        }

                        return validationHandler;
                    },
                    getValidationFailureMarkerHandler: function (formField) {
                        var validationMarkerHandler;

                        switch (formField.attr('name')) {
                            case 'eventDesc':
                                validationMarkerHandler = function (formField, result) {
                                    var editorContainer = $('#cke_eventDesc');
                                    if (result.valid) {
                                        editorContainer.removeClass('requiredFieldNeedsAttention');
                                    }
                                    else {
                                        editorContainer.addClass('requiredFieldNeedsAttention');
                                    }
                                };
                                break;

                            case 'whatsOnHeader':
                                validationMarkerHandler = function (formField, result) {
                                    var note = socialCircle.flashHelper.getMovie('whatsOn');
                                    note.showValidationFailureMarker(!combinedWhatsOnValid());
                                };
                                break;
                            case 'whatsOnText':
                                validationMarkerHandler = function (formField, result) {
                                    var note = socialCircle.flashHelper.getMovie('whatsOn');
                                    note.showValidationFailureMarker(!combinedWhatsOnValid());
                                };
                                break;
                            case 'whatsOnFooter':
                                // always valid
                                //
                                break;
                        }

                        return validationMarkerHandler;
                    },
                    getValidationFailureHandler: function (formField) {
                        var validationFailureHandler;

                        switch (formField.attr('name')) {
                            case 'eventDesc':
                                validationFailureHandler = function (formField) {
                                    window.setTimeout(function () {
                                        $.scrollTo($('#cke_eventDesc'), {
                                            duration: 200,
                                            offset: { top: -60, left: 0 },
                                            onAfter: function () {
                                                window.setTimeout(function () { formField.focus(); }, 0);
                                            },
                                            easing: "easeOutExpo"
                                        });
                                    }, 0);
                                };
                                break;
                            case 'whatsOnHeader':
                            case 'whatsOnText':
                                validationFailureHandler = function (formField) {
                                    if (whatsOnLoaded) {
                                        // do nothing - note is already visible
                                    }
                                };
                                break;
                        }

                        return validationFailureHandler;
                    }
                }
            );
    }
},








stringHelper: {
    // socialCircle.stringHelper._re_replaceHtmlTags
    //
    _re_replaceHtmlTags: /\<(?:\/)?([^>]+)\>/,

    // socialCircle.stringHelper.replaceHtmlTags (str);
    //
    replaceHtmlTags: function (str) {
        if (str) {
            str = str.replace(socialCircle.stringHelper._re_replaceHtmlTags, "$1");
        }
        return
    },

    // socialCircle.stringHelper.mergeTitleAndDesc (title, desc);
    //
    mergeTitleAndDesc: function (title, desc) {
        var merged;

        if (title && desc && title != desc
            ) {
            merged = title + " - " + desc;
        }
        else {
            merged = title || desc;
        }

        return merged;
    },

    // socialCircle.stringHelper._htmlToTextDomElem
    //
    _htmlToTextDomElem: $(document.createElement('span')),

    // socialCircle.stringHelper.htmlToText (html);
    //
    htmlToText: function (html) {
        var text = socialCircle.stringHelper._htmlToTextDomElem.html(html).text();

        return text;
    },

    // socialCircle.stringHelper._re_getUrlFileName
    //
    _re_getUrlFileName: /.*\/([\w-]+)\..*/,


    // socialCircle.stringHelper.getUrlFileName (url);
    //
    // for an url such as: 'http://www.social-circle.co.uk/default.asp',
    // returns 'default'
    //
    getUrlFileName: function (url) {
        var fileName;

        var result = url.match(socialCircle.stringHelper._re_getUrlFileName);

        if (result) {
            fileName = result[1];
        }
        return fileName;
    },

    // socialCircle.stringHelper.writtenInteger (value);
    //
    writtenInteger: function (value) {
        var written;

        var conv = [
                "zero",
                "one", "two", "three", "four", "five",
                "six", "seven", "eight", "nine", "ten",
                "eleven", "twelve", "thirteen", "fourteen", "fifteen",
                "sixteen", "seventeen", "eighteen", "nineteen", "twenty"
            ];

        var intVal = Math.round(value);
        if ((value == intVal) && intVal >= 0 && intVal < conv.length) {
            written = conv[intVal];
        }
        else {
            written = value.toString();
        }
        return written;
    },

    // socialCircle.stringHelper.removeItemFromCommaSepString (str, item);
    //
    removeItemFromCommaSepString: function (str, item) {
        var ret = "";

        if (str) {
            if (item) {
                var ar  = str.split (/,|\s*,\s*/);
                var pos = -1;

                for (var i = 0; i < ar.length; i++) {
                    if (ar [i] == item) {
                        pos = i;
                        break;
                    }
                }
                if (pos != -1) {
                    ar.splice (pos, 1);
                } 
                ret = ar.join (', ');
            }
            else {
                ret = str;
            }
        }

        return ret;
    }},

linkHelper: {
    reFixNeeded: /http\:\/\/localhost\/social-circle.*/,
    reLinkFix: /^\/(?!social-circle)(.*)/,

    // socialCircle.linkHelper.linkFix ();
    //
    linkFix: function () {
        if (window.location.href.match(socialCircle.linkHelper.reFixNeeded)) {
            $("a").each(function () {
                var a = $(this);
                var href = a.attr('href');
                if (href) {
                    var hrefFixed = href.replace(socialCircle.linkHelper.reLinkFix, "/social-circle/$1");

                    a.attr('href', hrefFixed);
                }
            });
        }
    }
},

adminSettingsHelper: {
    // socialCircle.adminSettingsHelper.write (settingName, settingValue, callback);
    //
    // callback is of the form: function (data, textStatus) {}
    //
    write: function (settingName, settingValue, callback) {
        // writes the value; passes the return value to the callback function
        //
        $.post(
                "admin-settings-async.asp",
                {
                    settingDirection: "write",
                    settingName: settingName,
                    settingValue: settingValue
                },
                callback
            );
    },

    // socialCircle.adminSettingsHelper.read (settingName, callback);
    //
    read: function (settingName, callback) {
        // read the value; passes the return value to the callback function
        //
        $.post(
                "admin-settings-async.asp",
                {
                    settingDirection: "read",
                    settingName: settingName
                },
                callback
            );
    }
},

flashHelper: {
    // var movie = socialCircle.flashHelper.getMovie (movieName);
    //
    getMovie: function (movieName) {
        var isIE = navigator.appName.indexOf("Microsoft") != -1;

        return (isIE) ? window[movieName] : document[movieName];
    }
},

domHelper: {
    // socialCircle.domHelper.siteWide ();
    //
    siteWide: function () {

        if ($.browser.msie) {
            switch ($.browser.version) {
                case "6.0":
                    $('body').addClass('ie6');
                    break;
                case "7.0":
                    $('body').addClass('ie7');
                    break;
                case "8.0":
                    $('body').addClass('ie8');
                    break;
            }
        }

        // breaks the browser's ability to recognise links
        //
        //$(document).pngFix(); 

        // -- misc ----------------------------------------------------------------------------------------
        // make external links open in a new tab/window
        $("a[rel=external]").attr("target", "_blank");

        socialCircle.linkHelper.linkFix();

        // -- drop-down menu ------------------------------------------------------------------------------

        // pre-request the hover images
        //
        var hidden = $(document.createElement('div'))
                            .css('display', 'none');

        $(document).append(hidden);

        $("#menu > ul > li").each(function () {
            var li = $(this);

            var img = $(document.createElement('img'))
                    .attr('src', getImageForMenuItem(li, "sel"));

            hidden.append(img);
        });

        $("#menu > ul > li > ul > li").each(function () {
            $(this).hover(function () {
                $(this).addClass("selectedMenuItem");
            }, function () {
                $(this).removeClass("selectedMenuItem");
            });
        });

        $("#menu > ul > li").hover(function () {
            var li = $(this);
            li.addClass("openMenu");

            setImageForMenuItem(li, "sel");
        }, function () {
            var li = $(this);
            li.removeClass("openMenu");

            setImageForMenuItem(li);
        }).click(function (e) {
            var li = $(this);
            if (li.hasClass("openMenu")) {
                li.removeClass("openMenu");
            }
            else {
                li.addClass("openMenu");
            }
            var targ = $(e.originalTarget);
            var singleton = targ.parent() && targ.parent().parent() && targ.parent().parent().hasClass("singleton");
            var topLevel = targ.parent() && targ.parent().hasClass("topLevelMenuLink");

            //                if (topLevel && !singleton) {
            //                    return false;
            //                }
        });

        $("#menu > ul > li").each(function () {
            var li = $(this);
            var items = li.find('li');

            if (items.length === 0) {
                li.addClass("singleton");
            }
            li.addClass("topLevelMenuItem");
            li.children("a").each(function () {
                $(this).addClass("topLevelMenuLink");
            });
        });

        var url = window.location.href;
        if (url === '<%= siteRootUrl %>') {
            url += "default.asp";
        }

        // show the current-page indicator
        //
        $('#menu a').each(function () {
            var link = $(this);
            var linkUrl = link.attr('href');

            if (url.indexOf(linkUrl) != -1) {
                var li = link.parent();

                if (li.hasClass('topLevelMenuItem')) {
                    setImageForMenuItem(li, "sel", true);
                }
                else {
                    li.addClass('curPage');
                    li = li.parents('li.topLevelMenuItem');
                    setImageForMenuItem(li, "nested", true);
                }
            }
        });

        socialCircle.domHelper.replaceTitles();

        // -- js-augmented js as IE6 needs to be supported :( ---------------------------------------------

        $('input[type=checkbox]').each(function () {
            $(this).addClass('checkbox');
        });

        $('.leeForm table td:first-child').addClass('labelCol');

        socialCircle.formHelper.augmentCss();
    },

    // -- dynamic title images -----------------------------------------------------------------------

    // socialCircle.domHelper._applyDynamicTitleClass ();
    //
    _applyDynamicTitleClass: function (elem, headerSize, additionalCssClasses) {
        var cssClass = "title";

        var dynamicCssClass = ["dynamicTitle"];

        if (additionalCssClasses) {
            dynamicCssClass.push (additionalCssClasses);
        }

        dynamicCssClass = dynamicCssClass.join (', ');
        switch (headerSize) {
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
            default:
                cssClass += headerSize.toString();
                dynamicCssClass += headerSize.toString();
        }
        elem.removeClass(cssClass);
        elem.addClass("disabledTitle");

        dynamicTitle(elem, elem.html(), dynamicCssClass);
    },

    // socialCircle.domHelper._re_replaceTitles;
    //
    _re_replaceTitles: /\btitle([0-9]?)\b/,

    // socialCircle.domHelper.replaceTitles ();
    //
    replaceTitles: function () {
        var candidateClasses = ['title', 'title2', 'title3', 'title4', 'title5'];
        var candidateSelectors = [];
        $.each (candidateClasses, function (index, elemClass) {
            candidateSelectors.push ("." + elemClass);
        });
        candidateSelectors = candidateSelectors.join (', ');
        $(candidateSelectors)
                .not(
                    '.basic, .disabledTitle, .dynamicTitle1, .dynamicTitle2, ' +
                    '.dynamicTitle3, .dynamicTitle4, .dynamicTitle5'
                ).each(
            function () {
                var elem     = $(this);
                var size     = 1;
                var cssClass = elem.attr('class') || "";
                var result   = cssClass.match(socialCircle.domHelper._re_replaceTitles);

                var remainingCssClass = cssClass;

                if (result) {
                    result            = result[1] || "1";
                    size              = parseInt(result);
                    var matchingCandidateClass = "";
                    $.each (candidateClasses, function (index, elemClass) {
                        if (elem.hasClass (elemClass)) {
                            matchingCandidateClass = elemClass;
                            return false;
                        }
                    });
                    remainingCssClass = socialCircle.stringHelper.removeItemFromCommaSepString (cssClass, matchingCandidateClass);
                }

                socialCircle.domHelper._applyDynamicTitleClass(elem, size, remainingCssClass);
            });

        $('.dynamicTitle1:first, .dynamicTitle2:first, .dynamicTitle3:first, .dynamicTitle4:first, .dynamicTitle5:first ').addClass('first');
    },

    // socialCircle.domHelper.applyTooltipDefaults ();
    //
    applyTooltipDefaults: function (settings) {
        var settingsDefaults = {
            track: true,
            delay: 0,
            showURL: false,
            top: -30,
            left: 15,
            fixPNG: false,
            extraClass: "tooltip"
        };

        for (var prop in settingsDefaults) {
            settings[prop] = settingsDefaults[prop];
        }

        return settings;
    },

    // socialCircle.domHelper.scrollToMainTitle ();
    //
    scrollToMainTitle: function (offset) {
        var params = {
            duration: 200,
            easing: "easeOutExpo"
        };
        if (offset) {
            params.offset = { top: -60, left: 0 };
        }
        window.setTimeout(function () {
            $.scrollTo($('#mainTitle'), params);
        }, 250);
    },

    // socialCircle.domHelper.scrollToMainTitleWhenReady ();
    //
    scrollToMainTitleWhenReady: function () {
        $(document).ready(function () {
            socialCircle.domHelper.scrollToMainTitle();
        });
    },

    // socialCircle.domHelper._maskedMessageCloseFunc
    //
    _maskedMessageCloseFunc: undefined,

    // socialCircle.domHelper.showMaskedProgressIndicator (msg);
    //
    showMaskedProgressIndicator: function (msg) {
        _maskedMessageCloseFunc = $.floatbox({
            content: "<img src='images/progressIndicator3.gif' /><br />" + msg,
            fade: true,
            bgConfig: {
                zIndex: 1001
            },
            boxConfig: {
                paddingTop: "18px",
                paddingBottom: "18px",
                zIndex: 1002
            },
            button: ""
        });
    },

    // socialCircle.domHelper.hideMaskedProgressIndicator ();
    //
    hideMaskedProgressIndicator: function () {
        if (_maskedMessageCloseFunc) {
            _maskedMessageCloseFunc();
        }
        _maskedMessageCloseFunc = undefined;
    }
}
};

