var timeCalculator = function() {
    // Different states
    var ENTER_TIME = 1;
    var SHOW_TIME  = 2;
    var ENTER_LAPS = 3;
    var SHOW_SPEED = 4;

    // Different buttons
    var NO_BUTTON        = 0;
    var BUTTON_EQUALS    = 1;
    var BUTTON_DISTANCE  = 2;
    var BUTTON_MULTIPLY  = 3;
    var BUTTON_DEVIDE    = 4;
    var BUTTON_ADD       = 5;
    var BUTTON_SUBSTRACT = 6;

    // If a time is negative we show a minus-sign
    var NEGATIVE = "- ";

    // Display info's
    var DISPINFO_MULTIPLY  = "x";
    var DISPINFO_DEVIDE    = "/";
    var DISPINFO_ADD       = "+";
    var DISPINFO_SUBSTRACT = "-";

    // Global variables
    var _TimeInMempory = 0.0;
    var _CurrentTime = 0.0;
    var _TimeInput = "";
    var _LapsInput = "";
    var _Dot1Index = 0;
    var _Dot2Index = 0;
    var _NumberOfDots = 0;
    var _CurrentState = ENTER_TIME;
    var _LastButtonClicked = NO_BUTTON;

    return {
        helpClick : function () {
           	dijit.byId('time_calculator_help').show();
        },

        seconds2time : function (flSeconds) {
            var strHours = "";
            var strMilliseconds = "";
            var strMinutes = "";
            var strSeconds = "";
            var seconds = 0;
            var minutes = 0;
            var hours = 0;

            // De fractie ronden we af op 2 cijfers
            strMilliseconds = (Math.round(flSeconds * 100.0) % 100).toString();
            strMilliseconds = (strMilliseconds.length === 1) ? "0" + strMilliseconds : strMilliseconds;

            // De seconds zonder de fractie
            seconds = Math.floor(flSeconds);

            // Minuten is het aantal seconden delen door 60
            minutes = Math.floor(seconds/60);

            // Hebben we zelfs ook nog uren ?
            hours = Math.floor(minutes/60);
            if (hours > 0) {
                strHours = hours.toString() + ":";
                strMinutes = (minutes % 60).toString();
                strMinutes = ((strMinutes.length === 1) ? "0" : "") + strMinutes;
            } else {
                strMinutes = minutes.toString();
            }

            // Het aantal seconden is rest bij delen door 60
            strSeconds = (seconds % 60).toString();
            strSeconds = ((strSeconds.length === 1) ? "0" : "") + strSeconds;

            // Maak the string op H:MM.SS.ss
            return strHours + strMinutes + "." + strSeconds + "." + strMilliseconds;
        },

        dspClick : function () {
            document.timecalc.dsp.select();
        },

        clearAll : function () {
            this.clearInputVariables();
            this.showTime("0");
            _TimeInMempory = 0;
            _CurrentTime = 0;
            _CurrentState = ENTER_TIME;
            _LastButtonClicked = NO_BUTTON;
        },

        clearEntry : function () {
            if (_CurrentState === ENTER_TIME || _CurrentState === ENTER_LAPS) {
                this.showTime("0");
                this.clearInputVariables();
            } else {
                this.clearAll();
            }
        },

        clearInputVariables : function () {
            _LapsInput = "";
            _TimeInput = "";
            _Dot1Index = 0;
            _Dot2Index = 0;
            _NumberOfDots = 0;
        },

        time2seconds : function (timeString) {
            // Deze functie berekent de ingevoerde tijd in seconden
            var hours = 0;
            var minutes = 0;
            var seconds = 0;
            var sseconds = 0;
            var strSs = "0";
            var dot1Index = -1;
            var dot2Index = -1;
            var numerOfDots = 0;
            var isNegative = false;
            var hoursDelimiterPos = -1;

            if (timeString.substring(0,2) === NEGATIVE) {
                isNegative = true;
                timeString = timeString.substring(2);
            }

            hoursDelimiterPos = timeString.indexOf(":");
            if (hoursDelimiterPos > -1) {
                hours = parseInt(timeString.substr(0, hoursDelimiterPos), 10);
                timeString = timeString.substring(hoursDelimiterPos+1);
            }

            // Analyse the given timeString on dots
            for (var i=0; i<timeString.length; i++) {
                if (timeString.substring(i,i+1) === '.') {
                    numerOfDots++;
                    if (numerOfDots === 1) {
                        dot1Index = i;
                    } else {
                        dot2Index = i;
                    }
                }
            }

            switch (numerOfDots) {
                case 0:
                    // Input bevat alleen minuten: MM.00.00
                    if (timeString !== "") {
                        minutes = parseInt(this.leftZeroTrim(timeString), 10);
                    }
                    seconds = 0;
                    strSs = "00";
                    break;
                case 1:
                    // Input bevat alleen minuten en seconden, geen cijfers achter de komma: MM.SS.00
                    minutes = parseInt(this.leftZeroTrim(timeString.substring(0,dot1Index)), 10);
                    seconds = timeString.substring(dot1Index+1);
                    seconds = seconds + ((seconds.length === 1) ? "0" : "");
                    strSs = "00";
                    break;
                case 2:
                    // Input bevat minuten, seconden en cijfers achter de komma: MM.SS.ss
                    minutes = parseInt(this.leftZeroTrim(timeString.substring(0,dot1Index)), 10);
                    seconds = parseInt(this.leftZeroTrim(timeString.substring(dot1Index+1,dot2Index)), 10);
                    strSs = timeString.substring(dot2Index+1);
                    break;
                default:
                    break;
            }

            strSs = (strSs.length < 2) ? strSs + "0" : strSs;
            sseconds = parseInt(this.leftZeroTrim(strSs), 10);
            return ((isNegative ? -1.0 : 1.0) * ((hours * 60.0 * 60.0) + (minutes * 60.0) + (seconds * 1.0) + (sseconds / 100.0)));
        },

        leftZeroTrim : function (sString) {
            while (sString.substring(0,1) === '0' && sString.length > 1) {
                sString = sString.substring(1, sString.length);
            }
            return sString;
        },

        numClick : function (number) {
            // De input (tijd) kan maximaal 8 karakters lang zijn (inclusief punten): MM.SS.ss
            // Voorloopnullen doen we niet aan, alleen tijden in de vorm van bijvoorbeeld 0.11
            // Het 1e cijfer na de 1e punt mag niet groter zijn dan 5 (zie periodClick)
            // Voor de 1e punt mogen maximaal 2 cijfers staan
            // Na een punt mogen maxmaal 2 cijfers staan
            // Tussen de 1e en 2e punt moeten precies 2 cijfers staan

            if (_CurrentState === SHOW_SPEED) {
                // Na het tonen van snelheid altijd weer een nieuwe time-entry
                this.clearAll();
            } else if (_CurrentState === SHOW_TIME && _LastButtonClicked !== BUTTON_ADD && _LastButtonClicked !== BUTTON_SUBSTRACT) {
                // De gebruiker begin weer aan een nieuwe time-entry
                this.clearAll();
            } else if (_CurrentState === SHOW_TIME && (_LastButtonClicked === BUTTON_ADD || _LastButtonClicked === BUTTON_SUBSTRACT)) {
                // De gebruiker begin weer aan een nieuwe time-entry
                this.clearInputVariables();
                _CurrentState = ENTER_TIME;
            }

            if (_CurrentState === ENTER_TIME && _TimeInput.length < 9 && (_TimeInput.length > 0 || number > '0')) {
                if (_TimeInput.length < 2 && _NumberOfDots === 0) {
                    // Als het goed is, is er nog geen punt ingevoerd
                    _TimeInput += number;
                } else {
                    if ((_TimeInput.length - (_Dot1Index+1)) < 2 && _NumberOfDots === 1) {
                        _TimeInput += number;
                    } else {
                        if ((_TimeInput.length - (_Dot2Index+1)) < 2 && _NumberOfDots === 2) {
                            _TimeInput += number;
                        }
                    }
                }
                this.showTime(_TimeInput.substring(0,_TimeInput.length));

            } else if (_CurrentState === ENTER_LAPS && _LapsInput.length < 3 && (_LapsInput.length > 0 || number > '0')) {

                // Als we een aatal ronden invoeren, mogen er geen punten worden ingevoerd.
                // Het aantal ronden mag niet meer dan 3 cijfers (999).
                _LapsInput += number;
                this.showTime(_LapsInput.substring(0,_LapsInput.length));

            } else if (_CurrentState !== ENTER_LAPS && _CurrentState !== ENTER_TIME){
                this.showTime("Error");
                _CurrentState = SHOW_TIME;
                _LastButtonClicked = NO_BUTTON;
            }
        },

        multiplyClick : function () {
            this.mClick(BUTTON_MULTIPLY);
        },

        devideClick : function () {
            this.mClick(BUTTON_DEVIDE);
        },

        mClick : function (buttonPressed) {
            if (_CurrentState === SHOW_TIME) {
                _CurrentState = ENTER_LAPS;
                _CurrentTime = this.time2seconds(document.timecalc.dsp.value);
                this.clearInputVariables();
                _LastButtonClicked = buttonPressed;
                this.showTime(_CurrentTime,buttonPressed);
            } else if (_CurrentState === ENTER_TIME) {
                _CurrentState = ENTER_LAPS;
                _CurrentTime = this.time2seconds(_TimeInput);
                this.clearInputVariables();
                _LastButtonClicked = buttonPressed;
                this.showTime(_CurrentTime,buttonPressed);
            } else if (_CurrentState === ENTER_LAPS) {
                if (_LapsInput !== "0" && _LapsInput !== "") {
                    _CurrentState = ENTER_LAPS;
                    if (buttonPressed === BUTTON_DEVIDE) {
                        _CurrentTime = _CurrentTime / parseFloat(_LapsInput);
                    } else {
                        _CurrentTime = _CurrentTime * parseFloat(_LapsInput);
                    }
                    this.clearInputVariables();
                    _LastButtonClicked = buttonPressed;
                    this.showTime(_CurrentTime,buttonPressed);
                }
            }
        },

        addClick : function () {
            this.aClick(BUTTON_ADD);
        },

        substractClick : function () {
            this.aClick(BUTTON_SUBSTRACT);
        },

        aClick : function (buttonPressed) {
            if (_CurrentState === SHOW_TIME) {
                var timeInDisplay = this.time2seconds(document.timecalc.dsp.value);
                _CurrentState = ENTER_TIME;
                if (_LastButtonClicked === BUTTON_ADD) {
                    _CurrentTime = _CurrentTime + timeInDisplay;
                } else if (_LastButtonClicked === BUTTON_SUBSTRACT) {
                    _CurrentTime = _CurrentTime - timeInDisplay;
                } else {
                    _CurrentTime = timeInDisplay;
                }
                this.clearInputVariables();
                _LastButtonClicked = buttonPressed;
                this.showTime(_CurrentTime,buttonPressed);
            } else if (_CurrentState === ENTER_LAPS) {
                _CurrentState = ENTER_TIME;

                if (_LastButtonClicked === BUTTON_DEVIDE) {
                    _CurrentTime = _CurrentTime / parseFloat(_LapsInput);
                } else {
                    _CurrentTime = _CurrentTime * parseFloat(_LapsInput);
                }
                this.clearInputVariables();
                _LastButtonClicked = buttonPressed;
                this.showTime(_CurrentTime,buttonPressed);
            } else if (_CurrentState === ENTER_TIME) {
                _CurrentState = SHOW_TIME;
                if (_LastButtonClicked === BUTTON_ADD) {
                    _CurrentTime = _CurrentTime + this.time2seconds(_TimeInput);
                } else if (_LastButtonClicked === BUTTON_SUBSTRACT) {
                    _CurrentTime = _CurrentTime - this.time2seconds(_TimeInput);
                } else {
                    _CurrentTime = this.time2seconds(_TimeInput);
                }
                this.clearInputVariables();
                _LastButtonClicked = buttonPressed;
                this.showTime(_CurrentTime,buttonPressed);
            }
        },

        equalClick : function () {
            if (_CurrentState === ENTER_LAPS) {
                if (_LapsInput !== "") {
                    _CurrentState = SHOW_TIME;
                    if (_LastButtonClicked === BUTTON_DEVIDE) {
                        _CurrentTime = _CurrentTime / parseFloat(_LapsInput);
                    } else {
                        _CurrentTime = _CurrentTime * parseFloat(_LapsInput);
                    }
                    this.clearInputVariables();
                    this.showTime(_CurrentTime);
                }
            } else if (_CurrentState === ENTER_TIME) {
                _CurrentState = SHOW_TIME;
                if (_LastButtonClicked === BUTTON_ADD) {
                    _CurrentTime = _CurrentTime + this.time2seconds(_TimeInput);
                } else if (_LastButtonClicked === BUTTON_SUBSTRACT) {
                    _CurrentTime = _CurrentTime - this.time2seconds(_TimeInput);
                } else {
                    _CurrentTime = this.time2seconds(_TimeInput);
                }
                this.clearInputVariables();
                this.showTime(_CurrentTime);
            }
        },

        periodClick : function () {
            if (_CurrentState === ENTER_TIME) {
                if (_TimeInput.length === 0) {
                    _Dot1Index = 1;
                    _TimeInput = "0.";
                    _NumberOfDots = 1;
                } else {
                    if ((_TimeInput.length === 1 || _TimeInput.length === 2) && (_NumberOfDots === 0)) {
                        _Dot1Index = _TimeInput.length;
                        _TimeInput += ".";
                        _NumberOfDots = 1;
                    } else {
                        // Na de eerste punt moeten 2 cijfers staan, en het
                        // 1e cijfer na de 1e punt mag niet groter zijn dan 5

                        if (_NumberOfDots === 1 && (_TimeInput.length - (_Dot1Index+1)) === 2 && _TimeInput.charAt(_Dot1Index+1) < '6') {
                            _Dot2Index = _TimeInput.length;
                            _TimeInput += ".";
                            _NumberOfDots = 2;
                        }
                    }
                }
                document.timecalc.dsp.value = _TimeInput.substring(0,_TimeInput.length);
            }
        },

        dstClick : function (distance) {
            if (_CurrentState === ENTER_LAPS) {
                _CurrentState = SHOW_TIME;
                if (_LastButtonClicked === BUTTON_DEVIDE) {
                    _CurrentTime = _CurrentTime / (distance / 400.0);
                } else {
                    _CurrentTime = _CurrentTime * (distance / 400.0);
                }
                this.clearInputVariables();
                this.showTime(_CurrentTime);
            }
        },

        speedClick : function () {
            if (_CurrentState === ENTER_TIME) {
                _CurrentState = SHOW_SPEED;
                _CurrentTime = this.time2seconds(_TimeInput);
                this.displaySpeed(_CurrentTime);
            } else if (_CurrentState === SHOW_TIME) {
                _CurrentState = SHOW_SPEED;
                _CurrentTime = this.time2seconds(document.timecalc.dsp.value);
                this.displaySpeed(_CurrentTime);
            }
        },

        displaySpeed : function (timeInSeconds) {
            var speedKmH = (400.0 * 60.0 * 60.0) / (_CurrentTime * 1000.0);
            // Afronden op 1 cijfer achter de komma
            speedKmH = Math.floor(speedKmH * 10.0) / 10.0;
            this.showTime(speedKmH + " km/h");
        },

        bckspcClick : function () {
            if (_CurrentState === ENTER_TIME) {
                if (_TimeInput.length > 0) {
                    // Bij het verwijderen van een punt moeten we iets extra's doen
                    if (_NumberOfDots > 0 && _TimeInput.charAt(_TimeInput.length-1) === '.') {
                        if (_NumberOfDots === 2) {
                            _Dot2Index = 0;
                        } else {
                            _Dot1Index = 0;
                        }
                        _NumberOfDots--;
                    }
                    _TimeInput = _TimeInput.substring(0,_TimeInput.length-1);
                }
                if (_TimeInput.length === 0) {
                    _TimeInput = "";
                    this.showTime("0");
                } else {
                    this.showTime(_TimeInput);
                }
            } else if (_CurrentState === ENTER_LAPS) {
                if (_LapsInput.length > 0) {
                    _LapsInput = _LapsInput.substring(0,_LapsInput.length-1);
                }
                if (_LapsInput.length === 0) {
                    _LapsInput = "";
                    this.showTime("0");
                } else {
                    this.showTime(_LapsInput);
                }
            }
        },

        showTime : function (timeInSecondsToShow,buttonPressed) {
            var isPositive = true;

            // typeof returns a string containing: number, string, boolean, object, function, undefined
            if (typeof timeInSecondsToShow === "number") {
                if (timeInSecondsToShow < 0.0) {
                    isPositive = false;
                    timeInSecondsToShow *= -1.0;
                }
                document.timecalc.dsp.value = ((!isPositive) ? NEGATIVE : "") + this.seconds2time(timeInSecondsToShow);
            } else {
                // It must be a string to show
                document.timecalc.dsp.value = timeInSecondsToShow;
            }

            if (typeof buttonPressed !== "undefined") {
                document.timecalc.dispinfo.value = this.getDisplayInfo(buttonPressed);
            } else {
                document.timecalc.dispinfo.value = "";
            }
        },

        getDisplayInfo : function (buttonPressed) {
            var displayInfo = "";
            if (buttonPressed === BUTTON_DEVIDE) {
                displayInfo = DISPINFO_DEVIDE;
            } else if (buttonPressed === BUTTON_MULTIPLY) {
                displayInfo = DISPINFO_MULTIPLY;
            } else if (buttonPressed === BUTTON_ADD) {
                displayInfo = DISPINFO_ADD;
            } else if (buttonPressed === BUTTON_SUBSTRACT) {
                displayInfo = DISPINFO_SUBSTRACT;
            }
            return displayInfo;
        },

        change_style : function (buttonRef,toClassName) {
            var currClassName = buttonRef.getAttribute("className");
            buttonRef.className = toClassName;
        },

        // <input type="text" onkeypress="return handleKey(event)" />
        handleKey : function (e) {
            var keynum;
            var keychar;

            if(window.event) { // IE
                keynum = e.keyCode;
            } else if(e.which) { // Netscape/Firefox/Opera
                keynum = e.which;
            }
            keychar = String.fromCharCode(keynum);
            switch (keychar) {
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                	this.numClick(keychar);
                    return true;
                case 's':
                case 'S':
                    this.speedClick();
                    return true;
                case '*':
                case 'x':
                case 'X':
                    this.multiplyClick();
                    return true;
                case '+':
                    this.addClick();
                    return true;
                case '-':
                    this.substractClick();
                    return true;
                case '/':
                    this.devideClick();
                    return true;
                case '=':
                    this.equalClick();
                    return true;
                case '?':
                    this.helpClick();
                    return true;
                case '.':
                	this.periodClick();
                    return true;
                case 'c':
                case 'C':
                    this.clearAll();
                    return true;
                case '<':
                    this.bckspcClick();
                    return true;
                default:
                    return false;
            }
            return false;
        }
    };
}();
