/*window.onerror = function(msg, url, line){
  alert('Error details' + '\nMessage:' + msg + '\nURL:' + url + '\nLine:' + line);
}*/
// dependency: mootools.js
if (typeof(console) == "undefined") {
    var console = {};
    if (!console.log) {
        console.log = Class.empty();
    }
}

function it_UtilsClass() {
    this.isDateBefore = isDateBefore;
    this.delegate = delegate;
    this.delegateOnlyCustomArgs = delegateOnlyCustomArgs;
    this.exists = exists;
    this.getProperty = getProperty;
    this.createParentDiv = createParentDiv;

    /** only tests the days, not the hours */
    function isDateBefore(baseDate, testedDate) {
        if (testedDate.getFullYear() != baseDate.getFullYear()) { return testedDate.getFullYear() < baseDate.getFullYear(); }
        if (testedDate.getMonth() != baseDate.getMonth()) { return testedDate.getMonth() < baseDate.getMonth(); }
        if (testedDate.getDate() != baseDate.getDate()) { return testedDate.getDate() < baseDate.getDate(); }
    }

    /**
     * . inspired by Tween.js
     * @param scopeObj
     * @param methodNameOrFunction
     * @param arguments (optional): passed when the function is called
     */
    function delegate(scopeObj, functionOrName) {
        var usedFunction = null;
        if (functionOrName instanceof String) {
            usedFunction = scopeObj[functionOrName];
        } else { // functionOrName is a function
            usedFunction = functionOrName;
        }
        var a = new Array();
        for(var i = 2 ; i < arguments.length ; i++){
            a[i - 2] = arguments[i];
        }
        return function() {
            var args = ArrayUtils.concat(arguments, a);
            usedFunction.apply(scopeObj, args);
        };
    }

    function delegateOnlyCustomArgs(scopeObj, functionOrName) {
        var usedFunction = null;
        if (functionOrName instanceof String) {
            usedFunction = scopeObj[functionOrName];
        } else { // functionOrName is a function
            usedFunction = functionOrName;
        }
        var a = new Array();
        for(var i = 2 ; i < arguments.length ; i++){
            a[i - 2] = arguments[i];
        }
        return function() {
            usedFunction.apply(scopeObj, a);
        };
    }

    function exists(element, propertyName) { //:boolean
        if (element == null) {
            return false;
        }
        return typeof(element[propertyName]) != "undefined";
    }

    function getProperty(element, propertyName, defaultValue) {
        if (element == null) {
            return defaultValue;
        }
        var value = element[propertyName];
        return value != null ? value : defaultValue;
    }

    function createParentDiv(div) {
        div = $(div);
        return new Element("div").injectBefore(div).adopt(div);
    }
}
var it_Utils = new it_UtilsClass();

