if (!Array.prototype.getLastIndex) {
    Array.prototype.getLastIndex = function() {
        return this.length - 1;
    }
}

if (!Array.isOutOfBounds) {
    Array.prototype.isOutOfBounds = function(index) {
        if ((index < 0)
                || (this.getLastIndex() < index)) {
            return true;
        }
        
        return false;
    }
}

if (!Array.prototype.push) {
    Array.prototype.push = function() {
        var startLength = this.length;
        for (var i = 0; i < arguments.length; i++)
        this[startLength + i] = arguments[i];
        return this.length;
    }
}

if (!Array.prototype.insertAt) {
    Array.prototype.insertAt = function(newElement, position) {
        var index = position - 1;
        
        if (this.length < index) {
            index = this.getLastIndex();
        }
        
        if (index < 0) {
            index = 0;
        }
        
        if (index == 0) {
            this.unshift(newElement);
            return true;
        }
        
        if (index > this.getLastIndex()) {
            this.push(newElement);
            return true;
        }
        
        
        var part1 = this.slice(0, index);
        var part2 = this.slice(index);
        
        this.length = 0;
        
        var sz = null;
        var i = null;
        
        sz = part1.length;
        for (i = 0; i < sz; i++) {
            this.push(part1[i]);
        }
        
        this.push(newElement);
        
        sz = part2.length;
        for (i = 0; i < sz; i++) {
            this.push(part2[i]);
        }
        
        return true;
    }
}


if (!Array.prototype.execute) {
    Array.prototype.execute = function (aFunction) {
        var i = 0;
        for (i = 0; i < this.length; i++) {
            aFunction(this[i], this);
        }
    }
}

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (searchElement) {
        var sz = this.length;
        
        if (sz < 1) {
            return -1;
        }
        
        var fromIndex = (arguments.length > 1) ? arguments[1] : 0;
        fromIndex = Number.parse.integer(fromIndex, 0);
        fromIndex = (this.getLastIndex() < fromIndex) ? 0 : fromIndex;
        if (fromIndex < 0) {
            fromIndex = Math.abs(fromIndex);
            fromIndex = sz - fromIndex;
            while (fromIndex < 0) {
                fromIndex = sz - fromIndex;
                fromIndex = Math.abs(fromIndex);
            }
        }
        
        
        for (var i = fromIndex; i < sz; i++) {
            if (this[i] === searchElement) {
                return i;
            }
        }
        
        return -1;
    }
}


if (!Array.prototype.lastIndexOf) {
    Array.prototype.lastIndexOf = function (searchElement) {
        var sz = this.length;
        
        if (sz < 1) {
            return -1;
        }
        
        var fromIndex = (arguments.length > 1) ? arguments[1] : 0;
        fromIndex = Number.parse.integer(fromIndex, 0);
        fromIndex = (this.getLastIndex() < fromIndex) ? 0 : fromIndex;
        if (fromIndex < 0) {
            fromIndex = Math.abs(fromIndex);
            fromIndex = sz - fromIndex;
            while (fromIndex < 0) {
                fromIndex = sz - fromIndex;
                fromIndex = Math.abs(fromIndex);
            }
        }
        
        
        for (var i = (sz - 1); fromIndex <= i; i--) {
            if (this[i] === searchElement) {
                return i;
            }
        }
        
        return -1;
    }
}


if (!String.random) {
    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;
    }
}

if (!String.prototype.getPrefixedWord) {
    String.prototype.getPrefixedWord = function() {
        var returnExtracted = true;
        var prefix = '';
        var suffix = '';
        
        if (2 < arguments.length) {
            returnExtracted = (arguments[2] == true) ? true : false;
            
        } else if (arguments.length == 1) {
            prefix = (arguments[0] == null) ? '' : arguments[0];
            suffix = (arguments[1] == null) ? '' : arguments[1];
            
        } else if (arguments.length == 0) {
            prefix = (arguments[0] == null) ? '' : arguments[0];
            
        }
        
        if ((prefix == '')
                && (suffix == '')) {
            return '';
        }
        
        var founded = null;
        
        var tmp = this.split(' ');
        
        if (tmp.length < 1) {
            if ((this.startsWith(prefix) == false)
                    || (this.endsWith(suffix) == false)) {
                return null;
            }
            
            if (returnExtracted == false) {
                return this;
            }
            
            return this.unQuote(prefix, suffix);;
        }
        
        var sz = tmp.length;
        var i = 0;
        var cur = null;
        
        for (i = 0; i < sz; i++) {
            cur = tmp[i];
            
            if ((cur.startsWith(prefix) == false)
                    || (cur.endsWith(suffix) == false)) {
                continue;
            }
            
            founded = cur;
            break;
        }
        
        if (founded == null) {
            return null;
        }
        
        if (returnExtracted == false) {
            return founded;
        }
        
        
        
        return founded.unQuote(prefix, suffix);
    }


}

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

