/**
 * Utility class for dealing with date ranges.
 */
Ext.define('Ext.calendar.date.Range', {
 
    /**
     * @property {Date} end
     * The end of this range.
     */
    end: null,
 
    /**
     * @property {Date} start
     * The start of this range.
     */
    start: null,
 
    isRange: true,
 
    statics: {
        fly: (function() {
            var range = null;
 
            return function(start, end) {
                if (start.isRange) {
                    return start;
                }
 
                if (!range) {
                    range = new Ext.calendar.date.Range();
                }
 
                range.start = start;
                range.end = end;
 
                return range;
            };
        })()
    },
 
    /**
     * @constructor
     * @param {Date} start The start date.
     * @param {Date} end The end date.
     */
    constructor: function(start, end) {
        this.start = start;
        this.end = end;
    },
 
    /**
     * Clone this range.
     * @return {Ext.calendar.date.Range} The new range.
     */
    clone: function() {
        var D = Ext.Date,
            T = this.self;
 
        return new T(D.clone(this.start), D.clone(this.end));
    },
 
    /**
     * Checks if this range contains a date.
     * @param {Date} d The date.
     * @return {Boolean} `true` if this date is contained in the range.
     */
    contains: function(d) {
        return this.start <= d && d <= this.end;
    },
 
    /**
     * Checks if this range fully contains another range (inclusive).
     * @param {Ext.calendar.date.Range/Date} start The range, or the start date.
     * @param {Date} end The end date. This is not required if a range is passed for start.
     * @return {Boolean} `true` if this range fully contains another range.
     */
    containsRange: function(start, end) {
        var other = this.self.fly(start, end);
 
        return other.start >= this.start && other.end <= this.end;
    },
 
    /**
     * Checks if this range equals another range.
     * @param {Ext.calendar.date.Range/Date} start The range, or the start date.
     * @param {Date} end The end date. This is not required if a range is passed for start.
     * @return {Boolean} `true` if this range equals another range.
     */
    equals: function(start, end) {
        var other;
 
        if (!start) {
            return false;
        }
 
        other = this.self.fly(start, end);
 
        return this.start.getTime() === other.start.getTime() &&
               this.end.getTime() === other.end.getTime();
    },
 
    /**
     * Get the duration of this range in milliseconds.
     * @return {Number} The duration.
     */
    getDuration: function() {
        return this.end.getTime() - this.start.getTime();
    },
 
    /**
     * Checks if this range is fully contained by another range.
     * @param {Ext.calendar.date.Range/Date} start The range, or the start date.
     * @param {Date} end The end date. This is not required if a range is passed for start.
     * @return {Boolean} `true` if this range fully is fully contained by another range.
     */
    isContainedBy: function(start, end) {
        var other = this.self.fly(start, end);
 
        return other.containsRange(this);
    },
 
    /**
     * Checks if any part of this range overlaps another range.
     * @param {Ext.calendar.date.Range/Date} start The range, or the start date.
     * @param {Date} end The end date. This is not required if a range is passed for start.
     * @return {Boolean} `true` if this range overlaps any part of the other range.
     */
    overlaps: function(start, end) {
        var other = this.self.fly(start, end);
 
        return other.start < this.end && this.start < other.end;
    }
});