define([
    "jquery",
    "css!./cloze.css"
    ],
    function (
        jq
     ) {

    "use strict";

    /**
     * @constructor
     */

    return function( options, context, metadata ){

        var cloze,
            pageEvaluatedId,
            isRight = false,
            alternativeSolutionsRegExp = new RegExp( options.alternativeSolutions, options.isCaseSensitive ? "" : "i" ),
            answer = "",
            elementType = "tInput",
            elementVariableId;;

        function asRgbaValue( colorValue, transparencyValue ) {

            var color = hexToRgb( colorValue ),
                alpha = asAlpha( transparencyValue );

            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);
            return parsingResult ? {
                r: parseInt(parsingResult[1], 16),
                g: parseInt(parsingResult[2], 16),
                b: parseInt(parsingResult[3], 16)
            } : {
                r: 0,
                g: 0,
                b: 0
            };
        }

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

        function onBlur(event) {
            if (isEvaluated()) {
                return;
            }
            setUserAnswer(getCurrentAnswer());
        }

        function getCurrentAnswer(){
			return cloze.val();
		}

        function setUserAnswer (){
            answer = cloze.val();
            setSavedAnswer(answer);

            if( (options.isCaseSensitive && answer === options.sampleSolution) ||
                (!options.isCaseSensitive && answer.toLowerCase() === options.sampleSolution.toLowerCase()) ||
                (options.alternativeSolutions !== "" && answer.match(alternativeSolutionsRegExp))
            ){
                isRight = true;
            }else{
                isRight = false;
            }
            context.page.quiz.setSelected(options.instance, isRight);
        }

        function createQuizInputField(){
            elementVariableId = "inputValue" + metadata.getId() + "_" + options.groupId;
            context.page.quiz.add(options.instance, options.groupId + elementType, isRight);
            cloze = jq(document.createElement("input"))
                .attr({
                    "type": "text",
                    "id": elementVariableId,
                    "onkeydown": "event.cancelBubble=true; return true;",
                    "onkeyup": "event.cancelBubble=true; return true;",
                    "onkeypress": "event.cancelBubble=true; return true;",
                    "onselectstart":"event.cancelBubble=true; return true;"
                })
                .addClass("cloze")
                .val( options.input )
                .keyup( function ( event ) {
                    setTimeout( onBlur, 10 );
                    event.cancelBubble = true;
                    return true;
                } );

            if(options.input){
                context.stage.variable.set(elementVariableId, options.input, options.elementVariableNameSpace);
            }else{
                context.stage.variable.set(elementVariableId, false, options.elementVariableNameSpace);
            }

            setInitialDesign(cloze);

            if( options.isInAuthoringMode ) {
                cloze.val( options.sampleSolution )
            }
        }

        function setInitialDesign(element){
            element.css({
                "font-size": options.text.fontSize + "px",
                "color": options.text.color.default,
                "font-family": options.text.fontFamily,
                "line-height": options.text.fontSize + "px",
                "text-align": options.text.textAlign,
                "background-color": asRgbaValue(options.autoform.default.fillColor, options.autoform.default.fillTransparency),
                "padding-left": (options.text.paddingLeft - options.autoform.default.borderWidth) + "px",
                "padding-right": (options.text.paddingRight - options.autoform.default.borderWidth) + "px",
                "padding-top": (options.text.paddingTop - options.autoform.default.borderWidth) + "px",
                "padding-bottom": (options.text.paddingBottom - options.autoform.default.borderWidth) + "px"
            })

            if (options.autoform.borderWidth !== 0) {
                element.css({
                    "border": options.autoform.default.borderWidth + "px solid " + asRgbaValue(options.autoform.default.borderColor, options.autoform.default.borderTransparency)
                });
            }

            if(options.settings.maxCharacters && options.settings.maxCharacters > 0){
                element
                    .attr({
                        "maxlength" : options.settings.maxCharacters
                    })
            }

            if(!options.settings.isAutoAdjustHeight){
                element
                    .css({
                        "height":"100%"
                    })
            }else{
                element
                    .css({
                        "line-height": options.fontSize + "px"
                    })
            }

            if(!options.settings.showDeleteCross){
                element.addClass( "noDeleteCross" );
            }
        }

        function setSampleSolutionDesign(){
            cloze.css({
                "background-color": asRgbaValue(options.autoform.sampleSolution.fillColor, options.autoform.sampleSolution.fillTransparency),
                "color": options.text.color.sampleSolution
            })
            .prop("disabled", true);

            if (options.autoform.default.borderWidth !== 0) {
                cloze.css({
                    "border": options.autoform.default.borderWidth + "px solid " + asRgbaValue(options.autoform.sampleSolution.borderColor, options.autoform.sampleSolution.borderTransparency)
                });
            }
        }

        function setCorrectUserSolutionDesign(){
            cloze.css({

                "background-color": asRgbaValue(options.autoform.correct.fillColor, options.autoform.correct.fillTransparency),
                "color": options.text.color.correct
            })
            .prop("disabled", true);

            if (options.autoform.default.borderWidth !== 0) {
                cloze.css({
                    "border": options.autoform.default.borderWidth + "px solid " + asRgbaValue(options.autoform.correct.borderColor, options.autoform.correct.borderTransparency)
                });
            }
        }

        function setWrongUserSolutionDesign(){
            cloze.css({
                "background-color": asRgbaValue(options.autoform.wrong.fillColor, options.autoform.wrong.fillTransparency),
                "color": options.text.color.wrong
            })
            .prop("disabled", true);

            if (options.autoform.default.borderWidth !== 0) {
                cloze.css({
                    "border": options.autoform.default.borderWidth + "px solid " + asRgbaValue(options.autoform.wrong.borderColor, options.autoform.wrong.borderTransparency)
                });
            }
        }

        function isEvaluated() {

            if (options.isInPreviewMode) {
                return false;
            }
    
            if (options.isStandardPlayer || options.isInLearningMode) {
                return context.stage.variable.get(pageEvaluatedId, options.elementVariableNameSpace);
            }
    
            return context.page.quiz.hasQuestion() && context.page.quiz.getQuestion().isFinalized();
        }
    
        function getSavedAnswer(){
			var savedAnswer = context.stage.variable.get(elementVariableId, options.elementVariableNameSpace);
			if( savedAnswer ){
				cloze.val(savedAnswer);
			} else {
                cloze.val("");
			}
        }

        function setSavedAnswer(value){
            if(value){
                context.stage.variable.set(elementVariableId, value, options.elementVariableNameSpace);
            }else{
                context.stage.variable.set(elementVariableId, false, options.elementVariableNameSpace);
            }
        }

        function switchToUserSolution() {
            if (options.isStandardPlayer) {
                context.stage.variable.set(pageEvaluatedId, true, options.elementVariableNameSpace);
            }
            getSavedAnswer();

            if(isRight){
                setCorrectUserSolutionDesign();
            }else{
                setWrongUserSolutionDesign();
            }
        }
    
        function switchToBestPracticeSolution() {
            cloze.val(options.sampleSolution);
            setSampleSolutionDesign();
        }

        function reset() {
            context.stage.variable.set(pageEvaluatedId, false, options.elementVariableNameSpace);
            setSavedAnswer(false);
            context.page.quiz.setSelected(options.instance, false);
            cloze.prop("disabled", false);
            cloze.val(options.input);
            if(options.settings.focused){
                cloze.focus();
            }
            setInitialDesign(cloze);
        }

        return {
            build : function() {
                createQuizInputField();
                context.page.quiz.add(options.instance, options.groupId + elementType, true);
                return {
                    getElement : function() {
                        return cloze.get(0);
                    },
                    getJqElement : function() {
                        return cloze;
                    },
                    onEnter : function() {
                        if(!options.isInAuthoringMode){
                            pageEvaluatedId = metadata.page.getId() + "_evaluated";
                        }
                        if (isEvaluated()) {
                            switchToUserSolution();
                        } else {
                            if(options.settings.focused){
                                cloze.focus();
                            }
                        }
                    },
                    onExit : function(){
                        if( options.isStandardPlayer ) {
                            reset();
                        }
                    },
                    onUserSolution : switchToUserSolution,
                    onBestPracticeSolution : switchToBestPracticeSolution
                }
            }
        };
    };
});