if (!String.prototype.addWord) {
    String.prototype.addWord = function(word) {
        if (this == "") {
            return word;
        }
        
        if (this.findWord(word) == true) {
            return this;
        }
        
        return this + " " + word;
    }
}

if (!String.prototype.removeWord) {
    String.prototype.removeWord = function(word) {
        var pattern = "(^| )" + word + "\W*";
        var re = new RegExp(pattern);
        
        return this.replace(re, "");
    }
}

if (!String.prototype.reverse) {
    String.prototype.reverse = function() {
        var result = "";
        
        var start = this.length - 1;
        
        var i = 0;
        
        for (i = start; i >= 0; i--) {
            result += this.charAt(i);
        }
        
        return result;
    }
}

if (!String.prototype.rtrim) {
    String.prototype.rtrim = function() {
        var sz = this.length;
        
        if (sz < 1) {
            return '';
        }
        
        return this.replace(/\s+$/, '');
        
    }
}

if (!String.prototype.ltrim) {
    String.prototype.ltrim = function() {
        var sz = this.length;
        
        if (sz < 1) {
            return '';
        }
        
        return this.replace(/^\s+/, '');
        
        
    }
}

if (!String.prototype.trim) {
    String.prototype.trim = function() {
        if (this.length < 1) {
            return '';
        }
        
        var result = this.rtrim();
        
        return result.ltrim();
        
    }
}

if (!String.prototype.startsWith) {
    String.prototype.startsWith = function(prefix) {
        return (this.indexOf(prefix) === 0);
    }
}

if (!String.prototype.endsWith) {
    String.prototype.endsWith = function(suffix) {
        var startPos = this.length - suffix.length;
        
        if (startPos < 0) {
          return false;
        }
        
        return (this.lastIndexOf(suffix, startPos) == startPos);
    }
}


if (!String.prototype.getPathInfo) {
    String.prototype.getPathInfo = function() {
        if (this.length < 1) {
            return null;
        }
        
        var suffixSeparator = '_';
        var tmp = null;
        var lastPos1 = 0;
        var lastPos2 = 0;
        
        switch (arguments.length) {
            case 1 : {
                tmp = new String(arguments[0]);
                
                lastPos1 = this.lastIndexOf(suffixSeparator);
                lastPos2 = this.lastIndexOf(tmp);
                
                if (lastPos1 < lastPos2) {
                    suffixSeparator = tmp;
                }
                
            } break;
            
            default : {
                // do nothing
            } break;
        }
        
        var part = this.split('/');
        var fileName = part.pop();
        var path = part.join('/');
        
        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;
                    }
            }
        
    }
}