//----------------------------------------------------------------//
//--------------------------Position Utils------------------------//
//----------------------------------------------------------------//
function PositionUtilsClass() {
    this.toPx = toPx;
    this.mouseX = 0;
    this.mouseY = 0;
    this.scrollX = 0;
    this.scrollY = 0;
    this.calculatePos = calculatePos;
    this.setPosition = setPosition;
    this.calculateAndSetPos = calculateAndSetPos;

    var self = this;
    var useDocumentElement = (document.documentElement != null) && (document.documentElement.scrollLeft != null);

    document.onmousemove = _updateMousePos;
    window.onscroll = _updateScrollPos; // avoids flickers that occur if put in updateMousePos

    function _updateMousePos(e) {
        var evt;
        if (window.event != null) {
            evt = event;
        } else {
            evt = e;
        }
        _updateMousePosXInDoc(evt);
        _updateMousePosYInDoc(evt);
    }

    function _updateMousePosXInDoc(evt) { // event is a keyword in IE
        if (evt.pageX) {
            // usually enough
            self.mouseX = evt.pageX;
        } else if (evt.clientX) {
            self.mouseX = evt.clientX + self.scrollX;
        } else {
            self.mouseX = 0;
        }
    }

    function _updateMousePosYInDoc(evt) {
        if (evt.pageY) {
            self.mouseY = evt.pageY;
        } else if (evt.clientY) {
            self.mouseY = evt.clientY + self.scrollY;
        } else {
            self.mouseY = 0;
        }
    }

    function _updateScrollPos() {
        if (document.documentElement.scrollTop) {
            self.scrollX = document.documentElement.scrollLeft;
            self.scrollY = document.documentElement.scrollTop;
        } else {
            self.scrollX = document.body.scrollLeft;
            self.scrollY = document.body.scrollTop;
        }
    }

    function toPx(str) {
        return "" + str + "px";
    }

    // . options (all optional, and $ is used):
    //         . anchorX, anchorY, anchor (anchorX and anchorY)
    //         . offsetX (default 0), offsetY (default 0)
    //         . alignmentX (only with anchorY)
    //             . with targetDiv: "left", "center"
    //            . with anchorX: "anchorXLeft", "anchorXCenter"
    // . targetDiv is the div (or its name) that contains the popup
    function calculatePos(targetDiv, options) {
        var posX, posY;
        if (options != null) {
            // div renferences
            targetDiv   = $(targetDiv);
            if (options.anchor) {
                options.anchorX = options.anchor;
                options.anchorY = options.anchor;
            }
            var anchorX = $(options.anchorX);
            var anchorY = $(options.anchorY);
            // posX
            if (anchorX) {
                posX = anchorX.getLeft() + anchorX.offsetWidth;
            } else {
                posX = this.mouseX;
            }
            if (options.offsetX) {
                posX += options.offsetX;
            }
            // posY
            if (anchorY) {
                posY = anchorY.getTop() + anchorY.offsetHeight;
                if (options.alignmentX) {
                    if (options.alignmentX == "center") {
                        posX -= targetDiv.offsetWidth / 2;
                    } else if (options.alignmentX == "left") {
                        posX -= targetDiv.offsetWidth;
                    } else if (options.alignmentX == "anchorXCenter") {
                        posX -= anchorX.offsetWidth / 2;
                    } else if (options.alignmentX == "anchorXLeft") {
                        posX -= anchorX.offsetWidth;
                    }
                }
            } else {
                posY = this.mouseY;
            }
            if (options.offsetY) {
                posY += options.offsetY;
            }
        } else {
            posX = this.mouseX + 10; // + 10 by security
            posY = this.mouseY + 10;
        }
        // pos security
        if (posX < 0) {
            posX = 0;
        }
        if (posY < 0) {
            posY = 0;
        }
        return {posX: posX, posY: posY};
    }

    function setPosition(element, left, top) {
        var el = $(element);
        if (el.offsetParent) {
            var parentEl = $(el.offsetParent);
            left -= parentEl.getLeft();
            top -= parentEl.getTop();
        }
        el.style.left = left + "px";
        el.style.top = top + "px";
    }

    function calculateAndSetPos(targetElement, options) {
        var pos = this.calculatePos(targetElement, options);
        this.setPosition(targetElement, pos.posX, pos.posY);
    }
}
// simulates static methods
var PositionUtils = new PositionUtilsClass();


//----------------------------------------------------------//
//-----------------------Array Classes----------------------//
//----------------------------------------------------------//
// usefull because 'in' and 'delete' operators have limitation (no delete obj[key])
// concat is ok (IE4+)
function ArrayUtilsClass() {
    this.add = push;
    this.addAll = addAll;
    this.concat = concat;
    this.clone = clone;
    this.push = push;
    this.unshift = unshift;
    this.remove = remove;
    this.indexOf = indexOf;
    this.contains = contains;

    function push(array, value) {
        array[array.length] = value;
    }
    function addAll(destArray, sourceArray) {
        for (var i = 0; i < sourceArray.length; i++) {
            this.push(destArray, sourceArray[i]);
        }
    }
    function concat(array1, array2) { // :Array
        var ret = new Array();
        this.addAll(ret, array1);
        this.addAll(ret, array2);
        return ret;
    }
    function clone(array) { // :Array
        var newArray = new Array(array.length);
        this.addAll(newArray, array);
        return newArray;
    }
    function unshift(array, value) {
        var lg = array.length;
        var currentValue = value;
        var i = 0;
        for (; i < lg; i++) {
            var nextValue = array[i];
            array[i] = currentValue;
            currentValue = nextValue;
        }
        array[i] = currentValue;
    }
    /** removes the element and offsets the end of the array to fill the blank **/
    function remove(array, element) {
        var elementFound = false;
        var length = array.length;
        for (var i = 0; i < length; i++) {
            if (!elementFound) {
                if (array[i] == element) {
                    elementFound = true;
                }
            } else {
                array[i-1] = array[i];
            }
        }
        if (elementFound && length != 0) {
            array.length = array.length - 1;
        }
    }
    function indexOf(array, element) { // :int
        for (var i = 0; i < array.length; i++) {
            if (array[i] == element) {
                return i;
            }
        }
        return -1;
    }
    function contains(array, element) { // :boolean
        return indexOf(array, element) != -1;
    }
}
// simulates static methods
var ArrayUtils = new ArrayUtilsClass();

