/**
 * E-Learning module.
 */
(function($) {

    // Classes
    var OPTION_CLASS = 'option';
    var OPTION_CHECKED = 'option-checked';
    var RADIO_CHECKED = 'radio-checked';
    var CHECKBOX_CHECKED = 'checkbox-checked';
    var LIST_TOGGLE_CLASS = 'list-toggle';
    var ACTIVE_CLASS = 'active';
    var ANSWERED_CLASS = 'answered';
    var QUESTION_SLIDE_CLASS = 'question';
    var SEE_ANSWER_ACTIVE_CLASS = 'see-answer-active';

    // Selectors
    var QUESTION = '.ecme-question';
    var OPTION_LIST = '.optionlist';
    var OPTION = '.' + OPTION_CLASS;
    var OPTIONS_SELECTOR = OPTION_LIST + ' ' + OPTION;
    var CHECKED_FIELDS_SELECTOR = OPTIONS_SELECTOR + ' input:checked';
    var LIST_TOGGLE = '.' + LIST_TOGGLE_CLASS;
    var TOGGLE_LINK = 'a[rel=toggle]';
    var TOGGLE_LINKS_SELECTOR = LIST_TOGGLE + ' ' + TOGGLE_LINK;
    var SEE_ANSWER = '.see-answer';
    var QA_BOX = '.emce-qa-box';
    var QA = '.ecme-qa';
    var NAVIGATION = '.ecme-module-nav';
    var ECME_WRAPPER = '.ecme-module';

    // Events
    var ELEARNING_EVENT = 'elearning';
    var CLICK_ELEARNING = 'click.' + ELEARNING_EVENT;
    var MOUSEUP_ELEARNING = 'mouseup.' + ELEARNING_EVENT;

    var ELearning = function() {
        this.isMobile = ($(window).width() < 640);
        this.touch = !!('ontouchstart' in window);
        this.nav = $(NAVIGATION);
        this.ecmeWrapper = $(ECME_WRAPPER);


        // Bind events
        $(OPTIONS_SELECTOR, QUESTION).bind('click', this.handleOptionListClick.bind(this));
        $(SEE_ANSWER, QUESTION).bind('click', this.handleSeeAnswerClick.bind(this));
        $(TOGGLE_LINKS_SELECTOR).bind('click', this.handleToggleListClick.bind(this));

        if ($(QUESTION).length > 0) {
            // Mediabar
            var mediabar = LBi.Mediabar.instances[0];
            this.mediabar = mediabar;
            this.hasMediabar = typeof(mediabar) != 'undefined';
            if (this.hasMediabar) {
                this.mbPrevButton = mediabar.prevButton;
                this.mbNextButton = mediabar.nextButton;
                this.mbMouseup = mediabar._mouseup;
                this.mbHitArea = mediabar.hitArea;
                $(window).hashchange(this.handleHashChange.bind(this));
            }
            this.mouseup = this.handleMouseup.bind(this);
        }

        // Setup mobile
        if (this.isMobile) {
            this.initMobile();
        }
    };

    ELearning.prototype = {

        /**
         * Initializes the component.
         */
        initialize: function() {
            this.initOptionLists();
            this.setupMediaBarControls();
        },

        /**
         * Initializes the option lists.
         * Gets the checked fields.
         */
        initOptionLists: function() {
            new LBi.EqualizedNodes({
                selector: '.optionlist-img',
                children: 'li label'
            });
            var checkedFields = $(CHECKED_FIELDS_SELECTOR, QUESTION);
            for (i = 0; i < checkedFields.length; i++) {
                this.checkOption(this.getOption(checkedFields[i]));
            }
        },

        /**
         * Handles the option list click event.
         * @param {Event} e the event
         */
        handleOptionListClick: function(e) {
            LBi.log('Optionlist click:', e);
            this.toggleOption(this.getOption(e.target));
        },

        /**
         * Handles the toggle list click event.
         * @param {Event} e the event
         */
        handleToggleListClick: function(e) {
            LBi.log('Toggle list click:', e);
            e.preventDefault();
            this.toggleList(this.getToggleList(e.target));
        },

        /**
         * Toggles an option. ('radio' or 'checkbox')
         * @param {jQuery} option the option
         */
        toggleOption: function(option) {

			//nicola mods
			var field = this.getOptionField(option);
			val = field.attr('value');
			var ansField = $('#ans_'+val);

            // Check if this option is a radio button
            if (!this.isCheckbox(option)) {
                // Reset the options
                this.resetChecked(this.getOptionList(option));
            }
            // Toggle check
            if (this.isChecked(option)) {
                this.uncheckOption(option);

				//nicola mods
				if (ansField.hasClass('checkbox-correct'))
					ansField.removeClass('checkbox-correct');
				if (ansField.hasClass('checkbox-wrong'))
					ansField.removeClass('checkbox-wrong');
            } else {
                this.checkOption(option);
            }
            // Check see answer button
            var question = option.closest(QUESTION);
            this.setupSeeAnswerButton(question.find(SEE_ANSWER));
        },

        /**
         * Toggles the explanation
         */
        toggleList: function(toggleList) {
            toggleList.toggleClass(ACTIVE_CLASS);
        },

        /**
         * Checks an option.
         * @param {jQuery} option the option
         */
        checkOption: function(option) {
            option.addClass(OPTION_CHECKED);
            var field = this.getOptionField(option);
            field.attr('checked', true);

			//nicola mods
			val = field.attr('value');
			var ansField = $('#ans_'+val);
			var corField = $('.cor-'+val);
			rel = field.attr('rel');

			$('img.cor').each(function(i){
				$(this).css('display','block');
			});

			$('div#explanation').css('display','none');
			$('div.expv').each(function(i){
				$(this).css('display','none');
			});

			expval = $('#expv-'+val).text();
			if(expval.length >0){
				$('div#explanation').css('display','block');
				$('#expv-'+val).css('display','block');
			}

            var img = this.getOptionImage(option);
			if (!field.hasClass('ans')){
            if (this.isCheckbox(option)) {
                img.addClass(CHECKBOX_CHECKED);
					if (rel > 0){
						//is right answer
						ansField.addClass('checkbox-correct');
						corField.css('display','none');
            } else {
						ansField.addClass('checkbox-wrong');
						corField.css('display','block');
					}
				} else {
                img.addClass(RADIO_CHECKED);
					if (rel > 0){
						//is right answer
						$('img.ans').each(function(i){
							$(this).removeClass('radio-correct');
							$(this).removeClass('radio-wrong');
						});
						ansField.addClass('radio-correct');
						corField.css('display','none');

					} else {
						$('img.ans').each(function(i){
							$(this).removeClass('radio-correct');
							$(this).removeClass('radio-wrong');
						});
						ansField.addClass('radio-wrong');
						corField.css('display','block');
            }
				}
			}
        },

        /**
         * Unchecks an option.
         * @param {jQuery} option the option
         */
        uncheckOption: function(option) {
            option.removeClass(OPTION_CHECKED);
            var field = this.getOptionField(option);
            field.attr('checked', false);
            var img = this.getOptionImage(option);
            if (this.isCheckbox(option)) {
                img.removeClass(CHECKBOX_CHECKED);
            } else {
                img.removeClass(RADIO_CHECKED);
            }
        },

        /**
         * Resets the checked options in an option list.
         * @param {jQuery} optionList the option list
         */
        resetChecked: function(optionList) {
            var options = optionList.find(OPTION);
            for (i = 0; i < options.length; i++) {
                var option = $(options[i]);
                if (this.isChecked(option)) {
                    this.uncheckOption(option);
                }
            }
        },

/**
 * ########################################################################################
 * #                                Utility methods                                       #
 * ########################################################################################
 */

        /**
         * Checks if an option is checked.
         * @param {jQuery} option the option
         */
        isChecked: function(option) {
            var field = this.getOptionField(option);
            if (field.attr('checked')) {
                return true;
            }
            return false;
        },

        /**
         * Checks if an option is a checkbox.
         * @param {jQuery} option the option
         */
        isCheckbox: function(option) {
            var field = this.getOptionField(option);
            if (field.is(':checkbox')) {
                return true;
            }
            return false;
        },

        /**
         * Gets the option. ('li.option')
         * @param {Node} node the node
         * @return {jQuery} the option
         */
        getOption: function(node) {
            var item = $(node);
            if (item.hasClass(OPTION_CLASS)) {
                return item;
            }
            return item.closest(OPTION);
        },

        /**
         * Gets the option field. ('li.option input')
         * @param {jQuery} option the option
         * @return {jQuery} the field
         */
        getOptionField: function(option) {
            return option.find('input');
        },

        /**
         * Gets the option image. ('li.option label img')
         * @param {jQuery} option the option
         * @return {jQuery} the image
         */
        getOptionImage: function(option) {
            return option.find('label img');
        },

        /**
         * Gets the option list. ('ul.optionlist')
         * @param {jQuery} option the option
         * @return {jQuery} the list
         */
        getOptionList: function(option) {
            return option.closest(OPTION_LIST);
        },

        /**
         * Gets the toggle list. ('ul.list-toggle')
         */
        getToggleList: function(node) {
            var item = $(node);
            if (item.is('li')) {
                return item;
            }
            return item.closest('li');
        },

/**
 * ########################################################################################
 * #                          Question in slideshow code                                  #
 * ########################################################################################
 */

        /**
         * Setup the media bar controls for Q&A box.
         */
        setupMediaBarControls: function() {
            if (this.hasMediabar) {
                var currentSlide = this.mediabar.getCurrentItem();
                var qaBox = this.findQABox(currentSlide);
                if (currentSlide.hasClass(QUESTION_SLIDE_CLASS) && qaBox.length > 0) {
                    if (qaBox.hasClass(ANSWERED_CLASS)) {
                        this.bindClickEvent(this.mbPrevButton, this.handleMediabarPrevClick);
                        this.unbindClickEvent(this.mbNextButton);
                    } else {
                        this.unbindClickEvent(this.mbPrevButton);
                        this.bindClickEvent(this.mbNextButton, this.handleMediabarNextClick);
                    }
                    this.setMediabarMouseup();
                    this.setupSeeAnswerButton(qaBox.find(SEE_ANSWER));
                } else {
                    this.unbindClickEvent(this.mbPrevButton);
                    this.unbindClickEvent(this.mbNextButton);
                    this.resetMediabarMouseup();
                }
            }
        },

                /**
         * Set the mediabar mouse up events.
         */
        setMediabarMouseup: function() {
            this.unbindMediabarMouseUp();
            this.unbindMouseup();
            this.bindMouseup();
        },

        /**
         * Reset the mediabar mouse events.
         */
        resetMediabarMouseup: function() {
            this.unbindMouseup();
            this.unbindMediabarMouseUp();
            this.bindMediabarMouseup();
        },

        /**
         * Unbinds the standard mediabar mouseup events.
         */
        unbindMediabarMouseUp: function() {
            var hitArea = this.mbHitArea;
            hitArea.unbind('mouseup', this.mbMouseup);
            if(this.mediabar.touch) {
                hitArea[0].removeEventListener('touchend', this.mbMouseup, false);
            }
        },

        /**
         * Binds the standard mediabar mouseup events.
         */
        bindMediabarMouseup: function() {
            var hitArea = this.mbHitArea;
            hitArea.bind('mouseup', this.mbMouseup);
            if(this.mediabar.touch) {
                hitArea[0].addEventListener('touchend', this.mbMouseup, false);
            }
        },

        /**
         * Binds the custom mediabar mouseup events.
         */
        bindMouseup: function() {
            var hitArea = this.mbHitArea;
            hitArea.bind('mouseup', this.mouseup);
            if(this.mediabar.touch) {
                hitArea[0].addEventListener('touchend', this.mouseup, false);
            }
        },

        /**
         * Unbinds the custom mediabar mouseup events.
         */
        unbindMouseup: function() {
            var hitArea = this.mbHitArea;
            hitArea.unbind('mouseup', this.mouseup);
            if(this.mediabar.touch) {
                hitArea[0].removeEventListener('touchend', this.mouseup, false);
            }
        },

        /**
         * Handles the custom mediabar mouseup event.
         * @param {Event} e the event
         */
        handleMouseup: function(e) {
            LBi.log('Mouse up:', e);
            // Do the same as in the mediabar
            if(this.mediabar.touch){
                this.mediabar.touch_node.removeEventListener('touchmove', this._drag);
            }
            var event = this.mediabar.getEvent(e);
            this.mediabar.eX = event.clientX;
            var dX = this.mediabar.eX - this.mediabar.sX;
            var currentSlide = this.mediabar.getCurrentItem();
            var qaBox = this.findQABox(currentSlide);
            if (dX < -100) {
                // If the answer is shown or the question is unanswered get to the next slide
                if (qaBox.hasClass(ANSWERED_CLASS) || !this.isAnswered(qaBox)) {
                    this.mediabar.next();
                } else {
                    // Show the answer
                    this.showAnswer(qaBox);
                }
            }
            if (dX > 100) {
                // If the answer is is shown show the question
                if (qaBox.hasClass(ANSWERED_CLASS)) {
                    this.showQuestion(qaBox);
                } else {
                    // Go to the next slide
                    this.mediabar.previous();
                }
            }
        },

        /**
         * Setup the see answer button.
         * @param {jQuery} the link
         */
        setupSeeAnswerButton: function(link) {
            if (link.length > 0) {
                var qaBox = this.getQABox(link);
                if (this.isAnswered(qaBox)) {
                    link.addClass(SEE_ANSWER_ACTIVE_CLASS);
                } else {
                    link.removeClass(SEE_ANSWER_ACTIVE_CLASS);
                }
            }
        },

        /**
         * Handles the see answer click event.
         * @param {Event} e the event
         */
        handleSeeAnswerClick: function(e) {
            LBi.log('See answer click:', e);
            e.preventDefault();
            this.showAnswer(this.getQABox(e.target));
        },

        /**
         * Handles the hash change for the questions in the slideshow.
         * @param {Event} e the event
         */
        handleHashChange: function(e) {
            LBi.log('Hash changed:', e);
            this.setupMediaBarControls();
        },

        /**
         * Handles the mediabar previous click.
         * @param {Event} e the event
         */
        handleMediabarPrevClick: function(e) {
            LBi.log('Mediabar previous click:', e);
            e.preventDefault();
            var currentSlide = this.mediabar.getCurrentItem();
            this.showQuestion(this.findQABox(currentSlide));
        },

        /**
         * Handles the mediabar previous click.
         * @param {Event} e the event
         */
        handleMediabarNextClick: function(e) {
            LBi.log('Mediabar next click:', e);
            var currentSlide = this.mediabar.getCurrentItem();
            var qaBox = this.findQABox(currentSlide);
            if (this.isAnswered(qaBox)) {
                this.showAnswer(qaBox);
                e.preventDefault();
            }
        },

        /**
         * Shows the question.
         * @param {jQuery} qaBox the Q&A box
         */
        showQuestion: function(qaBox) {
            var questionWidth = qaBox.find(QUESTION).outerWidth() * -1;
            qaBox.scrollTo(
                {top: 0, left: questionWidth},
                {duration: 500}
            );
            qaBox.removeClass(ANSWERED_CLASS);
            this.unbindClickEvent(this.mbPrevButton);
            this.bindClickEvent(this.mbNextButton, this.handleMediabarNextClick);
            if (this.isMobile) {
                this.mediabar.resetViewHeight();
            }
        },

        /**
         * Shows the answer.
         * @param {jQuery} qaBox the Q&A box
         */
        showAnswer: function(qaBox) {
            if (this.isAnswered(qaBox)) {
                var questionWidth = qaBox.find(QUESTION).outerWidth();
                qaBox.scrollTo(
                    {top: 0, left: questionWidth},
                    {duration: 500}
                );
                qaBox.addClass(ANSWERED_CLASS);
                this.bindClickEvent(this.mbPrevButton, this.handleMediabarPrevClick);
                this.unbindClickEvent(this.mbNextButton);
            }
            if (this.isMobile) {
                this.mediabar.resetViewHeight();
            }
        },

        /**
         * Binds the e-learning click event to the button.
         * @param {jQuery} button the button
         * @param {jQuery} handler the handler
         */
        bindClickEvent: function(button, handler) {
            if (!this.hasClickEvent(button)) {
                button.bind(CLICK_ELEARNING, handler.bind(this));
            }
        },

        /**
         * Unbinds the e-learning click event of the button.
         * @param {jQuery} button the button
         */
        unbindClickEvent: function(button) {
            button.unbind(CLICK_ELEARNING);
        },

        /**
         * Checks if a question in a Q&A box is answered.
         */
        isAnswered: function(qaBox) {
            var question = qaBox.find(QUESTION).first();
            if (question.find(':checked').length > 0) {
                return true;
            }
            return false;
        },

        /**
         * Gets the Q&A box. ('div.emce-qa-box')
         */
        getQABox: function(node) {
            var item = $(node);
            if (item.hasClass(QA_BOX)) {
                return item;
            }
            return item.closest(QA_BOX);
        },

        /**
         * Finds the Q&A box. ('div.emce-qa-box')
         */
        findQABox: function(container) {
            if (container.hasClass(QA_BOX)) {
                return container;
            }
            return container.find(QA_BOX);
        },

        /**
         * Checks if the button has the e-learning click event.
         * @param {jQuery} button the button
         */
        hasClickEvent: function(button) {
            var events = button.data('events');
            if (typeof(events) != 'undefined') {
                var clickEvents = events.click;
                if (typeof(clickEvents) != 'undefined') {
                    for (i = 0; i < clickEvents.length; i++) {
                        var event = clickEvents[0];
                        if (event.namespace == ELEARNING_EVENT) {
                            return true;
                        }
                    }
                }
            }
            return false;
        },

/**
 * ########################################################################################
 * #                          Question in slideshow code                                  #
 * ########################################################################################
 */
        /**
         * Initializes the mobile functions.
         */
        initMobile: function() {
            if (this.nav.length > 0) {
                this.setupMobileNav();

                // On orientation change
                this.isLandscape = $(window).width() > $(window).height();
                $(window).bind('resize', this.changeMobileOrientation.bind(this));
            }
        },

        /**
         * Called when changing the orientation of the screen.
         */
        changeMobileOrientation: function() {
            // Get orientation of screen
            var landscape = $(window).width() > $(window).height();
            if (landscape != this.isLandscape) {
                // Reset the view size
                this.setMobileNavSize();
                this.isLandscape = landscape;
            }
        },

        /**
         * Sets up the mobile nav.
         */
        setupMobileNav: function() {
            // Setup nav wrapper
            this.mNav = this.nav.children('.container');

            // Set the width of the nav
            var navWidth = 10;
            var items = this.mNav.find('ul').first().children('li');
            for (var i = 0; i < items.length; i++) {
                navWidth += $(items[i]).outerWidth(true);
            }
            this.mNavWidth = navWidth;
            this.mNavWidthOriginal = navWidth;
            this.mNav.css({
                width: navWidth + 'px',
                left: '0px'
            });

            // Setup hit area
            this.mNavHitArea = $('<div class="navhitarea"></div>');
            this.nav.append(this.mNavHitArea);
            this.mNavHitArea.css({
                position: 'absolute',
                height: '30px',
                top: 0,
                left: 0,
                'z-index': 9999
            });

            // Setup events
            this._mNavTouchStart = this.touchstartMobileNav.bind(this);
            this._mNavTouchEnd = this.touchendMobileNav.bind(this);
            this._mNavTouchMove = this.touchmoveMobileNav.bind(this);
            if (this.touch) {
                this.mNavHitArea[0].addEventListener('touchstart', this._mNavTouchStart, false);
                this.mNavHitArea[0].addEventListener('touchend', this._mNavTouchEnd, false);
            } else {
                this.mNavHitArea.bind('mouseover', this._mNavTouchStart);
                this.mNavHitArea.bind('mouseout', this._mNavTouchEnd);
            }

            // Set the size of the nav
            this.setMobileNavSize();
        },

        /**
         * Sets the mobile nav size.
         */
        setMobileNavSize: function() {
            var width = this.ecmeWrapper.width();
            // Set wrapper size
            this.nav.css('width', width + 'px');
            // Set nav size
            if (this.mNavWidthOriginal < width) {
                this.mNav.css('width', width + 'px');
                this.mNavWidth = width;
            } else {
                this.mNav.css('width', this.mNavWidthOriginal + 'px');
                this.mNavWidth = this.mNavWidthOriginal;
            }
            // Scroll nav to fit
            var maxLeft = -this.mNavWidth + width;
            if (this.mNav.position().left < maxLeft) {
                this.mNav.css('left', maxLeft + 'px');
            }
            // Set hitarea size
            this.mNavHitArea.css('width', width + 'px');
        },

        /**
         * Handles the touch start on the mobile navigation.
         * @param {Event} e the event
         */
        touchstartMobileNav: function(e) {
            var event = this.getEvent(e);

            this.mNavX = event.clientX;
            this.mNavLeftX = this.mNav[0].offsetLeft;

            if (this.touch) {
                this.mNavHitArea[0].addEventListener('touchmove', this._mNavTouchMove, false);
            } else {
                this.mNavHitArea.bind('mousemove', this._mNavTouchMove);
            }
        },

        /**
         * Handles the touch move on the mobile navigation.
         * @param {Event} e the event
         */
        touchmoveMobileNav: function(e) {
            var event = this.getEvent(e);

            // Move the nav
            var left = this.mNavLeftX + ((event.clientX - this.mNavX) * 3);
            var minLeft = 0;
            var maxLeft = -this.mNavWidth + this.ecmeWrapper.width();
            if (left > 0) {
                left = minLeft;
            } else if (left < maxLeft) {
                left = maxLeft;
            }
            this.mNav.css("left", left + "px");
        },

        /**
         * Handles the touch end on the mobile navigation.
         * @param {Event} e the event
         */
        touchendMobileNav: function(e) {
            if (this.touch) {
                this.mNavHitArea[0].removeEventListener('touchmove', this._mNavTouchMove);
            } else {
                this.mNavHitArea.unbind('mousemove', this._mNavTouchMove);
            }
        },

        /**
         * Gets the event.
         * @param {Event} e the event
         * @return {Event} the event
         */
        getEvent: function(e) {
            var event = e;
            var touch = e.touches;
            var changed = e.changedTouches;
            if(touch && touch[0]) {
                event = touch[0];
            } else if(changed && changed[0]) {
                event = changed[0];
            }
            return event;
        }

    };

    /**
     * Initializes the journal
     */
    $(function() {
        var eLearning = new ELearning();
        eLearning.initialize();
    });

})(jQuery);