if (!String.prototype.unQuote) {
    String.prototype.unQuote = function () {
        if (this.length < 1) {
            return '';
        }
        
        var quote = new Array();
        quote.push(['"', '"']);
        quote.push(["'", "'"]);
        
        switch (arguments.length) {
            case 2 : {
                quote = new Array();
                quote.push([arguments[0], arguments[1]]);
                
            } break;
            
            case 1 : {
                if (typeof arguments[0] == 'array') {
                    quote = arguments[0];
                    break;
                }
                
                quote = new Array();
                quote.push([arguments[0], arguments[0]]);
                
            } break;
            
            default : {
                
            } break;
            
        }
        
        var result = new String(this);
        var sz = quote.length;
        var i = 0;
        var firstPart = null;
        var lastPart = null;
        
        for (i = 0; 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;
    }
}


if (!String.prototype.capitalize) {
    String.prototype.capitalize = function ( ) {
        if (this.length < 1) {
            return '';
        }
        
        if (this.length == 1) {
            return this.toUpperCase();
        }
        
        return this.charAt(0).toUpperCase() + this.substr(1);
    }
}

if (!String.prototype.normalizeCodeVariable) {
    String.prototype.normalizeCodeVariable = function () {
        if (this.length < 1) {
            return '';
        }
        
        if (this.length == 1) {
            return this.toLowerCase();
        }
        
        var result = '';
        
        var tmp = this.split('-');
        var sz = tmp.length;
        var i = 0;
        
        for (i = 0; i < sz; i++) {
            
            result += tmp[i].capitalize();
        }
        
        tmp = result.split('_');
        result = '';
        sz = tmp.length;
        for (i = 0; i < sz; i++) {
            result += tmp[i].capitalize();
        }
        
        return result.charAt(0).toLowerCase() + result.substr(1);
        
    }
}


if (!String.prototype.replaceAll) {
    String.prototype.replaceAll = function(re, replaceText) {
        if (this.length < 1) {
            return '';
        }
        var sz = this.length;
        var currentIteration = -1;
        
        var result = new String(this);
        
        while (0 <= result.search(re)) {
            result = result.replace(re, replaceText);
            
            currentIteration++;
            if (sz < currentIteration) {
                return new String(this);
            }
            
        }
        
        return result;
    }
}


if (!Number.parse) {
    Number.parse = {
        integer : function (data) {
                var defaultValue = null;
                var hasDefaultValue = false;
                var radix = 10;
                
                switch (arguments.length) {
                    case 3 : {
                        radix = arguments[2];
                    }
                    
                    case 2 : {
                        defaultValue = arguments[1];
                        hasDefaultValue = true
                    } break;
                    
                    default : {
                    
                    } break;
                    
                }
                
                
                if (hasDefaultValue != true) {
                    return parseInt(data, radix);
                }
                
                if (data === null) {
                    return defaultValue;
                }
                
                var result = parseInt(data, radix);
                
                if (isNaN(result) == true) {
                    return defaultValue;
                }
                
                return result;
            },
        reel : function (data) {
                var defaultValue = null;
                var hasDefaultValue = false;
                
                switch (arguments.length) {
                    
                    case 2 : {
                        defaultValue = arguments[1];
                        hasDefaultValue = true
                    } break;
                    
                    default : {
                    
                    } break;
                    
                }
                
                if (hasDefaultValue != true) {
                    return parseFloat(data);
                }
                
                if (data === null) {
                    return defaultValue;
                }
                
                var result = parseFloat(data);
                
                if (isNaN(result) == true) {
                    return defaultValue;
                }
                
                return result;
            }
        }
    
}

function TreeMap() {
    this.values = new Array();
    this.keys = new Array();
    
    this.currentIndex = 0;
    
}

TreeMap.prototype.getKeyIndex = function(name) {
    var sz = this.keys.length;
    var i = 0;
    
    for (i = 0; i < sz; i++) {
        if (this.keys[i] == name) {
            return i;
        }
    }
    
    return -1;
}


TreeMap.prototype.has = function(name) {
    if (this.getKeyIndex(name) < 0) {
        return false;
    }
    
    return true;
}

TreeMap.prototype.set = function(name, value) {
    var ki = this.getKeyIndex(name);
    if (ki < 0) {
        // il s'agit d'un ajout
        this.keys.push(name);
        ki = this.getKeyIndex(name);
        this.values[ki] = value;
        
        return;
    }
    
    // il s'agit d'un remplacement
    this.values[ki] = value;
}

TreeMap.prototype.get = function(name) {
    var ki = this.getKeyIndex(name);
    if (ki < 0) {
        return null;
    }
    
    return this.values[ki];
}

TreeMap.prototype.remove = function(name) {
    var ki = this.getKeyIndex(name);
    if (ki < 0) {
        return false;
    }
    
    this.keys.splice(ki, 1);
    this.values.splice(ki, 1);
    
    return true;
}


TreeMap.prototype.isValidIndex = function(i) {
    if (this.keys.length < 1) {
        return false;
    }
    
    if (i < 0) {
        return false;
    }
    
    if (i < this.keys.length) {
        return true;
    }
    
    return false;
}

TreeMap.prototype.current = function() {
    if (this.valid() == false) {
        return null;
    }
    
    return this.get(this.key());
}


TreeMap.prototype.key = function() {
    if (this.valid() == false) {
        return null;
    }
    
    return this.keys[this.currentIndex];
}

TreeMap.prototype.next = function() {
    this.currentIndex++;
}

TreeMap.prototype.rewind = function() {
    this.currentIndex = 0;
}

TreeMap.prototype.valid = function() {
    return this.isValidIndex(this.currentIndex);
}


function GlobalScope () {}

GlobalScope.getInstance = function () {
    if (!this.instance) {
        this.instance = new TreeMap();
    }
    
    return this.instance;
}


function Point2D () {
    var defaultY = 0;
    var defaultX = 0;
    
    switch (arguments.length) {
        case 2 : {
            defaultY = Number.parse.integer(arguments[1], defaultY);
        }
        
        case 1 : {
            defaultX = Number.parse.integer(arguments[0], defaultX);
            
        } break;
        
        default : {
        
        } break;
        
    }
    
    this.x = defaultX;
    this.y = defaultY;
}

Point2D.prototype.clone = function () {
    return new Point2D(this.x, this.y);
}

function Vector2D () {
    this.angle = 0;
    this.force = 0;
    
    this.cx = 0;
    this.cy = 0;
}

Vector2D.ANGLE_TO_RIGHT = 0;
Vector2D.ANGLE_TO_RIGHT_UP = 45;
Vector2D.ANGLE_TO_TOP = 90;
Vector2D.ANGLE_TO_LEFT_UP = 135;
Vector2D.ANGLE_TO_LEFT = 180;
Vector2D.ANGLE_TO_LEFT_BOTTOM = 225;
Vector2D.ANGLE_TO_BOTTOM = 270;
Vector2D.ANGLE_TO_RIGHT_BOTTOM = 315;

Vector2D.prototype.defineAngle = function (angle, force) {
    if (angle != null) {
        this.angle = Number.parse.integer(angle, this.angle);
        this.angle = Number.abs(this.angle);
        this.angle = (this.angle % 360);
    }
    
    if (force != null) {
        this.force = Number.parse.integer(force, this.force);
    }
    
    return this.calculatesFromAngle();
}

Vector2D.prototype.defineSize = function (cx, cy) {
    if (cx != null) {
        cx = Number.parse.integer(cx, this.cx);
    }
    
    if (cy != null) {
        cy = Number.parse.integer(cy, this.cy);
    }
    
    return this.calculatesFromSize();
}


Vector2D.prototype.calculatesFromAngle = function () {
    if (this.force == 0) {
        this.cy = 0;
        this.cx = 0;
        return false;
    }
    
    var ang = (this.angle % 90);
    
    if (ang == 0) {
        // il s'agit d'un angle droit...
        switch (this.angle) {
            case Vector2D.ANGLE_TO_RIGHT : {
                this.cx = this.force;
                this.cy = 0;
            } break;
            case Vector2D.ANGLE_TO_TOP : {
                this.cx = 0;
                this.cy = this.force;
            } break;
            case Vector2D.ANGLE_TO_LEFT : {
                this.cx = this.force * -1;
                this.cy = 0;
            } break;
            case Vector2D.ANGLE_TO_BOTTOM : {
                this.cx = 0;
                this.cy = this.force * -1;
            } break;
        }
        
        return true;
    }
    
    this.cx = Math.cos(this.angle) * Math.abs(this.force);
    this.cy = Math.sin(this.angle) * Math.abs(this.force);
    
    if (this.angle > Vector2D.ANGLE_TO_BOTTOM) {
        this.cy = (this.cy * -1);
        
    } else if (this.angle > Vector2D.ANGLE_TO_LEFT) {
        this.cx = (this.cx * -1);
        this.cy = (this.cy * -1);
        
        
    } else if (this.angle > Vector2D.ANGLE_TO_TOP) {
        this.cx = (this.cx * -1);
        
    }
    
    return true;
}


Vector2D.prototype.calculatesFromSize = function () {
    if ((this.cx == 0)
            && (this.cy == 0)) {
        this.force = 0;
        return false;
    }
    
    var tmpCX = Math.abs(this.cx);
    var tmpCY = Math.abs(this.cy);
    
    
    if (tmpCX == 0) {
        if (0 <= this.cy) {
            this.angle = Vector2D.ANGLE_TO_TOP;
        } else {
            this.angle = Vector2D.ANGLE_TO_BOTTOM;
        }
        
    } else if (tmpCY == 0) {
        if (0 <= this.cx) {
            this.angle = Vector2D.ANGLE_TO_RIGHT;
            
        } else {
            this.angle = Vector2D.ANGLE_TO_Left;
            
        }
        
        
    }
    
    var hypo = Math.sqrt((tmpCX * tmpCX) + (tmpCY * tmpCY));
    
    if (isNaN(result) == true) {
        this.cx = 0;
        this.cy = 0;
        return false;
    }
    
    var ang = Math.acos(tmpCX / hypo);
    
    this.force = Number.parse.integer(hypo);
    
    if (0 <= this.cx) {
        if (0 <= this.cy) {
            this.angle = ang;
            
        } else {
            this.angle = 360 - ang;
            
        }
    } else {
        if (0 <= this.cy) {
            this.angle = 180 - ang;
            
        } else {
            this.angle = 270 - ang;
            
        }
        
        
    }
    
    
    return true;
}

Vector2D.prototype.apply = function (x, y) {
    return new Point2D (x + this.cx, y + this.cy);
    
}


