var OU = OU || {};

//an array of primitives == out of score (unless radio type)
OU.Feedback = function Feedback(cfg, buttons) {
    if (!(this instanceof Feedback)) {
        return new Feedback(cfg, buttons);
    }

    this.el = document.createElement('div');
    this.buttons = null;
    this.attempts = 0;
    this.data = null;
    this.correct = 0;
    this.total = 0;
    this.visible = false;
    this.allCorrect = false;
    this.maxAttemptsReached = false;
    this.cfg = {
        type: 'general',
        allowedAttempts: 1000,
        branch: [
            'That is one possible answer.',
            'That is the other possible answer.',
            'That is another possible answer.'
        ],
        general: [
            'Your answer is incorrect.',
            'Your answer is correct.',
            'Your answer is partially correct.'
        ],
        score: [
            'All of your answers are correct',
            ' of your answers are correct',
            ' of your answers is correct'
        ],
        specific: [],
        final: {
            branch: {
                general: [], //shown in order answered, e.g. first answered will show [0]
                specific: [] //shown relative to specific branch
            },
            exercise: [
                'Try another question.',
                'That is the end of the exercise.'
            ]
        },
        correct: '',
        incorrect: '',
        partial: '',
        always: '',
        whenCorrect: null, //callback for when correct
        getFeedback: null //callback for getting feedback
    };

    OU.utils.setCfg(cfg, this.cfg);

    this.el.className = 'general-feedback';

    if (buttons) {
        this.buttons = buttons;
    }

    if (typeof cfg.getFeedback == 'function') {
        this.get = cfg.getFeedback.bind(this);
    }
};

OU.Feedback.prototype.get = function() { //number of correct responses
    var str;

    switch (this.cfg.type) {
        case 'general':
            switch (this.correct) {
                case 0:
                    str = this.cfg.general[0] || '';
                    break;
                case this.total:
                    str = this.cfg.general[1] || '';
                    break;
                default:
                    str = this.cfg.general[2] || '';
            }
            break;
        case 'score':
            switch (this.correct) {
                case 0:
                    str = '<p>None ' + this.cfg.score[1] + '.</p>';
                    break;
                case this.total:
                    str = '<p>' + this.cfg.score[0] + '.</p>';
                    break;
                case 1:
                    str = '<p>' + OU.utils.capFirstLetter(OU.utils.inWords(this.correct)) + this.cfg.score[2] + '.</p>';
                    break;
                default:
                    str = '<p>' + OU.utils.capFirstLetter(OU.utils.inWords(this.correct)) + this.cfg.score[1] + '.</p>';
            }
    }

    //response specific
    /*if (this.cfg.specific.length > 0 && index >= 0) {
     str += ' ' + this.cfg.specific[index];
     }*/

    //correct/incorrect
    switch (this.correct) {
        case 0:
            str += (this.cfg.incorrect.length ? ' ' + this.cfg.incorrect : '');
            break;
        case this.total:
            str += (this.cfg.correct.length ? ' ' + this.cfg.correct : '');
            break;
        default:
            str += (this.cfg.partial.length ? ' ' + this.cfg.partial : (this.cfg.incorrect.length ? ' ' + this.cfg.incorrect : ''));
    }

    str += (this.cfg.always.length ? ' ' : '') + this.cfg.always;

    if (this.attempts == this.cfg.allowedAttempts) {
        this.maxAttemptsReached = true;
        str += '<p>The correct answer is now shown.</p>';
    }

    return str;
};

OU.Feedback.prototype.calculate = function() {
    this.total = 0;
    this.correct = 0;

    this.data.forEach(function(row) {
        row.forEach(function(data) {
            if (Array.isArray(data)) {
                data.forEach(function(data) {
                    if (data !== null) {
                        this.total++;
                        this.correct = data ? ++this.correct : this.correct;
                    }
                }.bind(this));
            }
            else {
                if (data !== null) {
                    this.total++;
                    this.correct = data ? ++this.correct : this.correct;
                }
            }
        }.bind(this));
    }.bind(this));

    //console.log(this.correct, this.total);
};

OU.Feedback.prototype.show = function(attempt) {
    var bb;

    if (this.visible) {
        this.hide();
    }

    this.attempts++;
    this.data = attempt;
    this.calculate();

    this.el.textContent = '';
    this.el.insertAdjacentHTML('beforeend', this.get());

    if (this.buttons.retry) {
        this.el.appendChild(this.buttons.retry);
    }
    else {
        this.el.insertAdjacentHTML('beforeend', '<p>Try again.</p>');
    }

    this.el.style.display = 'block';

    /*if (VLE && VLE.serverversion) {
     VLE.resize_iframe();
     }*/

    OU.utils.resize_iframe();

    if (window.frameElement) {
        bb = window.frameElement.getBoundingClientRect();

        if (bb.bottom > window.top.innerHeight) {
            window.top.scrollTo(0, window.top.pageYOffset + bb.bottom - window.top.innerHeight);
        }
    }
    else {
        //TODO needs work...
        //window.scrollTo(0, document.body.scrollHeight);
    }

    this.visible = true;

    if (this.correct > 0 && this.correct == this.total) {
        this.allCorrect = true;

        if (typeof this.cfg.whenCorrect === 'function') {
            this.cfg.whenCorrect.call(this);
        }
    }
};

OU.Feedback.prototype.hide = function() {
    this.el.textContent = '';
    this.el.style.display = 'none';

    /*if (VLE && VLE.serverversion) {
     VLE.resize_iframe();
     }*/

    OU.utils.resize_iframe();

    this.visible = false;
};

OU.Feedback.prototype.reset = function() {
    this.allCorrect = false;
    this.maxAttemptsReached = false;
    this.hide();
};