jQuery.fn.cc_form_validate = function (options) {
    if (!options) {
        options = {};
    }
    var requiredText = 'is required.';
    if ('requiredText' in options) {
        requiredText = options.requiredText;
    }
    var emailFormatText = 'must be an email format.';
    if ('emailFormatText' in options) {
        emailFormatText = options.emailFormatText;
    }
    function errors_to_text(errors) {
        var text = '';
        for (name in errors) {
            text += errors[name] + '\n';
        }
        return text;
    }

    $(this).submit(function (ev) {
        var valid = true;
        var errors = {};
        $(this).find('input[type="text"],select,textarea').each(function () {
            var title = $(this).prev().html().split(' <')[0];
            if ($(this).attr('required') && !$(this).val()) {
                valid = false;
                var name = $(this).attr('name');
                if (requiredText.indexOf('%s') >= 0) {
                    errors[name] = requiredText.replace('%s', title);
                } else {
                    errors[name] = title + ' ' + requiredText;
                }
            }
            if ($(this).val() && title && (title.indexOf('Email') >= 0) && ($(this).val().indexOf('@') < 0)) {
                valid = false;
                errors[name] = title + ' ' + emailFormatText;
            }
        });
        if (!valid) {
            ev.preventDefault();
            window.alert(errors_to_text(errors));
        }
    });
};

jQuery.fn.ccImageTitle = function () {
    $(this).each(function () {
        var title = $(this).attr('alt');
        if (title) {
            $(this).after('<div class="image-title">' + title + '</div>');
        }
    });
};

jQuery.fn.ccAddress = function (tailE) {
    $(this).each(function () {
        var title = $(this).attr('title');
        tailE = '?' + tailE;
        var tail = '';
        for (var i = 0; i < tailE.length; ++i) {
            tail += String.fromCharCode(tailE.charCodeAt(i)+1);
        }
        var addr = title + tail;
        $(this).html('<a href="mailto:' + addr + '">' + addr + '</a>');
    });
};

jQuery.ccAddressE = function (addr) {
    var e = '';
    for (var i = 0; i < addr.length; ++i) {
        e += String.fromCharCode(addr.charCodeAt(i)-1);
    }
    return e;
};

jQuery.fn.ccExpandable = function () {
    var toggleClicked = function () {
        var $expanded = $(this).closest('.cc-expandable').find('.cc-expanded');
        if ($expanded.is(':visible')) {
            $expanded.fadeOut();
            $(this).removeClass('active');
        } else {
            $expanded.fadeIn();
            $(this).addClass('active');
        }
    };
    $(this).find('.cc-expanded').css('display', 'none');
    $(this).find('.cc-expand-toggle').bind('click', toggleClicked);
};

jQuery.ccExpandable = function () {
    $('.cc-expandable').ccExpandable();
};

jQuery.fn.ccFormFocus = function () {
    $(this).find('input').first().focus();
};

jQuery.fn.ccFormInnerLabel = function () {
    var ensureField = function () {
        if ($(this).val()) {
            $(this).addClass('filled');
        } else {
            $(this).removeClass('filled');
        }
    };
    $(this).find('input[type="text"], textarea').each(function () {
        $(this).bind('change', ensureField);
        $(this).bind('blur', function () {
            if (!$(this).hasClass('filled')) {
                $(this).val($(this).attr('title'));
            }
        });
        $(this).bind('focus', function () {
            if (!$(this).hasClass('filled')) {
                $(this).val('');
            }
        });
        /* empty the value */
        $(this).val('');
        $(this).trigger('change');
        $(this).trigger('blur');
    });
    $(this).find('select').each(function () {
        $(this).bind('change', ensureField);
        $(this).trigger('change');
    });
    $(this).submit(function (ev) {
        $(this).find('input[type="text"], textarea').each(function () {
            if (!$(this).hasClass('filled')) {
                $(this).val('');
            }
        });
    });
};

