(function($) {
    var secs = 0;
    var mins = 0;
    var hrs = 0;
    var secsStr = "00";
    var minsStr = "00";
    var hrsStr = "00";
    var timerId = null;
    var timeValidator = null;
    var startTimestamp = null;
    var delay = 1000;
    var isTimerRunning = false;
    var isCountdown = false;
    var countdownCallback = null;
    var flashWhenLow = 0;
    var fontSize = 10;

    var initSecs = 0;
    var initMins = 0;
    var initHrs = 0;

    $.fn.timer = function(method, options) {

        var timerElement = $("#timer");
        if(timerElement.length > 0)
            fontSize =  parseInt($("#timer").css('font-size').replace(/px/, ''));

        var settings = $.extend({
            showHours: false
        }, options);
        
        if (settings.seconds !== undefined)
        {
            
            if(settings.seconds < 0)
            {
                hrs = 0;
                mins = 0;
                secs = 0;
            }
            else
            {
                hrs = Math.floor(settings.seconds / 3600);
                mins = Math.floor((settings.seconds - (hrs * 3600)) / 60);
                secs = settings.seconds - (hrs * 3600) - (mins * 60);
            }

            initHrs = hrs;
            initSecs = secs;
            initMins = mins;

            timeToString();
            updateTimerDisplay();
        }

        if ( settings.countdownCallback !== undefined)
        {
            countdownCallback = settings.countdownCallback;
        }

        switch (method) {
            case"start":
                if (!isTimerRunning) {
                    isCountdown = false;
                    startTimer();
                }
                else
                    updateTimerDisplay();

                break;

            case"countdown":
                if (!isTimerRunning) {
                    isCountdown = true;
                    startCountdown();
                }
                else if(!isCountdown) {
                    pauseTimer();
                    isCountdown = true;

                    startCountdown();
                }
                else
                    updateTimerDisplay();

                break;
            case"pause":
                pauseTimer();
                break;
            case"resume":
                if (!isTimerRunning) {
                    //var timerValue = ((hrs * 3600) + (mins * 60) + secs - 1);
                    var timerValue = getTimeSeconds();

                    if(isCountdown)
                    {
                        startTimestamp = new Date().getTime() + (timerValue*1000);
                        startCountdownInterval();
                    }
                    else
                    {
                        startTimestamp = new Date().getTime() - (timerValue*1000);
                        startTimerInterval();
                    }
                }
                break;

            case"reset":
                secs = 0;
                mins = 0;
                hrs = 0;

                pauseTimer();

                if(isCountdown)
                {
                    //Forgive me father, for I have sinned.
                    //This is a technical debt. [!!]
                    //
                    //When saved times are used for countdowns, they will be wrong..
                    secs = initSecs;
                    mins = initMins;
                    hrs = initHrs;

                    startCountdown();
                }
                else
                {     
                    startTimer();
                }

                timeToString();
                updateTimerDisplay();

                break;
            case"get_seconds":
                var secondsTime = getTimeSeconds();
                return secondsTime;
                break;
            case"get_formated_time":
                if (hrs > 0) {
                    settings.showHours = true;
                }
                if (settings.showHours) {
                    return hrsStr + ":" + minsStr + ":" + secsStr;
                } else {
                    return minsStr + ":" + secsStr;
                }
                break;
            case"get_formatted_time_string":
                var timeString = "";

                //Get hours
                if (parseInt(hrsStr) == 1)
                    timeString += "1 hour";
                else if (parseInt(hrsStr) > 1)
                    timeString += parseInt(hrsStr) + " hours";

                //Get minutes
                if (parseInt(minsStr) == 1)
                    timeString += " 1 minute";
                else if (parseInt(minsStr) > 1)
                    timeString += " " + parseInt(minsStr) + " minutes";

                //Get seconds
                if (parseInt(secsStr) == 1)
                    timeString += " 1 second";
                else if (parseInt(secsStr) > 1)
                    timeString += " " + parseInt(secsStr) + " seconds";

                if (timeString == "")
                    timeString = "0 seconds";

                return timeString.trim();
                break;

            case "flash_when_low":
                flashWhenLow = settings.flash_when_low;
                break;
        }
        function getTimeSeconds() {

            if (isCountdown)
            {
                return((hrs * 3600) + (mins * 60) + secs);
            }
            else
            {
                return((hrs * 3600) + (mins * 60) + secs);
            }
        }
        function pauseTimer() {
            clearInterval(timerId);
            clearInterval(timeValidator);
            isTimerRunning = false;
            updateTimerDisplay();
        }
        function startTimer() {
            startTimestamp = new Date().getTime();

            updateTimerDisplay();
            //incrementTime();
            startTimerInterval();
        }
        function startTimerInterval() {
            timerId = setInterval(incrementTime, delay);
            timeValidator = setInterval(correctTimer, delay * 2);
            isTimerRunning = true;
        }
        function startCountdown() {

            if(checkCountdown())
            {
                return;
            }

            var timerValue = getTimeSeconds();//    ((hrs * 3600) + (mins * 60) + secs - 1);
            startTimestamp = new Date().getTime() + (timerValue * 1000);
            var offset = startTimestamp - new Date().getTime();

            updateTimerDisplay();
            //decrementTime();
            startCountdownInterval();
        }
        function startCountdownInterval() {
            timerId = setInterval(decrementTime, delay);
            timeValidator = setInterval(correctCountdown, delay * 2);
            isTimerRunning = true;
        }
        function updateTimerDisplay() {
            if (hrs > 0) {
                settings.showHours = true;
            }
            else{
                settings.showHours = false;
            }


            if (parseInt(hrsStr) == 0 && parseInt(minsStr) == 0  && parseInt(secsStr) > 0 && parseInt(secsStr) <= flashWhenLow)
            {
                var multiplier = 1.5;

                $("#timer").addClass('timer-low');

                var timeline = new TimelineMax({onComplete: function() {
                        $('#timer').css('font-size', fontSize + 'px');
                    }
                });

                timeline.to($('#timer'), 0.2, {fontSize: (fontSize * multiplier)});
                timeline.to($('#timer'), 0.2, {fontSize: fontSize});
            }
            else
            {
                $("#timer").removeClass('timer-low');
            }

            if (settings.showHours)
            {
                $("#timer").html(hrsStr + ":" + minsStr + ":" + secsStr);
            }
            else
            {

                $("#timer").html(minsStr + ":" + secsStr);
            }
        }
        function timeToString() {

            if (secs < 10) {
                secsStr = "0" + secs;
            } else {
                secsStr = secs;
            }
            if (mins < 10) {
                minsStr = "0" + mins;
            } else {
                minsStr = mins;
            }
            if (hrs < 10) {
                hrsStr = "0" + hrs;
            } else {
                hrsStr = hrs;
            }
        }
        function incrementTime() {

            secs++;
            if (secs % 60 == 0) {
                mins++;
                secs = 0;
            }
            if (mins > 59 && mins % 60 == 0) {
                hrs++;
                mins = 0;
            }

            timeToString();
            updateTimerDisplay();
        }
        function decrementTime() {
            if(checkCountdown())
            {
                return;
            }

            secs--;
            if (secs < 0) {
                mins--;
                secs = 59;
            }
            if (mins < 0 ) {
                hrs--;
                mins = 59;
            }

            timeToString();
            updateTimerDisplay();
        }
        function correctTimer() {

            var currentTime = Math.floor((new Date().getTime() - startTimestamp) / 1000);
            var timerValue = getTimeSeconds();    //((hrs * 3600) + (mins * 60) + secs - 1);

            if (timerValue < currentTime-1)
            {
                settings.seconds = currentTime - 1;
                hrs = Math.floor(settings.seconds / 3600);
                mins = Math.floor((settings.seconds - (hrs * 3600)) / 60);
                secs = settings.seconds - (hrs * 3600) - (mins * 60);
                updateTimerDisplay();
            }
        }
        function correctCountdown() {

            var actualTime = Math.ceil((startTimestamp - new Date().getTime()) / 1000);
            var timerValue = getTimeSeconds();    //((hrs * 3600) + (mins * 60) + secs - 1);
            
            //Look at fixing this correction formula
            if (timerValue-1 > actualTime)
            {
                settings.seconds = actualTime - 1;
                hrs = Math.floor(settings.seconds / 3600);
                mins = Math.floor((settings.seconds - (hrs * 3600)) / 60);
                secs = settings.seconds - (hrs * 3600) - (mins * 60);
                updateTimerDisplay();
            }
        }
        function checkCountdown() {

            if((secs <= 0 && mins <= 0 && hrs <= 0) || hrs < 0)
            {
                if(countdownCallback != null)
                {
                    countdownCallback();
                }

                secs = 0;
                mins = 0;
                hrs = 0;
                //updateTimerDisplay();
                pauseTimer();
                return true;
            }

            return false;
        }
    };
})(jQuery);