window.$tools = {
    $: function (obj) {
        obj.$ = !obj.$ ? {} : obj.$;
        obj.$.classes = !obj.$.classes ? {} : obj.$.classes;
    },
    exists: function () {
        return (arguments.length < 1)
            ? false
            : (typeof arguments[0] == 'undefined')
                ? false
                : true;
    },
    
    coalesce: function () {
        for (var i = 0; i  < arguments.length; i++) {
            if ($tools.exists(arguments[i])) {
                return arguments[i];
            };
        };
        return void(0);
    },
    
    
    override: function (obj, name, fn) {
        var force = !!$tools.coalesce(arguments[3], false);
        if ((force == true)
                || (!obj.prototype[name])) {
            obj.prototype[name] = fn;
        };
        return obj;
    },
    
    overrideStatic: function (obj, name, fn) {
        var force = !!$tools.coalesce(arguments[3], false);
        if ((force == true)
                || (!obj[name])) {
            obj[name] = fn;
        };
        return obj;
    },
    
    id: function (id) {
        return document.getElementById(id);
    },
    
    parse : {
        integer : function (data) {
            var defaultValue = $tools.coalesce(arguments[1], null);
            var hasDefaultValue = $tools.exists(arguments[1]);
            var radix = $tools.coalesce(arguments[2], 10);
            
            if (hasDefaultValue != true) {
                return parseInt(data, radix);
            } else if (data === null) {
                return defaultValue;
            };
            
            var result = parseInt(data, radix);
            return (isNaN(result)) ? defaultValue : result;
        },
        reel : function (data) {
            var defaultValue = $tools.coalesce(arguments[1], null);
            var hasDefaultValue = $tools.exists(arguments[1]);
            
            if (hasDefaultValue != true) {
                return parseFloat(data);
            } else if (data === null) {
                return defaultValue;
            }
            
            var result = parseFloat(data);
            return (isNaN(result)) ? defaultValue : result;
        }
    },
    
    cookies: {
        getValueFromOffset: function (offset) {
            var end = document.cookie.indexOf (';', offset);
            if (end == -1) {
                end = document.cookie.length;
            };
            return unescape(document.cookie.substring(offset, end));
        },
        has: function (name) {
            for(var i = 0,
                    c = '',
                    ca = document.cookie.split(';'),
                    nameEQ = name + '='; i < ca.length; i++) {
                c = ca[i];
                while (c.charAt(0) == ' ') {
                    c = c.substring(1,c.length);
                };
                if (c.indexOf(nameEQ) == 0) {
                    return true;
                };
            };
            return false;
        },
        read: function (name) {
            for(var i = 0,
                    c = '',
                    ca = document.cookie.split(';'),
                    nameEQ = name + '='; i < ca.length; i++) {
                c = ca[i];
                
                while (c.charAt(0) == ' ') {
                    c = c.substring(1,c.length);
                };
                if (c.indexOf(nameEQ) == 0) {
                    return unescape(c.substring(nameEQ.length, c.length));
                };
            };
            return void(0);
        },
        write: function (name) {
            var value = $tools.coalesce(arguments[1], null);
            if (value == null) {
                $tools.cookies.remove(name);
                return;
            };
            var expires = $tools.coalesce(arguments[2], null);
            var path    = $tools.coalesce(arguments[3], null);
            var domain  = $tools.coalesce(arguments[4], null);
            var secure  = $tools.coalesce(arguments[5], false);
            
            document.cookie = name + '=' + escape (value)
                + ((expires == null) ? '' : ('; expires=' + expires.toGMTString()))
                + ((path == null) ? '' : ('; path=' + path))
                + ((domain == null) ? '' : ('; domain=' + domain))
                + ((secure == false) ? '' : '; secure');
        },
        remove: function (name) {
            var exp = new Date();
            exp.setTime(exp.getTime() - 1);
            document.cookie = name + '=' + Cookies.read(name) + '; expires=' + exp.toGMTString();
        }
    }
};

window.$rugama = {};

// Based on code from http://www.youngpup.net/
$tools.override(Function, 'apply', function (object, parameters) {
    var parameterStrings = [];
    object = $tools.coalesce(object, window);
    parameters = $tools.coalesce(parameters, []);
    
    for (var i = 0; i < parameters.length; i++) {
      parameterStrings[i] = 'parameters[' + i + ']';
    };
    
    object.__apply__ = this;
    var result = eval('obj.__apply__(' +  parameterStrings.join(', ') + ')');
    object.__apply__ = null;
    
    return result;
});

$tools.overrideStatic(Function, 'isInstance', function (object) {
    return (typeof object).toLowerCase() == 'function';
});