jQuery.fn.ccFormInnerLabelValidate = function () {
    $(this).submit(function (ev) {
        if ($(this).find('input[type="text"]:not(.filled):visible, textarea:not(.filled), select:not(.filled)').length) {
            ev.preventDefault();
            $(this).find('input[type="text"], textarea').trigger('blur');
            window.alert('Please complete the form.');
        }
    });
};

jQuery.fn.ccInnerLink = function () {
    $(this).each(function () {
        $(this).bind('click', function () {
            var addr = $(this).find('a').attr('href');
            window.location = addr;
        });
    });
};

jQuery.fn.ccScrollFollow = function () {
    if ($(this).length) {
        var $window = $(window);
        var topPadding = 20;
        var $follow = $(this);
        var offsetTop = $follow.offset().top;
        $window.scroll(function () {
            if ($window.scrollTop() > offsetTop - topPadding) {
                $follow.stop().animate({marginTop: $window.scrollTop() - offsetTop + topPadding});
            } else {
                $follow.stop().animate({marginTop: 0});
            }
        });
    }
};

jQuery.fn.ccLangOptions = function () {
    $(this).bind('change', function () {
        var addr = $(this).find('option[value="' + $(this).val() + '"]').attr('title') + window.location.pathname;
        var queryStr = '';
        var q = window.location.href.indexOf('?');
        if (q >= 0) addr += window.location.href.slice(q);
        window.location = addr;
    });
};

jQuery.ccDialogBox = function (message) {
    var closeDialog = function () {
        $('#cc-dialog-overlay, #cc-dialog-box').hide();
    };
    var closeText = 'Close';
    if ((window.messages != undefined) && ('close' in window.messages)) {
        closeText = window.messages['close'];
    }
    if (!$('#cc-dialog-box').length) {
        $('body').append('<div id="cc-dialog-overlay"></div><div id="cc-dialog-box"><div id="cc-dialog-message"></div><div id="cc-dialog-close"><span>' + closeText + '</span></div></div>');
    }
    $('#cc-dialog-message').html(message.replace(/\n/g, '<br />'));
    var boxTop = $(window).height()/3 - $('#cc-dialog-box').height()/2;
    var boxLeft = $(window).width()/2 - $('#cc-dialog-box').width()/2;
    $('#cc-dialog-box').css({top: boxTop + $(window).scrollTop(), left: boxLeft});
    $('#cc-dialog-overlay').css({height: $(document).height()});
    $('#cc-dialog-overlay, #cc-dialog-box').show();
    $('#cc-dialog-close span, #cc-dialog-overlay').bind('click', function () {
        closeDialog();
    });
};

jQuery.fn.ccGrouper = function (tag, options) {
    if (!options) options = {};
    var flush = function ($temp, title) {
        if (!title) {
            title = defaultTitle;
        }
        $temp.wrapAll('<div title="' + title + '"/>');
    }
    var $temp = $();
    var $children = $(this).children();
    var title = '';
    var stripTitle = false;
    var defaultTitle = '';
    if ('stripTitle' in options) {
        stripTitle = options.stripTitle;
    }
    if ('defaultTitle' in options) {
        defaultTitle = options.defaultTitle;
    }
    for (var i = 0; i < $children.length; i++) {
        var child = $children[i];
        if (child.tagName == tag) {
            flush($temp, title);
            title = $(child).text();
            $temp = $();
            if (stripTitle) $(child).remove();
            else $temp = $temp.add(child);
        } else {
            $temp = $temp.add(child);
        }
    }
    flush($temp, title);
};

jQuery.fn.ccCreateNav = function (cls) {
    var str = '<ul class="' + cls + '">\n';
    $(this).children().each(function () {
        str += '<li>' + $(this).attr('title') + '</li>\n';
    });
    str += '</ul>\n';
    $(this).before(str);
};

jQuery.fn.ccFormSubmitOnChange = function () {
    $(this).change(function () {
        $(this).closest('form').submit();
    });
};

