/**
 * enhancement.js
 * 
 * Collect & Create by Terence Chao
 */

// String Enhancement
String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$|\n$|^\n/g, '');
};

String.prototype.escapeMarkup = function() {
    var character = {
        '<': '&lt;',
        '>': '&gt;',
        '&': '&amp;',
        '"': '&quot;'
    };
    return this.replace(/[<>&"]/g, function (c) {
        return character[c];
    });
};

String.prototype.isPartOf = function(str) {
    var re = new RegExp( '(^|\\s)' + this + '(^|\\s)' );
    return re.test( str );
};

// Array Enhancement
Array.prototype.foreach = function(fn) {
    for( var i=0; i<this.length; i++) {
        fn.call( this[i] );
    } // for
};

// Function Enhancement
Function.prototype.method = function(name, fn) {
    this.prototype[name] = fn;
};

// Interface class
var Interface = function(name, methods) {
    if(arguments.length != 2) {
        throw new Error( 'Interfac constructor called with ' + arguments.length + 
        ' arguments, but expected exactly 2' );
    } //if
    
    this.name = name;
    this.methods = [];
    
    for( var i=0, len=methods.length; i<len; i++) {
        if( typeof methods[i] !== 'string' ) {
            throw new Error( 'Interface constructor expects method names to be ' +
            'passed in as a string.' );
        } // if
        this.methods.push( methods[i] );
    } // for
};

// from John Resig's book
// Static class method to ensure implements interface methods
Interface.ensureImplements = function(object) {
    if(arguments.length < 2) {
        throw new Error( 'Function Interface.ensureImplements called with ' + arguments.length +
        ' arguments, but expected at least 2.' );
    } // if
    
    for( var i=1, len=arguments.length; i<len; i++) {
        var interface = arguments[i];
        if(interface.constructor !== Interface) {
            throw new Error( 'Function Interface.ensureImplements expects arguments ' +
            'two and above to be instances of Interface' );
        } // if
        
        for( var j=0, methodsLen=interface.methods.length; j<methodsLen; j++) {
            var method = interface.methods[j];
            if( !object[methods] || typeof object[method] !== 'function' ) {
                throw new Error( 'Function Interface.ensureImplements: object ' +
                'does not implement the ' + interface.name +
                ' interface. Method ' + method + ' was not found.' );
            } // if
        } // for
    } // for
};

// Form Validation (from John Resig)
// CSS Class based JavaScript Form Validation
var errMsg = {
    // check for required field
    required: {
        msg: '這個欄位為必填欄位。',
        test: function( obj ) {
            return obj.value.length > 0;
        }
    },
    notrel: {
        msg: '欄位值不合法',
        test: function( obj ) {
            return !obj.value || !( obj.value === obj.getAttribute( 'rel' ) );
        }
    },
    year: {
        msg: '輸入年格式錯誤(請輸入西元年)',
        test: function( obj ) {
            return !obj.value || /^\d{4}$/.test( obj.value );
        }
    },
    month: {
        msg: '輸入月份格式錯誤(請輸入1-12)',
        test: function( obj ) {
            return !obj.value || /^[1-9]{1}$|^1[0-2]{1}$/.test( obj.value );
        }
    },
    day: {
        msg: '輸入日期格式錯誤(請輸入1-31)',
        test: function( obj ) {
            return !obj.value || /^[1-9]{1}$|^[1-2][0-9]{1}$|^3[0-1]{1}$/.test( obj.value );
        }
    },
    creditcardtype: {
        msg: '請選擇信用卡類別',
        test: function( obj ) {
            return !obj.value || obj.value === 'AE' || obj.value === 'VISA' || obj.value === 'MASTER';
        }
    },
    equmaxlen: {
        msg: '輸入值過長',
        test: function( obj ) {
            // for ie6 getAttribute('maxlength') is number but not true in ff and ie8
            return !obj.value || obj.value.length.toString() === obj.getAttribute('maxlength').toString();
        }
    },
    sameasref: {
        msg: '兩個欄位值必須相同',
        test: function( obj ) {
            if( obj.getAttribute('ref') === null || document.getElementById( obj.getAttribute('ref') ) === null ) {
                return false;
            } else {
                return !obj.value || obj.value === document.getElementById( obj.getAttribute('ref') ).value;
            }
        }
    },
    mobiletw: {
        msg: '行動電話格式錯誤',
        test: function( obj ) {
            if( obj.value !== undefined && obj.value !== '' ) {
                return /^09\d{8}$/.test( obj.value );
            }
            return true;
        }
    }
};

function validateForm( form, errlist, errstyle ) {
    var valid = true;
    
    for( var i=0; i<form.elements.length; i++ ) {
        if( ! validateField( form.elements[i], errlist, errstyle ) ) {
            valid = false;
        } // if
    } // for
    
    return valid;
};

function validateField( elem, errlist, errstyle ) {
    var errors = [];
    var name;
    var re;
    
    for( name in errMsg ) {
        re = new RegExp( '(^|\\s)' + name + '(\\s|$)' );
        if( re.test( elem.className ) && !errMsg[name].test( elem ) ) {
            errors.push( elem.getAttribute( 'alt' ) + ': ' + errMsg[name].msg );
            elem.setAttribute('style', errstyle);
        } // if
    } // for
    
    if(errors.length>0) {
        errors.foreach( function() {
            errlist.push( this + '\n' );
        });
    }
    
    return !(errors.length > 0);
};

function setFormInputStyle( form, style, escapetype ) {
    for( var i=0; i<form.elements.length; i++ ) {
        if( form.elements[i].getAttribute('type') !== null && 
            !form.elements[i].getAttribute('type').isPartOf(escapetype) ) {
            form.elements[i].setAttribute('style', style);
        }
    } // for
};

