﻿// extention helper methods;  
Date.prototype.copy = function() {
    return new Date(this.getTime());
};

Date.prototype.to12HrTimeString = function() {
    var h = "0" + this.getHours();
    var m = "0" + this.getMinutes();
    return [h.slice(-2), m.slice(-2)].join(':');
};


if (typeof Date.prototype.format === 'undefined') {
    Date.prototype.format = function() {
    
        var a = [
            this.getMonth()+1, 
            this.getDate(), 
            this.getFullYear()];
        
        var months = [
            "January",
            "February",
            "March",
            "April",
            "May",
            "June",
            "July",
            "August",
            "September",
            "October",
            "November",
            "December"];
            
        var days = [
            'Sunday',
            'Monday',
            'Tuesday',
            'Wednesday',
            'Thursday',
            'Friday',
            'Saturday'];
            
        return {
            'date': this,
            'usa': a.join('/'),
            'standard': [a[1], a[0], a[2]].join('/'),
            'day': a[1],
            'dayName': days[this.getDay()],
            'month': a[0]-1, 
            'monthName': months[a[0]-1],
            'year': a[2],
            'time': this.to12HrTimeString(), 
            'hours': this.getHours(), 
            'mins': this.getMinutes(), 
            'millisecs': this.getTime()
        }
    };
};


String.prototype.capitalise = function() {
    return this.replace(/^(\w)/g, function(){
        return arguments[1].toUpperCase();
    });
};


String.prototype.uncapitalise = function() {
    return this.replace(/^(\w)/g, function(){
        return arguments[1].toLowerCase();
    });
};

String.prototype.camelise = function() {
    return this.replace(/[\-|\s](\w)/g, function(){
        return arguments[1].toUpperCase();
    });
};


var validator = {

    validate: function(o) {
        // takes 2 dates and an update date, merges the 
        // update with it's related date and compares this
        // with it's inverse and updates accordingly;
        
        var offset = o.update.type === 'time' ? 2 : 24;

        // merge updated values with current date;
        var current = this.merge(o.current||{}, o.update);
        // update millisecs;
        current.millisecs = this.create(current).millisecs;
        
        // validate newly updated date against existing inverse date;
        if (! (o.update.name.indexOf('return') != -1 && o.update.sin === '0') && 
            ! this.isValidDate(current, o.inverse)) {
        
            // if inverse invalid create new inverse 
            // by copying current and...;
            var inverse = this.merge({}, current);
            
            // if date update, maintain supplied inverse' time;
            if (o.update.type === 'date' && inverse.hours < 22) {
                inverse.mins = o.inverse.mins;  
                inverse.hours = o.inverse.hours;   
            };
            
            // ...offsetting by a fixed time period;
            if (current.name.indexOf('outbound') != -1) {
                inverse.hours += offset;
            } else {
                inverse.hours -= offset;
            };
            
            // re-introduce any none date specific properties;
            current = this.merge(o.current, this.create(current));
            inverse = this.merge(o.inverse, this.create(inverse));
            
            return current.name.indexOf('outbound') != -1 ?
                [current, inverse] : [inverse, current];

        } else {
            return [this.merge(current||{}, this.create(current))];
        };
    },
    
    
    create: function(o) {
        return new Date(o.year, o.month, o.day, o.hours, o.mins).format();
    },
    
    
    merge: function(o, update) {
        for(var prop in update) {
            o[prop] = update[prop];
        };
        return o;
    },
    
    
    isValidDate: function(cur, inv) {
       // name always availible in any update;
       if ((cur === null || cur.name === undefined) || 
           (inv === null || inv.name === undefined)) {
            return true;
        }else {
            return cur.name && cur.name.indexOf('outbound') != -1 ?
                inv.millisecs >= cur.millisecs : cur.millisecs >= inv.millisecs;   
        };
    }
};

/*
var o3 = {
    current: {
        name: 'outboundDateTime',
        millisecs: new Date('7/8/1972').getTime()
    },
    inverse: {
        name: 'returnDateTime',
        millisecs: new Date('7/10/1972').getTime()
    },
    update: {
        name: 'outboundDateTime',
        millisecs: new Date('7/9/1972').getTime()
    }
}

console.log('isValid true:', validator2.isValidDate(o3.current, o3.inverse));

var o2 = {
    current: {
        name: 'outboundDateTime',
        millisecs: new Date('7/8/1972').getTime()
    },
    inverse: {},
    update: {
        name: 'outboundDateTime',
        millisecs: new Date('7/9/1972').getTime()
    }
}

console.log('isValid true:', validator2.isValidDate(o2.current, o2.inverse));


var o1 = {
    current: {
        name: 'outboundDateTime',
        millisecs: new Date('7/8/2010').getTime()
    },
    inverse: {
        name: 'returnDateTime',
        millisecs: new Date('7/22/2010').getTime()
    },
    update: {
        name: 'outboundDateTime',
        millisecs: new Date('7/9/2010').getTime(),
        type: 'date',
        hours: 10,
        year: 2010,
        month: 4,
        day: 13,
        mins: 7
    }
}

//console.log('isValid true:', validator2.validate(o1.current, o1.inverse));
console.log('update both:', validator2.validate(o1));
*/
// end helpers;

    
    