$tools.overrideStatic(Array, 'isInstance', function (object) {
    return object instanceof Array;
});

$tools.override(Array, 'indexOf', function (el) {
    for (var i = 0, start = $tools.coalesce(arguments[1], 0), sz = this.length; i < sz; i++) {
        if (this[i] === el) {
            return i;
        };
    };
    return -1;
});

$tools.override(Array, 'contains', function (value) {
    return this.indexOf(value) < 0 ? false : true;
});

$tools.override(Array, 'filter', function (functionRef) {
    if (!Function.isInstance(functionRef)) {
        return [];
    };
    var target = $tools.coalesce(arguments[1], window);
    var result = [];
    for (var i = 0, sz = this.length; i < sz; i++) {
        if (functionRef.apply(target, [this[i], i, this]) != true) {
            continue;
        };
        result.push(this[i]);
    };
    return result;
});


$tools.override(Array, 'map', function (functionRef) {
    if (!Function.isInstance(functionRef)) {
        return [];
    };
    var target = $tools.coalesce(arguments[1], window);
    var result = [];
    for (var i = 0, sz = this.length; i < sz; i++) {
        result.push(functionRef.apply(target, [this[i], i, this]));
    };
    return result;
});



$tools.override(Array, 'forEach', function (functionRef) {
    if (!Function.isInstance(functionRef)) {
        return [];
    };
    var target = $tools.coalesce(arguments[1], window);
    for (var i = 0, sz = this.length; i < sz; i++) {
        functionRef.apply(target, [this[i], i, this]);
    };
});


$tools.override(Array, 'every', function (functionRef) {
    if (!Function.isInstance(functionRef)) {
        return [];
    };
    var target = $tools.coalesce(arguments[1], window);
    for (var i = 0, sz = this.length; i < sz; i++) {
        if (functionRef.apply(target, [this[i], i, this]) == true) {
            continue;
        };
        return false;
    };
    return true;
});

$tools.override(Array, 'some', function (functionRef) {
    if (!Function.isInstance(functionRef)) {
        return [];
    };
    var target = $tools.coalesce(arguments[1], window);
    for (var i = 0, sz = this.length; i < sz; i++) {
        if (functionRef.apply(target, [this[i], i, this]) == true) {
            return true;
        };
    };
    return false;
});



$tools.overrideStatic(String, 'isInstance', function (object) {
    return (typeof object).toLowerCase() == 'string';
});

$tools.overrideStatic(String, 'random', function () {
    var length = Number.parse.integer((arguments[0] || 6), 6);
    
    var result = '';
    var i = 0;
    
    for (i = 0; i < length; i++) {
        result += String.fromCharCode(97 + Math.floor((Math.random()*24)));
    };
    
    return result;
});

$tools.override(String, 'unQuote', function () {
    if (this.length < 1) {
        return '';
    };
    
    var quote = [
        ['"', '"'],
        ["'", "'"]];
    
    if (0 < arguments.length) {
        quote = [[arguments[0], $tools.coalesce(arguments[1], arguments[0])]];
    };
    
    var result = new String(this);
    
    for (var i = 0, sz = quote.length, firstPart = null, lastPart = null;
            i < sz; i++) {
        firstPart = new String(quote[i][0]);
        lastPart = new String(quote[i][1]);
        if (result.startsWith(firstPart) == true) {
            result = result.substr(firstPart.length);
        };
        if (result.endsWith(lastPart) == true) {
            result = result.substring(0, result.length - lastPart.length);
        };
    };
    return result;
});

$tools.override(String, 'findWord', function (word) {
    if (word == '') {
        return (this.toString() == '') ? true : false;
    };
    
    var tmp = this.split(' ');
    if (tmp.length < 1) {
        return (this.toString() == word) ? true : false
    };
    
    for (var i = 0, sz = tmp.length; i < sz; i++) {
        if (tmp[i] == word) {
            return true;
        };
    };
    return false;
});


$tools.override(String, 'addWord', function (word) {
    if (this == '') {
        return word;
    } else if (this.findWord(word) == true) {
        return this;
    };
    return this + ' ' + word;
});


$tools.override(String, 'removeWord', function (word) {
    var pattern = '(^| )' + word + '\W*';
    var re = new RegExp('(^| )' + word + '\W*');
    return this.replace(re, '');
});


$tools.override(String, 'reverse', function () {
    var result = '';
    for (i = this.length - 1; i >= 0; i--) {
        result += this.charAt(i);
    };
    return result;
});


$tools.override(String, 'rtrim', function () {
    return this.length < 1 ? '' : this.replace(/\s+$/, '');
});

$tools.override(String, 'ltrim', function () {
    return this.length < 1 ? '' : this.replace(/^\s+/, '');
});

