function Mmf_Form(opts)
{
    var _form, _preventDefaults;

    function _writeError(item, message) {
        var error;
        if ((error = $('div.error', item.parents('tr:first'))).size() > 0) {
            error.html(message);
        } else if (item.is('textarea')) {
            $('div.message_error').html(message);
        }
    }

    function _preventDefaultAction(item, name) {
        if (typeof item == 'string') {
            return false;
        }
        return _preventDefaults[item.attr('name')] && _preventDefaults[item.attr('name')][name]; 
    }
    
    function _validEmail(item) {
        var str;
        if (!_preventDefaultAction(item, 'validEmail')) {
            str = (typeof item == 'string') ? item : item.val();
            if (!/^[A-Za-z0-9\.\_\%\+\-]+\@[A-Za-z0-9\.\-]+\.[A-Za-z]{2,6}$/.test(str)) {
                if (typeof item !== 'string') {
                    _writeError(item, 'Please enter a valid email address.');
                }
                return false;
            }
            return true;
        }
    }

    function _preSelectSubject(subject) {
        $.each($('select option', _form),
            function() {
                if ($(this).html() == subject || $(this).val() == subject) {
                    $('select').val($(this).val());
                }
            });
    }

    function _isEmpty(item) {
        if (!_preventDefaultAction(item, 'isEmpty')) {
            if (item.attr('value') === '') {
                _writeError(item, 'This field is required.');
                return true;
            }
            return false;
        }
        return false;
    }

    function _lengthTest(item, lengthLimit) {
        if (!_preventDefaultAction(item, 'lengthTest')) {
            if (item.attr('value').length > lengthLimit) {
                _writeError(item, 'Your input is too long by ' + (item.val().length - lengthLimit) + ' character(s).');
                return false;
            }
            return true;
        }
    }

    function _characterCount(event) {
        var messageLength, error;
        messageLength = event.target.value.length;
        error = $('div.message_error');
        if (messageLength > _MAX_CNT) {
            error.html('Your message is too long by ' + (messageLength - _MAX_CNT) + ' character(s).');
            error.css('color', '#C22724');
        } else {
            error.html(_MAX_CNT - messageLength + ' character(s) left.');
            error.css('color', '');
        }
    }

    function _phoneValidate(item) {
        if (!/^\d?(\s*|[\-\.])\d{3}(\s*|[\-\.])\d{3}(\s*|[\-\.])\d{4}$/.test(item.val())) {
            _writeError(item, 'Enter a valid telephone number.');
            return false;
        }
        return true;
    }

    function _emailsValidate(item) {
        var i, emails;
        if (!_isEmpty(item)) {
            emails = item.val().split(',');
            for (i = 0; i < emails.length; i++) {
                if (!_validEmail(Mmf_Util.trim(emails[i]))) {
                    _writeError(item, 'Invalid email address: ' + emails[i]);
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    function _subjectValidate(item) {
        if (item.is('select')) {
            return !_isEmpty(item);
        }
        return true;
    }

    function _validateItem(item) {
        switch (item.attr('name')) {
            case 'first_name':
                return !_isEmpty(item);
            case 'last_name':
                return !_isEmpty(item);
            case 'names':
                return !_isEmpty(item);
            case 'email':
                return !_isEmpty(item) && _validEmail(item);
            case 'emails':
                return _emailsValidate(item);
            case 'telephone':
                return !_isEmpty(item) && _phoneValidate(item);
            case 'subject':
                return _subjectValidate(item);
            case 'message':
                return _lengthTest(item, _MAX_CNT) && !_isEmpty(item);
            case 'title':
                return !_isEmpty(item);
            case 'company':
                return !_isEmpty(item);
        }
        return true;
    }
    
    function _validateAndSend(event) {
        event.preventDefault();
        var valid = true;
        $.each($('input[type!="hidden"][name], textarea[name], select[name]', _form),
                function() {
                    if (!_preventDefaults || !_preventDefaults[$(this).attr('name')]) {
                        var validItem = _validateItem($(this));
                        if (validItem) {
                            _writeError($(this), '');
                        }
                        valid = valid && validItem;
                    }
                });
        if (valid) {
            _form.unbind('submit');
            _form.submit();
        }
    }

    function _init(opts) {
        _form = $(opts.formSelector);
        _preventDefaults = opts.preventDefaults ? opts.preventDefaults : false;
        _MAX_CNT = opts.MAX_CNT ? opts.MAX_CNT : 4000;
        $('textarea[name="message"]', _form).bind('keyup', _characterCount);
        _form.bind('submit', _validateAndSend);
        if (opts.preSelectedSubject && $('select', _form)) {
            _preSelectSubject(opts.preSelectedSubject);
        }
    }
    
    _init(opts);
}