// arrayOut is optional
function ArrayBuilder(arrayOut) {
    if (arrayOut == null) {
        this.arrayOut = new Array();
    } else {
        this.arrayOut = arrayOut;
    }

    this.push = push;
    this.unshift = unshift;

    // the return this allows the user to write push(...).push(...)
    function push(value) {
        ArrayUtils.push(this.arrayOut, value);
        return this;
    }

    function unshift(value) {
        ArrayUtils.unshift(this.arrayOut, value);
        return this;
    }
}

//----------------------------------------------------------//
//----------------------String Classes----------------------//
//----------------------------------------------------------//
function StringUtilsClass() {
    this.isEmpty = isEmpty;
    this.trim = trim;
    this.startsWith = startsWith;
    this.endsWith = endsWith;

    function isEmpty(str) {
        return str == undefined || str == null || str.length == 0;
    }

    function trim(value, maxSize, options) {
        if (maxSize != null && value.length > maxSize) {
            var withDots = (options != null && options.withDots);
            var withSpan = (options != null && options.withSpan);
            var strBuilder = new StringBuilder();
            if (withSpan) {
                strBuilder.append('<span title="').append(value).append('">');
            }
            strBuilder.append(withDots ? value.substring(0, maxSize - 3) : value.substring(0, maxSize));
            if (withDots) {
                strBuilder.append("...");
            }
            if (withSpan) {
                strBuilder.append("</span>")
            }
            return strBuilder.toString();
        } else {
            return value;
        }
    }

    function startsWith(bigStr, smallStr) {
        return _startsWithInternal(bigStr, smallStr, 0);
    }

    function endsWith(bigStr, smallStr) {
        return _startsWithInternal(bigStr, smallStr, bigStr.length - smallStr.length);
    }

    // private static
    function _startsWithInternal(bigStr, smallStr, offset) {
        if (smallStr.length + offset > bigStr.length) {
            return false;
        }
        for (var i = 0; i < smallStr.length; i++) {
            if (bigStr.charAt(i + offset) != smallStr.charAt(i)) {
                return false;
            }
        }
        return true;
    }
}
var StringUtils = new StringUtilsClass();

function StringBuilder() {
    this.arrayBuilder = new ArrayBuilder(new Array());

    this.append = append;
    this.a = append;
    this.appendIfNotEmpty = appendIfNotEmpty;
    this.appendArray = appendArray;
    this.toString = toString;

    var trimOptions = { withDots:true, withSpan:true };

    function append(value, maxSize) {
        if (maxSize != null) {
            value = StringUtils.trim(value, maxSize, trimOptions);
        }
        this.arrayBuilder.push(value);
        return this;
    }
    function appendIfNotEmpty(value, maxSize) {
        if (!StringUtils.isEmpty(value)) {
            return this.append(value, maxSize);
        } else {
            return this;
        }
    }
    function appendArray(array, maxSize) {
        if (array == null) {
            return this;
        }
        var strBuilder = new StringBuilder();
        for (var i=0; i<array.length; i++) {
            if (i>0) {
                strBuilder.append(", ");
            }
            strBuilder.append(array[i]);
        }
        var value = strBuilder.toString();
        value = StringUtils.trim(value, maxSize, trimOptions);
        this.append(value);
        return this;
    }
    function toString() {
        return this.arrayBuilder.arrayOut.join("");
    }
}
//---------------------------------------------------------//

/*
example of data (it handles array and indexation):
            var selectData = new Array();
            selectData[0] = [ "FR", "France", [
                [ "PAR", "Paris" ],
                [ "LYS", "Lyon" ]
            ]];
            selectData.FR = selectData[0];
            selectData[1] = [ "IT", "Italie", [
                [ "BLQ", "Bologne" ],
                [ "MIL", "Milan" ],
                [ "ROM", "Rome" ]
            ]];
            selectData.IT = selectData[1];
*/
function it_SelectClass() {
    this.fill = fill;

    function fill(selectDivOrName, data, selectedCode) {
        var select = $(selectDivOrName);
        select.options.length = 0;
        for (var i = 0; i < data.length; i++) {
            var valuePair = data[i];
            select.options[i] = new Option(valuePair[1], valuePair[0]); // text and code
            if (selectedCode != null && valuePair[0] == selectedCode) {
                select.selectedIndex = i;
            }
        }
    }
}
var it_Select = new it_SelectClass();

function SelectPair(masterSelect, slaveSelect, data) {
    var master = $(masterSelect);
    var slave = $(slaveSelect);
    var data = data;

    this.initMaster = initMaster;
    this.updateSlave = updateSlave;

    function initMaster(masterSelCode, slaveSelCode) {
        it_Select.fill(master, data, masterSelCode); // only uses the first 2 strings
        master.onchange = it_Utils.delegate(this, this.updateSlave);
        updateSlave(slaveSelCode);
    }
    /**
     * selectedCode can be null
     */
    function updateSlave(selectedCode) {
        slave.options.length = 0;
        var masterValue = master.options[master.selectedIndex].value;
        var slaveData = data[masterValue][2]; // after the master code and text
        it_Select.fill(slave, slaveData, selectedCode);
    }
}