$tools.override(String, 'trim', function () {
    return this.length < 1 ? '' : this.rtrim().ltrim();
});

$tools.override(String, 'startsWith', function (word) {
    return (this.indexOf(word) === 0);
});

$tools.override(String, 'endsWith', function (word) {
    var startPos = this.length - word.length;
    return (startPos < 0)
        ? false
        : (this.lastIndexOf(word, startPos) == startPos);
});

$tools.override(String, 'capitalize', function (word) {
    return (this.length < 1)
        ? ''
        : (this.length == 1)
            ? this.toUpperCase()
            : this.charAt(0).toUpperCase() + this.substr(1);
});




$tools.override(String, 'getUrlInfo', function (word) {
    if (this.length < 1) {
        return null;
    }
    
    var suffixSeparator = $tools.coalesce(arguments[1], '_');
    var part = this.split('index.php');
    var fileName = part.pop();
    var path = part.join('index.php');
    part = fileName.split('.');
    var extension = part.pop();
    var fileNameBase = part.join('.');
    var currentSuffix = '';
    part = fileNameBase.split(suffixSeparator);
    currentSuffix = part.pop();
    var basefileWithoutSuffix = part.join(suffixSeparator);
    return {
        path : path,
        file : fileName,
        ext : extension,
        basefile : fileNameBase,
        basefileWithoutSuffix : basefileWithoutSuffix,
        suffixSeparator : suffixSeparator,
        suffix : currentSuffix,
        changeSuffix : function (newSuffix) {
            return this.path
                + '/' + this.basefileWithoutSuffix
                + this.suffixSeparator
                + newSuffix
                + '.'
                + this.ext;
        },
        changeFile : function (newFile) {
            return this.path
                + '/'
                + newFile;
        }
    };
});



window.Point2D = function () {
    this.x = $tools.coalesce(arguments[0], 0);
    this.y = $tools.coalesce(arguments[1], 0);
};
Point2D.prototype.add = function () {
    this.x = this.x + $tools.parse.integer($tools.coalesce(arguments[0], 0), 0);
    this.y = this.y + $tools.parse.integer($tools.coalesce(arguments[1], 0), 0);
};
Point2D.prototype.clone = function () {
    return new Point2D(this.x, this.y);
};
Point2D.prototype.toString = function () {
    return 'Point2D(' + this.x + ', ' + this.y + ')';
};



window.Rectangle2D = function () {
    this.x = $tools.parse.integer($tools.coalesce(arguments[0], 0), 0)
    this.y = $tools.parse.integer($tools.coalesce(arguments[1], 0), 0)
    this.width = $tools.parse.integer($tools.coalesce(arguments[2], 0), 0)
    this.height = $tools.parse.integer($tools.coalesce(arguments[3], 0), 0)
    
};
Rectangle2D.prototype.setTopLeft = function (aPoint) {
    this.x = aPoint.x;
    this.y = aPoint.y;
};
Rectangle2D.prototype.setBottomRight = function (aPoint) {
    var deltaX = aRPoint.x - this.x;
    var deltaY = aRPoint.y - this.y;
    
    if (0 <= deltaX) {
        this.width = deltaX;
    } else {
        this.width = -deltaX;
        this.x = aRPoint.x;
    };
    
    if (0 <= deltaY) {
        this.height = deltaY;
    } else {
        this.height = -deltaY;
        this.y = aRPoint.y;
    };
};
Rectangle2D.prototype.getBottomRight = function () {
    return  new Point2D(this.x + this.width, this.y + this.height);
};
Rectangle2D.prototype.getTopLeft = function () {
    return new Point2D(this.x, this.y);
};
Rectangle2D.prototype.contains = function (x, y) {
    return this.containsPoint(new Point2D(x, y));
};
Rectangle2D.prototype.containsPoint = function (aPoint) {
    var topleft = this.getTopLeft();
    var bottomright = this.getBottomRight();
    
    return ((aPoint.x < topleft.x)
            || (bottomright.x < aPoint.x)
            || (aPoint.y < topleft.y)
            || (bottomright.y < aPoint.y))
        ? false
        : true;
};
Rectangle2D.prototype.containsRectangle = function (aRectangle2D) {
    return this.containsPoint(aRectangle2D.getTopLeft())
        && this.containsPoint(aRectangle2D.getBottomRight());
};
Rectangle2D.prototype.clone = function () {
    return new Rectangle2D(this.x, this.y, this.width, this.height);
};
Rectangle2D.prototype.toString = function () {
    return 'Rectangle2D(' + this.x + ', ' + this.y + ', ' + this.width + ', ' + this.height + ')';
};

