define(["jquery"],function( jq ) {

    "use strict";

    /**
     * @constructor
     */
    return function( context, metadata ) {

        var self = null,
            parameters = metadata.parameters,
            isStandardPlayer = context.getPlayerName() === "standard",

            wrapper,
            emptyTextChecker = jq( document.createElement("div") ),

            growAlign = parameters.get( "align", "top" ),

            feedback,
            feedbackAvailable = false,
            showFeedbacks = true,
            feedbackEnabled = metadata.parameters.get("display-mode") === "COMMENT_AND_FEEDBACK" || metadata.parameters.get("display-mode") === "FEEDBACK_ONLY",

            comment,
            commentAvailable = false,
            commentEnabled = metadata.parameters.get("display-mode") === "COMMENT_AND_FEEDBACK" || metadata.parameters.get("display-mode") === "COMMENT_ONLY",

            fontSize = metadata.parameters.asNumber( "font-size", 14),
            borderSize = metadata.parameters.asNumber( "border-size", 1 ),
            padding = {
                "betweenCommentAndFeedback" : metadata.parameters.asNumber("padding-comment-feedback"),
                "top": metadata.parameters.asNumber("padding-top", 10),
                "right": metadata.parameters.asNumber("padding-right", 10),
                "bottom": metadata.parameters.asNumber("padding-bottom", 10),
                "left": metadata.parameters.asNumber("padding-left", 10)
            },
            fonts = [
                'Arial, Helvetica, sans-serif',
                '"Times New Roman", Times, serif',
                'Verdana, Geneva, sans-serif',
                '"Courier New", Courier, monospace',
                'Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif',
                '"Droid Serif", "Times New Roman", Times, serif'
            ];

        function asRgbaValue( colorParameterName, defaultColor, transparencyParameterName ) {

            var color = hexToRgb( parameters.get(colorParameterName, defaultColor)),
                alpha = asAlpha( parameters.asNumber(transparencyParameterName, 0) );

            return "rgba(" + color.r + ", " + color.g + ", " + color.b + ", " + alpha + ")";
        }

        function hexToRgb( hex ) {

            var parsingResult = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
            if( parsingResult ) {
                return {
                    r: parseInt(parsingResult[1], 16),
                    g: parseInt(parsingResult[2], 16),
                    b: parseInt(parsingResult[3], 16)
                };
            }

            return {
                r: 0,
                g: 0,
                b: 0
            };
        }

        function asAlpha( percentValue ) {
            return (100 - percentValue) / 100;
        }

        function getFont(index) {
            var fontIndex = (index > 0 && index < fonts.length) ? index - 1 : 0;
            return fonts[fontIndex];
        }

        function isEmpty( html ) {

            if( !html || (html.trim().length === 0) ){
                return true;
            }

            emptyTextChecker.html( html );
            var text = emptyTextChecker.text();

            return (text.trim().length === 0 && !hasImageElements(html));
        }

        function createComponent() {
            self = this;
            setComponentBehaviour();
            createDOM();
            initialize();
        }

        function setComponentBehaviour() {

            if( typeof context.page.event.bindOnPlayModeChanged === "function" ) {
                context.page.event.bindOnPlayModeChanged( self );
            }

            context.page.event.bindOnEnter(self);
            context.page.event.bindOnExit(self);

            context.page.quiz.event.bindOnEvaluateTestRun(self);
            context.page.quiz.event.bindOnUserSolution(self);
            context.page.quiz.event.bindOnBestPracticeSolution(self);

            context.page.interaction.event.bindOnWrong(self);
        }

        function createDOM() {

            jq(context.getElement())
                .css( getCoreStyles() )
                .addClass( getSCTestId() )
                .append( createWrapper() );

            if( context.stage.isInAuthoringMode() ) {
                createAuthoringShield();
            }
        }

        function getCoreStyles() {
            return {
                "border" : "0",
                "height" : metadata.getHeight() + "px"
            };
        }

        function getSCTestId(){

            if( commentEnabled && feedbackEnabled ){
                return "ttsCommentAndFeedbackComponent";
            }

            if( feedbackEnabled ){
                return "ttsFeedbackComponent";
            }
            if( commentEnabled ){
                return "ttsCommentComponent";
            }

            return "";
        }

        function createWrapper() {

            var boxShadowSizeHorizontal = metadata.parameters.asNumber( "box-shadow-size-h", 4 ),
                boxShadowSizeVertical = metadata.parameters.asNumber( "box-shadow-size-v", 4 ),
                boxShadowBlur = metadata.parameters.asNumber( "box-shadow-blur", 2 );

            wrapper = jq(document.createElement("div"))
                .css({
                    "width": "100%",
                    "height": "auto",
                    "clear": "both",
                    "color": "#000000",
                    "font-family": getFont(parameters.asNumber("font-family", 0)),
                    "background-color": asRgbaValue("background-color", "#cccccc", "background-transparency"),
                    "boxShadow": boxShadowSizeHorizontal + "px " + boxShadowSizeVertical + "px " + boxShadowBlur + "px 0px " + asRgbaValue("box-shadow-color", "4", "box-shadow-transparency"),
                    "borderRadius": metadata.parameters.asNumber("border-radius", 10) + "px",
                    "box-sizing": "border-box",
                    "padding": padding.top + "px " + padding.right + "px " + padding.bottom + "px " + padding.left + "px ",
                    "border": (borderSize !== 0) ? borderSize + "px solid " + asRgbaValue("border-color", "#4d4d4d", "border-transparency") : 0
                })
                .attr( "class", "tts-feedback-wrapper" )
                .append( createFeedbackElement() )
                .append( createCommentElement() );


            if( context.stage.isInAuthoringMode() ) {
                if( growAlign === "bottom" ){
                    wrapper.css( "border-bottom", "1px #ff0000 dashed" );
                }
                else {
                    wrapper.css( "border-top", "1px #ff0000 dashed" );
                }
            }

            if( growAlign === "bottom" ){
                wrapper.css({
                    "position": "absolute",
                    "bottom": "0px"
                });
            }

            return wrapper;
        }

        function createCommentElement() {

            comment = jq(document.createElement("div"))
                .css({
                    "width": "100%",
                    "height": "100%",
                    "clear": "both",
                    "color": metadata.parameters.asCssColor("color-comment","#000000")
                })
                .attr( "class", "tts-comment" )
                .append( createDefaultCommentText() );

            return comment;
        }

        function createDefaultCommentText() {
            return jq(document.createElement("div"))
                .css({
                    "width": "100%",
                    "height": "100%",
                    "overflow" : context.stage.isInAuthoringMode() ? "hidden" : "auto",
                    "font-size": fontSize + "px",
                    "white-space" : context.stage.isInAuthoringMode() ? "nowrap" : "normal"
                })
                .append( createDefaultCommentLabel() );
        }

        function createDefaultCommentLabel(){
            return jq(document.createElement("p"))
                .css({
                    "display": "block",
                    "width": "100%",
                    "text-align": "center",
                    "white-space:" : "nowrap"
                });
        }

        function createFeedbackElement() {
            feedback = jq(document.createElement("div"))
                .css({
                    "width": "100%",
                    "height": "100%",
                    "clear": "both",
                    "color": metadata.parameters.asCssColor("color-feedback","#000000")
                })
                .attr( "class", "tts-feedback" );

            return feedback;
        }

        function createAuthoringShield(){

            var authoringView = jq( document.createElement("div") );
            authoringView.css({
                "width" : "100%",
                "height" : "100%",
                "position" : "absolute",
                "opacity" : "0.15"
            });

            if( metadata.parameters.asNumber("background-transparency", 20) === 100 ){
                authoringView.css({
                    "background-image" : "url(\"" + context.getPath() + "invis.png\")"
                });
            }

            jq(context.getElement()).prepend( authoringView );
        }

        function setAndShowComment( commentDocumentFragment ) {

            comment.html("");
            comment.append(createComment(commentDocumentFragment));

            commentAvailable = isCommentAvailable();
            feedbackAvailable = isFeedbackAvailable();

            setPaddingBetweenCommentAndFeedback();

            if( !showComment() ) {
                hideComment();

                if( !feedbackAvailable ) {
                    hideFeedback();
                    refreshWrapperVisibility();
                }
            }
        }

        function showComment() {

            if( commentAvailable ) {
                showWrapper();
                comment.show();
                return true
            }

            return false;
        }

        function hideComment(){
            comment.hide();
        }

        function clearFeedback(){
            setAndShowFeedback("");
        }

        function setAndShowFeedback( feedbackDocumentFragment ) {

            feedback.html("");
            feedback.append(createFeedback(feedbackDocumentFragment));

            commentAvailable = isCommentAvailable();
            feedbackAvailable = isFeedbackAvailable();

            setPaddingBetweenCommentAndFeedback();

            if( !showFeedback() ) {

                hideFeedback();

                if( !commentAvailable ) {
                    hideComment();
                    refreshWrapperVisibility();
                }
            }
        }

        function showFeedback() {

            if( showFeedbacks && feedbackAvailable ) {
                showWrapper();
                feedback.show();
                return true;
            }

            return false;
        }

        function hideFeedback() {
            feedback.hide();
        }

        function setPaddingBetweenCommentAndFeedback(){
            feedback.css( "padding-bottom", (commentAvailable && feedbackAvailable) ? padding.betweenCommentAndFeedback + "px" : "0px" );
        }

        function isFeedbackAvailable( ){
            if( !feedbackEnabled ){
                return false;
            }

            return feedback.text().trim().length !== 0 || hasImageElements(feedback.html());
        }

        function isCommentAvailable(){
            if( !commentEnabled ){
                return false;
            }

            return comment.text().trim().length !== 0 || hasImageElements(comment.html()) ;
        }

        function hasImageElements(html) {
            if(html !== "" && html !== "&nbsp;"){
                return jq(html).find("img, kbd").length !== 0;
            }else{
                return false;
            }
        }

        function createFeedback( feedbackDocumentFragment ){

            var feedbackFragment = jq(feedbackDocumentFragment);

            feedbackFragment.css({
                "font-size": fontSize + "px",
                "color": metadata.parameters.asCssColor("color-feedback","#000000")
            });

            feedbackFragment.first().css({
                "marginTop" : 0
            });

            feedbackFragment.last().css({
                "marginBottom" : 0
            });

            return feedbackFragment;
        }

        function createComment( commentDocumentFragment ){

            var commentFragment = jq(commentDocumentFragment);

            commentFragment.css({
                "font-size": fontSize + "px",
                "color": metadata.parameters.asCssColor("color-comment","#000000")
            });

            commentFragment.first().css({
                "marginTop" : 0
            });

            commentFragment.last().css({
                "marginBottom" : 0
            });

            return commentFragment;
        }

        function initialize() {

            commentAvailable = commentEnabled ? initializeCommentText() : false;
            if( !commentAvailable ) {
                hideComment();
            }

            feedbackAvailable = feedbackEnabled ? initializeFeedbackText() : false;
            if( !feedbackAvailable ) {
                hideFeedback();
            }

            refreshWrapperVisibility();
        }

        function initializeCommentText(){
            return initializeCommentTextFromQuiz() || initializeDefaultCommentText();
        }

        function initializeCommentTextFromQuiz() {

            var questionId,
                questionContext;

            if (!isStandardPlayer && context.page.quiz.hasQuestion()) {

                questionId = context.page.quiz.getQuestionMetadata().getId();
                questionContext = context.quiz.getQuestionById(questionId);
                if (questionContext.isFinalized()) {
                    setAndShowComment(questionContext.getInstruction());
                    return true;
                }
            }

            setAndShowComment("");
            return false;
        }

        function initializeDefaultCommentText() {

            var commentHTML = context.page.getCommentHTML();
            if (!isEmpty(commentHTML)) {
                setAndShowComment(commentHTML);
                return true;
            }

            if( context.stage.isInAuthoringMode() ){
                setAndShowComment("<i>Comment</i>");
                return true;
            }

            setAndShowComment("");
            return false;
        }

        function initializeFeedbackText(){

            if( context.stage.isInAuthoringMode() ){
                setAndShowFeedback("<i>Feedback</i>");
                return true;
            }

            clearFeedback();
            return false;
        }

        function showWrapper(){
            if( feedbackAvailable || commentAvailable ) {
                wrapper.show();
            }
        }

        function refreshWrapperVisibility(){
            if( !feedbackAvailable && !commentAvailable ) {
                wrapper.hide();
            }
        }

        function hide() {
            hideComment();
            hideFeedback();
            refreshWrapperVisibility();
        }

        return {
            onLoading : createComponent,
            onEnterPage : initialize,
            onExitPage : initialize,

            onInteractionWrong : function( html5PlayerData, standardPlayerData ) {
                var data = standardPlayerData || html5PlayerData;

                setAndShowFeedback( data.feedback );
            },

            onEvaluateTestRun : function( html5PlayerData, standardPlayerData ) {
                var data = standardPlayerData || html5PlayerData;
                if( context.stage.isInLearningMode() ) {
                    setAndShowComment(data.text.instruction);
                }

                if (isStandardPlayer || context.stage.isInLearningMode() ) {
                    setAndShowFeedback(data.text.feedback);
                }
            },

            onUserSolution : function( html5PlayerData, standardPlayerData ){
                var data = standardPlayerData || html5PlayerData;
                setAndShowComment( data.text.instruction );
                setAndShowFeedback( data.text.feedback );
            },
            onBestPracticeSolution : function(html5PlayerData, standardPlayerData){
                var data = standardPlayerData || html5PlayerData;
                hide();
                clearFeedback();
                setAndShowComment( data.text.tip );
            },
            onPlayModeChanged: function( data ) {
                if( data.activeMode.componentId !== "com.tts.playmode.interactive" ) {
                    showFeedbacks = false;
                    hideFeedback();
                    return;
                }

                showFeedbacks = true;
            }
        };
    };
});