/**
 * masterServiceName can be null (if the options are put by a jsp)
 */
function it_AjaxSelectPair(masterSelect, slaveSelect, serviceUrl, masterServiceName, slaveServiceName) {
    var master = $(masterSelect);
    var slace = $(slaveSelect);

    this.initMaster = initMaster;
    this.updateSlave = updateSlave;

    function initMaster() {
        master.onchange = it_Utils.delegate(this, this.updateSlave);
    }
    function updateSlave() {

    }
}

function it_AjaxClass() {
    /** static (some private methods are still made properties so that they can be overridden */
    this.sendValue = sendValue;
    this._onComplete = _onComplete;
    this._showMessage = _showMessage;
    this._showError = _showError;

    /**
     * serviceUrl: must be absolute
     */
    function sendValue(serviceUrl, commandName, options, param1Name, param1Value, param2Name, param2Value) {
        options = Object.extend({callback: Class.empty}, options || {});
        var params = new StringBuilder();
        _addParam(params, "cmd", commandName);
        if (!StringUtils.isEmpty(param1Name)) {
            params.a("&");
            _addParam(params, param1Name, param1Value);
            if (!StringUtils.isEmpty(param2Name)) {
                params.a("&");
                _addParam(params, param2Name, param2Value);
            }
        }
        new Ajax(serviceUrl,
            {postBody: params.toString(),
            onComplete: it_Utils.delegate(this, this._onComplete, options.callback),
            onFailure: it_Utils.delegateOnlyCustomArgs(this, this._showError, "Erreur inconnue")})
        .request();
    }

    /** static */
    function _addParam(builder, name, value) {
        builder.a(encodeURIComponent(name)).a("=").a(encodeURIComponent(value));
    }

    function _onComplete(responseText, responseXml, callback) {
        var response = eval('(' + responseText + ')');
        if (it_Utils.exists(response, "error")) {
            this._showError(response.error);
            return;
        }
        if (it_Utils.exists(response, "error")) {
            this._showMessage(response.message);
        }
        callback(response.content);
    }

    function _showMessage(message) {
        alert(message); // may change in the future (with a status bar for instance)
    }
    function _showError(errorMessage) {
        alert("Erreur: " + errorMessage);
    }
}
var it_Ajax = new it_AjaxClass();

//---------------------------------------------------------------//
//------------------------------Flash-----------------------------//
//----------------------------------------------------------------//
function it_writeFlash(path, id, width, height) {
    var source = '<OBJECT id="' + id + '" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" width="' + width + '" height="' + height + '" align="middle">\n'
    + '<param name="allowScriptAccess" value="never" />\n'
    + '<PARAM name="movie" value="' + path + '" />\n'
    + '<param name="loop" value="false" />\n'
    + '<param name="menu" value="false" />\n'
    + '<param name="quality" value="high" />\n'
    + '<param name="scale" value="noscale" />\n'
    + '<param name="salign" value="lt" />\n'
    + '<param name="wmode" value="transparent" />\n'
    + '<embed name="' + id + '" swLiveConnect="false" src="' + path + '" wmode="transparent" loop="false" menu="false" quality="high" scale="noscale" salign="lt" width="' + width + '" height="' + height + '" align="top" allowScriptAccess="never" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />\n'
    + '</OBJECT>\n';
    document.write(source);
}

var it_IE = (navigator.appName == 'Microsoft Internet Explorer');

/** async loading of frames (IE bug) */
function it_frameLoaderClass() {
    var frameNames = new Array();
    var locations = new Array();

    this.add = add;
    this.loadFrames = loadFrames;
    this._loadFramesImpl = _loadFramesImpl;

    function add(frameName, location) {
        ArrayUtils.push(frameNames, frameName);
        ArrayUtils.push(locations, location);
    }

    function loadFrames() {
        if (it_IE && parent.frames.length > 1) { // using IE and in a frame
            setTimeout(it_Utils.delegate(this, _loadFramesImpl), 2000);
        } else {
            this._loadFramesImpl();
        }
    }

    function _loadFramesImpl() {
        for (var i = 0; i < frameNames.length; i++) {
            // console.log("frame named: " + frameNames[i] + ", " + frames[frameNames[i]])
            frames[frameNames[i]].location.href = locations[i];
        }
    }
}
var it_frameLoader = new it_frameLoaderClass();
