/* eslint no-var: "error"*/
/* eslint no-unused-vars: warn */
/* eslint max-depth: ["error", 6] */
/* eslint promise/no-nesting: "off" */
/* eslint camelcase: "off" */
/* eslint-env es6*/
// Put this file in path/to/plugin/amd/src

import {loadStrings} from './util/string-helper';
import {call} from 'core/ajax';
import notification from 'core/notification';
import TSComponents from './treestudyplan-components';
import FitTextVue from './util/fittext-vue';
import {formatDatetime} from "./util/date-helper";
import {svgarcpath} from './util/svgarc';

// Make π available as a constant
const π = Math.PI;
/**
 * Strip tags from html
 * @param {*} html
 * @returns {string}
 */
function striptags(html) {
    const tmp = document.createElement("DIV");
    tmp.innerHTML = html;
    const text = tmp.textContent || tmp.innerText;
    tmp.remove();
    return text;
}

/**
 * Retrieve condition headers
 * @param {Object} item
 * @returns {Array}
 */
function conditionHeaders(item) {
    const list = [];
    if (item.course) {
        const course = item.course;
        if (course.competency) {
            for (const cmp of course.competency.competencies) {
                list.push({
                    name: (cmp.details ? (`${cmp.title} - ${cmp.details}`) : cmp.title),
                    tooltip: (cmp.details ? (`${cmp.title} - ${cmp.details}`) : cmp.title),
                    link: cmp.link ? cmp.link : null
                });
            }
        } else if (course.completion) {
            for (const cnd of course.completion.conditions) {
                for (const itm of cnd.items) {
                    list.push({
                        name: itm.title,
                        tooltip: itm.title,
                        link: itm.link ? itm.link : null,
                    });
                }
            }
        } else if (course.grades) {
            for (const g of course.grades) {
                if (g.selected) {
                    list.push({
                        name: g.name,
                        tooltip: `${g.typename}: ${striptags(g.name)}`,
                        link: g.link ? g.link : null,
                    });
                }
            }
        }
    } else if (item.badge) {
        for (const typ of item.badge.criteria.types) {
            for (const crit of typ.criteria) {
                list.push({
                    name: typ.title + crit.title,
                    tooltip: typ.longtitle + "<br>" + crit.title,
                    link: crit.link ? crit.link : null,
                });
            }
        }
    }
    return list;
}

/**
 * Retrieve conditions
 * @param {Object} item
 * @returns {Array}
 */
function conditions(item) {
    const list = [];
    if (item.course) {
        const course = item.course;
        if (course.competency) {
            for (const cmp of course.competency.competencies) {
                list.push(cmp);
            }
        } else if (course.completion) {
            for (const cnd of course.completion.conditions) {
                for (const itm of cnd.items) {
                    list.push(itm);
                }
            }
        } else if (course.grades) {
            for (const g of course.grades) {
                if (g.selected) {
                    list.push(g);
                }
            }
        }
    } else if (item.badge) {
        for (const typ of item.badge.criteria.types) {
            for (const crit of typ.criteria) {
                list.push(crit);
            }
        }
    }
    return list;
}

/**
 * Retrieve userconditions
 * @param {Object} item
 * @returns {Array}
 */
function userconditions(item) {
    const list = [];
    if (item.course) {
        const course = item.course;
        if (course.competency) {
            for (const cmp of course.competency.competencies) {
                list.push(cmp);
            }
        } else if (course.completion) {
            for (const cnd of course.completion.conditions) {
                for (const itm of cnd.items) {
                    list.push(itm);
                }
            }
        } else if (course.grades) {
            for (const g of course.grades) {
                if (g.selected) {
                    list.push(g);
                }
            }
        }
    } else if (item.badge) {
        for (const typ of item.badge.completion.types) {
            for (const crit of typ.criteria) {
                list.push(crit);
            }
        }
    }
    return list;
}


export default {
    install(Vue /* ,options */) {
        Vue.use(TSComponents);
        Vue.use(FitTextVue);

        let strings = loadStrings({
            report: {
                loading: "loadinghelp@core",
                filter: "filter@core",
            },
            invalid: {
                error: 'error',
            },
            header: {
                overall: 'overall',
                students: 'students@core',
                firstname: 'firstname@core',
                lastname: 'lastname@core',
                email: 'email@core',
                lastaccess: 'lastaccess@core',
            },
            studentresults: {
                completion_incomplete: "completion_incomplete",
                completion_failed: "completion_failed",
                completion_pending: "completion_pending",
                completion_progress: "completion_progress",
                completion_completed: "completion_completed",
                completion_good: "completion_good",
                completion_excellent: "completion_excellent",
                student_not_tracked: "student_not_tracked",
                never: "never@core",
                yes: "yes@core",
                no: "no@core",
            }
        });

        /* **********************************
         *                                  *
         * Treestudyplan Viewer components  *
         *                                  *
         * **********************************/

        Vue.component('q-studyplanreport', {
            props: {
                structure: {
                    type: Object,
                },
            },
            data() {
                return {
                    students: [],
                    studentresults: {},
                    studentsloading: true,
                    expansioninfo: {
                        periods: {},
                        lines: {},
                        items: {},
                    },
                    groupinfo: {},
                    filter: "",
                    sorting: {
                        header: 'lastname',
                        asc: true,
                    },
                    text: strings.report
                };
            },
            watch: {
                structure: {
                    immediate: true,
                    handler(structure) {
                        this.loadStudents(); // Reload the student list
                        // (Re)build expansion info structure
                        let firstperiod = true;
                        for (const period of structure.periods) {
                            const pid = period.period.id;
                            if (!this.expansioninfo.periods[pid]) {
                                // Use this.$set to make sure the properties are reactive.
                                this.$set(
                                    this.expansioninfo.periods,
                                    pid,
                                    {
                                        expanded: ((firstperiod && period.lines.length > 0) ? true : false),
                                    }
                                );
                                this.$set(
                                    this.expansioninfo.lines,
                                    period.period.id,
                                    {}
                                );
                            }
                            for (const line of period.lines) {
                                const lid = line.line.id;
                                if (!this.expansioninfo.lines[lid]) {
                                    // Use this.$set to make sure the properties are reactive.
                                    this.$set(
                                        this.expansioninfo.lines[pid],
                                        lid,
                                        {
                                            expanded: true,
                                        }
                                    );
                                }
                                for (const item of line.items) {
                                    if (!this.expansioninfo.items[item.id]) {
                                        // Use this.$set to make sure the properties are reactive.
                                        this.$set(
                                            this.expansioninfo.items,
                                            item.id,
                                            {
                                            expanded: false,
                                            }
                                        );
                                    }
                                }
                            }
                            firstperiod = false;
                        }
                    }
                }
            },
            computed: {
                sortedstudents() {
                    // Make a deep copy first, to avoid messing up the data structure.
                    const students = JSON.parse(JSON.stringify(this.students));
                    for (const group of students) {
                        // Apply filter if needed.
                        if (this.filter.length > 0) {
                            const filter = new RegExp(RegExp.escape(this.filter), 'i');
                            const users = [];
                            for (const u of group.users) {
                                const name = u.firstname + " " + u.lastname;
                                if (name.match(filter)) {
                                    users.push(u);
                                }
                            }

                            group.users = users; // Overwrite with selection.
                        }

                        // Now sort the remaining users
                        group.users.sort((a, b) => {
                            let d = a;
                            let e = b;
                            if (!this.sorting.asc) {
                                d = b;
                                e = a;
                            }
                            if (this.sorting.header == "lastaccess") {
                                const dvalue = (d[this.sorting.header] ? d[this.sorting.header] : 0);
                                const evalue = (e[this.sorting.header] ? e[this.sorting.header] : 0);
                                return dvalue - evalue;
                            } else {
                                return String(d[this.sorting.header]).localeCompare(String(e[this.sorting.header]));
                            }
                        });

                    }
                    return students;
                },
            },
            methods: {
                loadStudents() {
                    const self = this;
                    self.studentsloading = true;
                    call([{
                        methodname: 'local_treestudyplan_all_associated_grouped',
                        args: {'studyplan_id': this.structure.studyplan.id}
                    }])[0].then((response) => {
                        self.students = response;
                        for (const group of self.students) {
                            self.$set(
                                self.groupinfo,
                                group.id,
                                {
                                  expanded: true,
                                }
                            );

                            for (const student of group.users) {
                                self.$set(
                                    self.studentresults,
                                    student.id,
                                    {
                                        loading: true,
                                        results: [],
                                    }
                                );
                                call([{
                                    methodname: 'local_treestudyplan_get_report_data',
                                    args: {
                                        pageid: self.structure.page.id,
                                        userid: student.id,
                                        firstperiod: self.structure.firstperiod,
                                        lastperiod: self.structure.lastperiod,
                                    }
                                }])[0].then((response) => {
                                    self.studentresults[student.id].loading = false;
                                    self.studentresults[student.id].results = response;
                                    return;
                                }).catch(notification.exception);
                            }
                        }
                        self.studentsloading = false;
                        return;
                    }).catch(notification.exception);
                },
                expansionChanged(parm, id, val) {
                    if (parm[0] == 'p') {
                        parm = 'periods';
                    } else if (parm[0] == 'l') {
                        parm = 'lines';
                    } else {
                        parm = 'items';
                    }

                    if (parm == 'lines') {
                        this.expansioninfo[parm][id[0]][id[1]].expanded = val;
                    } else {
                        this.expansioninfo[parm][id].expanded = val;
                    }
                },
                groupExpansionChanged(group) {
                    this.groupinfo[group.id].expanded = !this.groupinfo[group.id].expanded;
                },
                toggleSort(header) {
                    if (this.sorting.header == header) {
                        this.sorting.asc = !this.sorting.asc;
                    } else {
                        this.sorting.header = header;
                        this.sorting.asc = true;
                    }
                },
                resultColCount() {
                    let count = 0;
                    for (const period of this.structure.periods) {
                        const pid = period.period.id;
                        if (!this.expansioninfo.periods[pid].expanded) {
                            // This period is not expanded. Make it 2 units wide.
                            count += 2;
                        } else {
                            for (const line of period.lines) {
                                const lid = line.line.id;
                                if (!this.expansioninfo.lines[pid][lid].expanded) {
                                    count += 1;
                                } else {
                                    for (const item of line.items) {
                                        if (!this.expansioninfo.items[item.id].expanded) {
                                            count += 1;
                                        } else {
                                            count += 1 + conditions(item).length;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    return count;
                },
                resetFilter() {
                    this.filter = '';
                }
            },
            template: `
            <table class='q-studyplanreport'
                :style="'--resultColCount: '+resultColCount()+';'">
                <colgroup class="q-col-studentinfo">
                    <col class="q-name"></col>
                    <col class="q-lastaccess"></col>
                </colgroup>
                <colgroup class="q-col-resultinfo">
                    <col v-for="n in resultColCount"></col>
                </colgroup>
                <q-header
                    :sorting='sorting'
                    :structure='structure'
                    :expansion='expansioninfo'
                    @expansion='expansionChanged'
                    @togglesort="toggleSort"
                ><div class="q-studentfilter"
                    ><input type="text" class="form-control" v-model="filter" :placeholder="text.filter"
                    ></input><a v-if="filter" @click.prevent="resetFilter" href='#'
                    ><i class='fa fa-times'></i></a></template
                ></div></q-header>
                <template v-if="!studentsloading">
                    <template v-for="group in sortedstudents">
                        <q-groupheading
                            v-if="group.users && group.users.length > 0"
                            :group="group"
                            :expanded="groupinfo[group.id].expanded"
                            @togglegroup="groupExpansionChanged"
                            :resultcolumns="resultColCount()"
                            :studentinfocolumns="2"
                        ></q-groupheading>
                        <template v-if='groupinfo[group.id].expanded'>
                            <q-studentresults v-for="(student,idx) in group.users"
                                :key="'g'+group.id+'/'+student.id"
                                :student='student'
                                :even="(idx%2==1)"
                                :structure='structure'
                                :results='studentresults[student.id].results'
                                :loading='studentresults[student.id].loading'
                                :expansion='expansioninfo'
                                ></q-studentresults>
                        </template>
                    </template>
                </template>
                <q-inforow v-else
                    :resultcolumns="resultColCount()"
                    :studentinfocolumns="2"><div class="spinner-border spinner-border-sm text-info" role="status"></div></q-inforow>
            </table>
            `,
        });

        Vue.component('q-header', {
            props: {
                structure: {
                    type: Object,
                },
                sorting: {
                    type: Object,
                },
                expansion: {
                    type: Object
                },
            },
            data() {
                return {
                    text: strings.header,
                };
            },
            computed: {
            },
            methods: {
                conditions(item) {
                    return conditionHeaders(item);
                },
                colspanPeriod(period) {
                    const pid = period.period.id;
                    if (this.expansion.periods[pid].expanded) {
                        let sum = 0;
                        for (const l of period.lines) {
                            sum += this.colspanLine(period, l);
                        }
                        return sum;
                    } else {
                        return 2;
                    }
                },
                colspanLine(period, line) {
                    const pid = period.period.id;
                    const lid = line.line.id;

                    if (this.expansion.lines[pid][lid].expanded) {
                        let sum = 0;
                        for (const i of line.items) {
                            sum += this.colspanItem(i);
                        }
                        return sum;
                    } else {
                        return 1;
                    }
                },
                colspanItem(item) {
                    if (this.expansion.items[item.id].expanded) {
                        const cs = this.conditions(item);
                        return 1 + cs.length;
                    } else {
                        return 1;
                    }
                },
                togglePeriod(period, val) {
                    if (val === undefined) {
                        val = !(this.expansion.periods[period.id].expanded);
                    }
                    this.$emit('expansion', 'periods', period.id, val);
                },
                toggleLine(period, line, val) {
                    if (val === undefined) {
                        val = !(this.expansion.lines[period.id][line.id].expanded);
                    }
                    this.$emit('expansion', 'lines', [period.id, line.id], val);
                },
                toggleItem(item, val) {
                    if (val === undefined) {
                        val = !(this.expansion.items[item.id].expanded);
                    }
                    this.$emit('expansion', 'items', item.id, val);
                },
                toggleSort(heading) {
                    this.$emit('togglesort', heading);
                }
            },
            /* TODO: https://css-tricks.com/position-sticky-and-table-headers/ */
            template: `
            <thead class='q-header'>
                <tr> <!-- period heading -->
                    <th rowspan='4' colspan='2' class='q-studentinfo q-generic'><span>{{text.students}}</span><slot></slot></th>
                    <th v-for="p in structure.periods" 
                        :class="'q-period-heading '+ ((expansion.periods[p.period.id].expanded)?'expanded':'collapsed')"
                        :colspan='colspanPeriod(p)'
                        :rowspan='(expansion.periods[p.period.id].expanded && p.lines.length > 0)?1:5'
                        ><span class="q-wrap"><a v-if='(p.lines.length > 0)' href='#' @click.prevent="togglePeriod(p.period)"
                            ><i v-if="expansion.periods[p.period.id].expanded"
                                class='q-chevron fa fa-minus'></i
                            ><i v-else class='q-chevron fa fa-plus'></i
                        >&nbsp;<span v-html="p.period.display.fullname"></span></a
                        ><span v-else><span v-html="p.period.fullname"></span></span></span
                    ></th>
                </tr>
                <tr> <!-- line heading -->
                    <template v-for="p in structure.periods">
                        <template v-if="expansion.periods[p.period.id].expanded">
                            <th v-for="l in p.lines"
                                :class="'q-line-heading '
                                        + ((expansion.lines[p.period.id][l.line.id].expanded)?'expanded':'collapsed')"
                                :colspan="colspanLine(p,l)"
                                :rowspan='(expansion.lines[p.period.id][l.line.id].expanded)?1:4'
                                ><span class="q-wrap"><fittext vertical maxsize="18pt"
                                    ><span  class='q-label'
                                            :title="l.line.shortname"
                                            v-html="l.line.display.shortname"
                                    ></span
                                ></fittext></span
                            ></th>
                        </template>
                    </template>
                </tr>
                <tr> <!-- item heading -->
                    <template v-for="p in structure.periods">
                        <template v-if="expansion.periods[p.period.id].expanded">
                            <template v-for="l in p.lines">
                                <template v-if="expansion.lines[p.period.id][l.line.id].expanded">
                                    <th v-for="item in l.items"
                                        :class="'q-item-heading ' + ((expansion.items[item.id].expanded)?'expanded':'collapsed')"
                                        :colspan="colspanItem(item)"
                                        :rowspan='(expansion.items[item.id].expanded)?1:3'
                                        ><a class="q-wrap"  href='#' @click.prevent="toggleItem(item)"
                                            ><div class="q-toggle"
                                                ><i v-if="expansion.items[item.id].expanded"
                                                    class='q-chevron fa fa-minus'></i
                                                ><i v-else
                                                    class='q-chevron fa fa-plus'></i
                                            ></div><div class="q-title"
                                                ><fittext vertical maxsize="12pt" minsize="9pt"
                                                    ><span v-if="item.course" class='q-label'
                                                        :title="item.course.displayname"
                                                        v-html="item.course.displayname"
                                                    ></span
                                                    ><span v-if="item.badge" class="q-label"
                                                        :title="item.badge.name"
                                                    ><img class="q-badgeimage" :src="item.badge.imageurl"></span
                                                ></fittext
                                            ></div
                                        ></a
                                    ></th>
                                </template>
                            </template>
                        </template>
                    </template>
                </tr>
                <tr> <!-- condition heading -->
                    <template v-for="p in structure.periods">
                        <template v-if="expansion.periods[p.period.id].expanded">
                            <template v-for="l in p.lines">
                                <template v-if="expansion.lines[p.period.id][l.line.id].expanded">
                                    <template v-for="item in l.items">
                                        <template v-if="expansion.items[item.id].expanded">
                                            <th class='q-condition-heading overall' rowspan="2"
                                                ><span class='q-wrap'>{{ text.overall }}</span></th>
                                            <th v-for="(c, cidx) in conditions(item)"
                                                rowspan="2"
                                                class='q-condition-heading'
                                                ><span class="q-wrap"
                                                    ><b-tooltip
                                                        :target="'crit-item-'+item.id+'-crit-'+cidx"
                                                        ><span v-html="c.tooltip"></span></b-tooltip
                                                    ><fittext vertical maxsize="14pt"
                                                        ><a v-if="c.link" class='q-label q-condition-label'
                                                            :id="'crit-item-'+item.id+'-crit-'+cidx"
                                                            ><span v-html="c.name"></span></a
                                                        ><span v-else class='q-label q-condition-label'
                                                            :id="'crit-item-'+item.id+'-crit-'+cidx"
                                                            ><span v-html="c.name"></span></span
                                                ></fittext></span
                                            ></th>
                                        </template>
                                    </template>
                                </template>
                            </template>
                        </template>
                    </template>
                </tr>
                <tr> <!-- student info heading -->
                    <th class="q-studentinfo q-name">
                        <fittext maxsize="12pt"
                            ><a href="#" @click.prevent="toggleSort('firstname')">{{text.firstname}}</a
                            ><i v-if="sorting.header=='firstname' && sorting.asc" class='fa fa-sort-asc fa-fw'></i
                            ><i v-else-if="sorting.header=='firstname' && !sorting.asc" class='fa fa-sort-desc fa-fw'></i>
                            / <a href="#" @click.prevent="toggleSort('lastname')">{{text.lastname}}</a
                            ><i v-if="sorting.header=='lastname' && sorting.asc" class='fa fa-sort-asc fa-fw'></i
                            ><i v-else-if="sorting.header=='lastname' && !sorting.asc" class='fa fa-sort-desc fa-fw'></i
                        ></fittext>
                    </th>
                    <th class="q-studentinfo q-email">
                        <fittext maxsize="12pt"
                            ><a href="#" @click.prevent="toggleSort('lastaccess')">{{text.lastaccess}}</a
                            ><i v-if="sorting.header=='lastaccess' && sorting.asc" class='fa fa-sort-asc fa-fw'></i
                            ><i v-else-if="sorting.header=='lastaccess' && !sorting.asc" class='fa fa-sort-desc fa-fw'></i
                        ></fittext>
                    </th>
                </tr>
            </thead>
            `,
        });

        Vue.component('q-groupheading', {
            props: {
                group: {
                    type: Object,
                },
                resultcolumns: {
                    type: Number,
                    'default': 1
                },
                studentinfocolumns: {
                    type: Number,
                    'default': 1
                },
                expanded: {
                    type: Boolean,
                }
            },
            data() {
                return {

                };
            },
            computed: {
            },
            methods: {
                toggleGroup() {
                    this.$emit('togglegroup', this.group);
                }
            },
            template: `
            <tr class='q-groupheading'>
                <th :colspan="studentinfocolumns"><a href="#" @click.prevent="toggleGroup"
                    ><i v-if="expanded" class="fa fa-minus"></i
                    ><i v-else class="fa fa-plus"></i
                    >&nbsp;{{group.label}}</a></th>
                <td :colspan="resultcolumns"></td>
            </tr>
            `,
        });

        Vue.component('q-inforow', {
            props: {
                resultcolumns: {
                    type: Number,
                    'default': 1
                },
                studentinfocolumns: {
                    type: Number,
                    'default': 1
                },
            },
            data() {
                return {
                };
            },
            computed: {
            },
            methods: {
            },
            template: `
            <tr class='q-inforow'>
                <td :colspan="studentinfocolumns"><slot></slot></td>
                <td :colspan="resultcolumns"></td>
            </tr>
            `,
        });


        Vue.component('q-studentresults', {
            props: {
                student: {
                    type: Object,
                },
                structure: {
                    type: Object,
                },
                results: {
                    type: Array,
                },
                loading: {
                    type: Boolean,
                    'default': false
                },
                expansion: {
                    type: Object,
                },
                even: {
                    type: Boolean,
                    'default': false,
                }
            },
            data() {
                return {
                    text: strings.studentresults,
                };
            },
            computed: {
                lastaccess() {
                    if (this.student.lastaccess) {
                        return formatDatetime(this.student.lastaccess); // Takes date in milliseconds
                    } else {
                        return this.text.never;
                    }
                }
            },
            methods: {
                useritems(line) {
                    const list = [];
                    for (const item of line.items) {
                        let newitm = item;
                        for (const itm of this.results) {
                            if (item.id == itm.id) {
                                newitm = itm;
                                break;
                            }
                        }
                        list.push(newitm);
                    }
                    return list;
                },
                useritem(item) {
                    for (const itm of this.results) {
                        if (item.id == itm.id) {
                            return itm;
                        }
                    }
                    return {};
                },
                conditions(item) {
                    return conditions(item);
                },
                userconditions(item) {
                    return userconditions(item);
                },
            },
            /* https://css-tricks.com/position-sticky-and-table-headers/ */
            template: `
            <tr :class="'q-student-results userrow ' + (even?'even':'odd')">
                <td class='q-studentinfo q-name'><fittext maxsize="12pt">{{student.firstname}} {{student.lastname}}</fittext></td>
                <td class='q-studentinfo q-email'><fittext maxsize="12pt">{{lastaccess}}</fittext></td>
                <template v-for="p in structure.periods">
                    <template v-if="expansion.periods[p.period.id].expanded && p.lines.length > 0">
                        <template v-for="l in p.lines">
                            <template v-if="expansion.lines[p.period.id][l.line.id].expanded">
                                <template v-for="item in l.items">
                                    <td class='q-result overall'
                                        ><q-courseresult
                                            :item="useritem(item)"
                                            :student="student"
                                            :loading="loading"
                                        ></q-courseresult
                                    ></td>
                                    <template v-if="expansion.items[item.id].expanded">
                                        <td v-for="(c,idx) in conditions(item)"
                                            class='q-result'
                                            ><q-conditionresult
                                                :item="useritem(item)"
                                                :conditionidx="idx"
                                                :student="student"
                                                :loading="loading"
                                            ></q-conditionresult
                                        ></td>
                                    </template>
                                </template>
                            </template>
                            <td v-else class='q-result collapsed'>&nbsp;</td>
                        </template>
                    </template>
                    <td v-else colspan="2" class='q-result collapsed'>&nbsp;</td>
                </template>
            </tr>
            `,
        });

        Vue.component('q-courseresult', {
            props: {
                student: {
                    type: Object,
                },
                item: {
                    type: Object,
                },
                loading: {
                    type: Boolean,
                    'default': false
                },
            },
            data() {
                return {
                    text: strings.studentresults,
                };
            },
            computed: {
                hasprogressinfo() {
                    if (this.course) {
                        const course = this.item.course;
                        if (!course.enrolled) {
                            return false;
                        } else {
                            return (course.completion || course.competency || course.grades) ? true : false;
                        }
                    } else if (this.badge) {
                        return (this.badge.completion);
                    } else {
                        return false;
                    }
                },
                completion_icon() {
                    const completion = this.item.completion;
                    switch (completion) {
                        default: // Case "incomplete"
                            return "circle-o";
                        case "pending":
                            return "question-circle";
                        case "failed":
                            return "times-circle";
                        case "progress":
                            return "exclamation-circle";
                        case "completed":
                            return "check-circle";
                        case "good":
                            return "check-circle";
                        case "excellent":
                            return "check-circle";
                    }
                },
            },
            methods: {
            },
            template: `
            <span class='q-courseresult'>
                <template v-if="loading">
                    <div class="spinner-border spinner-border-sm text-info" role="status"></div>
                </template>
                <q-user-badge v-else-if='item.badge'
                    :item="item"
                ></q-user-badge>
                <template v-else-if='item.course && !item.course.enrolled'>
                    <i v-b-popover.top
                        class="fa fa-exclamation-triangle t-not-enrolled-alert"
                        :title="text.student_not_tracked"></i>
                </template>
                <template v-else-if="item.lineenrolled" >
                    <i v-b-popover.top
                        :class="'fa fa-'+completion_icon+
                                ' r-completion-'+item.completion"
                        :title="text['completion_'+item.completion]"></i>
                </template>
            </span>
            `,
        });

        Vue.component('q-conditionresult', {
            props: {
                student: {
                    type: Object,
                },
                item: {
                    type: Object,
                },
                loading: {
                    type: Boolean,
                    'default': false
                },
                conditionidx: {
                    type: Number,
                }
            },
            data() {
                return {
                    text: strings.studentresults,
                };
            },
            computed: {
                userconditions() {
                    return userconditions(this.item);
                },
                usercondition() {
                    if (this.conditionidx >= 0 && this.conditionidx < this.userconditions.length) {
                        return this.userconditions[this.conditionidx];
                    } else {
                        return null;
                    }
                },
                hasprogressinfo() {
                    if (this.item.course) {
                        const course = this.item.course;
                        if (!course.enrolled) {
                            return false;
                        } else {
                            return (course.completion || course.competency || course.grades) ? true : false;
                        }
                    } else if (this.item.badge) {
                        return (this.badge.completion);
                    } else {
                        return false;
                    }
                },
                completion_icon() {
                    const completion = this.condition_completion;
                    switch (completion) {
                        default: // Case "incomplete"
                            return "circle-o";
                        case "pending":
                            return "question-circle";
                        case "failed":
                            return "times-circle";
                        case "progress":
                            return "exclamation-circle";
                        case "completed":
                            return "check-circle";
                        case "good":
                            return "check-circle";
                        case "excellent":
                            return "check-circle";
                    }
                },
                condition_value() {
                    if (this.item.course) {
                        const course = this.item.course;
                        if (course.competency) {
                            if (this.usercondition.grade) {
                                // Return grade if possible.
                                return this.usercondition.grade;
                            }
                        } else if (course.completion) {
                            if (this.usercondition.grade) {
                                // Return grade if possible.
                                return this.usercondition.grade;
                            }
                        } else if (course.grades) {
                            return this.usercondition.grade;
                        }
                    } else if (this.item.badge) {
                        return this.usercondition.completed ? this.text.yes : this.text.no;
                    }
                    // Fallback to completion icon.
                    const icon = this.completion_icon();
                    return `<i class='fa fa-${icon}'></i>`;
                },
                condition_completion() {
                    // Unify completion information
                    if (this.item.course) {
                        const course = this.item.course;
                        if (course.competency) {
                            const competency = this.usercondition;
                            if (competency.proficient && competency.courseproficient) {
                                return "completed";
                            } else if (competency.proficient) {
                                return "completed";
                            } else if (competency.proficient === false) {
                                return "failed";
                            } else if (competency.progress) {
                                return "progress";
                            } else {
                                return "incomplete";
                            }
                        } else if (course.completion) {
                            return this.usercondition.status;
                        } else if (course.grades) {
                            return this.usercondition.completion;
                        } else {
                            return "incomplete";
                        }
                    } else if (this.item.badge) {
                        if (this.usercondition.completed) {
                            return "completed";
                        } else {
                            return "failed";
                        }
                    } else {
                        return "incomplete";
                    }
                }
            },
            methods: {
            },
            template: `
            <span class='q-conditionresult'>
                <fittext v-if="item.lineenrolled" maxsize="10pt" singleline dynamic>
                    <template v-if="loading">
                        <div class="spinner-border spinner-border-sm text-info" role="status"></div>
                    </template>
                    <template v-else-if='(item.course && !item.course.enrolled)'>
                        <i  class="fa fa-ellipsis-h"
                            :title="text.student_not_tracked"></i>
                    </template>
                    <template v-else>
                        <span
                            :class="'r-completion-'+condition_completion"
                            :title="text['completion_'+condition_completion]"
                            >{{condition_value}}</span
                        >
                    </template>
                </fittext>
            </span>
            `,
        });
        Vue.component('q-user-badge', {
            props: {
                item: {
                    type: Object,
                    default() {
                        return {};
                    },
                },
            },
            data() {
                return {
                    text: strings.badge,
                };
            },
            computed: {
                completion() {
                    return this.item.badge.issued ? "completed" : "incomplete";
                },
                arcpathIssued() {
                    if (this.item.badge.studentcount) {
                        const fraction = this.item.badge.issuedcount / this.item.badge.studentcount;
                        return this.arcpath(0, fraction);
                    } else {
                        return ""; // No path
                    }
                },
                arcpathProgress() {
                    if (this.item.badge.completion) {
                        const fraction = this.item.badge.completion.progress / this.item.badge.completion.count;
                        return this.arcpath(0, fraction);
                    } else {
                        return ""; // No path
                    }
                },
                badgeinprogress() {
                    return (
                        this.item.badge.issued ||
                        (
                            this.item.badge.completion
                            && this.item.badge.completion.progress >= this.item.badge.completion.count
                        )
                    );
                }
            },
            methods: {
                arcpath(start, end) {
                    const r = 44;
                    const t1 = start * 2 * π;
                    const Δ = (end * 2 * π - 0.01);
                    return svgarcpath([50, 50], [r, r], [t1, Δ], 1.5 * π);
                },
                status(complete) {
                    if (complete) {
                        return "complete";
                    } else {
                        return "incomplete";
                    }
                }
            },
            template: `
            <span :class="'q-user-badge r-completion-'+completion" v-b-tooltip.hover :title="item.badge.name"
                ><svg class="q-badge-backdrop " width='32px' height='32px' viewBox="0 0 100 100">
                    <title><span v-html="item.badge.name"></span></title>
                    <circle v-if="item.badge.issued" cx="50" cy="50" r="46"
                        style="stroke: currentcolor; stroke-width: 8; fill: currentcolor; fill-opacity: 0.5;"/>
                    <template v-else-if="item.badge.completion">
                        <circle cx="50" cy="50" r="44"
                            style="stroke: #ccc; stroke-width: 8; fill: #ddd; fill-opacity: 0.8;"/>
                        <path :d="arcpathProgress"
                            :style="'stroke-width: 8; stroke: var(--color-completed); fill: none;'"/>
                    </template>
                    <circle v-else cx="50" cy="50" r="46"
                        stroke-dasharray="6 9"
                        style="stroke: #999; stroke-width: 6; fill: #ddd; fill-opacity: 0.8;"/>
                    <image class="badge-image" clip-path="circle() fill-box"
                        :href="item.badge.imageurl" x="12" y="12" width="76" height="76"
                        :style="(badgeinprogress)?'':'opacity: 0.4;'" />
                </svg
            ></span>
            `,
        });

    },
};