/*eslint no-var: "error"*/
/*eslint no-console: "off"*/
/*eslint no-unused-vars: warn */
/*eslint max-len: ["error", { "code": 160 }] */
/*eslint-disable no-trailing-spaces */
/*eslint-env es6*/
// Put this file in path/to/plugin/amd/src

import {SimpleLine} from './simpleline';
import {get_strings} from 'core/str';
import {load_strings, format_date} from './string-helper';
import {call} from 'core/ajax';
import notification from 'core/notification';
import {svgarcpath} from './svgarc';
import Debugger from './debugger';
import Config from "core/config";

// Make π available as a constant
const π = Math.PI;
// Gravity value for arrow lines - determines how much a line is pulled in the direction of the start/end before changing direction
const LINE_GRAVITY = 1.3;

export default {
    install(Vue/*,options*/){
        let debug = new Debugger("treestudyplan-viewer");
        debug.enable();
        let lastCaller = null;
        /**
         * Scroll current period into view
         * @param {*} handle A key to pass so subsequent calls with the same key won't trigger (always triggers when null or undefined)
         */
        function scrollCurrentIntoView(handle){
            const elScrollContainer = document.querySelector(".r-studyplan-scrollable");
            const elCurrentHeader = elScrollContainer.querySelector(".s-studyline-header-period.current");

            if(elCurrentHeader && ((!handle) || (handle != lastCaller))){
                lastCaller = handle;
                elCurrentHeader.scrollIntoView({
                    behavior: "smooth",
                    block: "start",
                    inline: "center",
                });
            }
        }

        let strings = load_strings({
            invalid: {
                error: 'error',
            },
            grading: {
                ungraded: "ungraded",
                graded: "graded",
                allgraded: "allgraded",
                unsubmitted: "unsubmitted",
                nogrades: "nogrades",
                unknown: "unknown",
            },
            completion: {
                completed: "completion_completed",
                incomplete: "completion_incomplete",
                completed_pass: "completion_passed",
                completed_fail: "completion_failed",
                ungraded: "ungraded",
                aggregation_all: "aggregation_all",
                aggregation_any: "aggregation_any",
                aggregation_overall_all: "aggregation_overall_all",
                aggregation_overall_any: "aggregation_overall_any",
                completion_not_configured: "completion_not_configured",
                configure_completion: "configure_completion",
                view_completion_report: "view_completion_report",

            },
            badge: {
                share_badge: "share_badge",
                dateissued: "dateissued",
                dateexpire: "dateexpire",
                badgeinfo: "badgeinfo",
                badgeissuedstats: "badgeissuedstats",
            },
            course: {
                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",
                view_feedback: "view_feedback",
                coursetiming_past: "coursetiming_past",
                coursetiming_present: "coursetiming_present",
                coursetiming_future: "coursetiming_future",
                required_goal: "required_goal",
            },
            teachercourse: {
                select_conditions: "select_conditions",
                select_grades: "select_grades",
                coursetiming_past: "coursetiming_past",
                coursetiming_present: "coursetiming_present",
                coursetiming_future: "coursetiming_future",      
                grade_include: "grade_include",          
                grade_require: "grade_require",         
                required_goal: "required_goal",
            }

        });

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

        /**
         * Check if element is visible
         * @param {Object} elem The element to check
         * @returns {boolean} True if visible
         */
        function isVisible(elem){
            return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
        }

        // Create new eventbus for interaction between item components
        const ItemEventBus = new Vue();

        Vue.component('r-progress-circle',{
            props: {
                value: {
                    type: Number,
                },
                max: {
                    type: Number,
                    default: 100,
                },
                min: {
                    type: Number,
                    default: 0,
                },
                stroke: {
                    type: Number,
                    default: 0.2,
                },
                bgopacity: {
                    type: Number,
                    default: 0.2,
                },
                title: {
                    type: String,
                    default: "",
                },
                icon: {
                    type: String,
                }

            },
            data() {
                return {
                    selectedstudyplan: null,
                };
            },
            computed: {
                range() {
                    return this.max - this.min;
                },
                fraction(){
                    if(this.max - this.min == 0){
                        return 0;
                        // 0 size is always empty :)
                    } else {
                        return (this.value - this.min)/(this.max - this.min);
                    }
                },
                radius() {
                    return 50 - (50*this.stroke);
                },
                arcpath() {
                    let fraction = 0; 
                    const r = 50 - (50*this.stroke);
                    if(this.max - this.min != 0){
                        fraction = (this.value - this.min)/(this.max - this.min);
                    }

                    const Δ = fraction * 2*π;
                    return svgarcpath([50,50],[r,r],[0,Δ], 1.5*π);
                },
            },
            methods: {
            },
            template: `
            <div style="display: inline-block; width: 1em; height: 1em; position:relative; padding: 0;">
                <svg width="1em" height="1em" viewBox="0 0 100 100"
                     style="position: absolute;top: 0;left: 0;">
                    <title>{{title}}</title>
                    <circle v-if="fraction >= 1.0" cx="50" cy="50" :r="radius" 
                        :style="'opacity: 1; stroke-width: '+ (stroke*100)+'; stroke: currentcolor; fill: none;'"/>
                    <g v-else>
                        <circle cx="50" cy="50" :r="radius" 
                            :style="'opacity: ' + bgopacity + ';stroke-width: '+ (stroke*100)+'; stroke: currentcolor; fill: none;'"/>
                        <path :d="arcpath" 
                            :style="'stroke-width: ' + (stroke*100) +'; stroke: currentcolor; fill: none;'"/>
                    </g>
                </svg>
                <i v-if='icon' :class="'fa fa-'+icon" 
                    style=" position: absolute; top: 0.42em; left: 0.43em; text-align:center; display: inline-block; 
                            width:1em; font-size: 0.55em; "
                ></i>
            </div>
            `,
        });


        Vue.component('r-report', {
            props: {
                value: {
                    type: Array,
                },
                guestmode: {
                    type: Boolean,
                    default: false,
                },
                teachermode: {
                    type: Boolean,
                    default: false,
                }
            },
            data() {
                return {
                    selectedstudyplan: null,
                };
            },
            computed: {
                displayedstudyplan(){
                    if(this.selectedstudyplan){
                        return this.selectedstudyplan;
                    } else if(this.value && this.value.length > 0){
                        return this.value[0];
                    } else {
                        return null;
                    }
                }
            },
            methods: {
                selectstudyplan(plan) {
                    this.selectedstudyplan = plan;
                },
            },
            template: `
            <div class='t-studyplan-container'> 
                <b-list-group horizontal
                    class='r-report-tabs'>
                    <b-list-group-item 
                        v-for="(studyplan,planindex) in value"
                        :key="studyplan.id"
                        :active="displayedstudyplan && studyplan.id == displayedstudyplan.id"
                        button
                        @click="selectstudyplan(studyplan)"
                        >{{studyplan.name}}</b-list-group-item>
                </b-list-group>
                <r-studyplan v-if='displayedstudyplan' v-model='displayedstudyplan' :guestmode='guestmode' :teachermode='teachermode'></r-studyplan>
            </div>
            `,
        });

        Vue.component('r-studyplan', {
            props: {
                value: {
                    type: Object,
                },
                guestmode: {
                    type: Boolean,
                    default: false,
                },
                teachermode: {
                    type: Boolean,
                    default: false,
                }
            },
            data() {
                return {
                };
            },
            computed: {
                columns() {
                    return 1+ (this.page.periods * 2);
                },
                columns_stylerule() {
                    // Uses css variables, so width for slots and filters can be configured in css
                    let s = "grid-template-columns: var(--studyplan-filter-width)"; // use css variable here
                    for(let i=0; i<this.page.periods;i++){
                        s+= " var(--studyplan-course-width) var(--studyplan-filter-width)";
                    }
                    return s+";";
                },
                page() {
                    //FIXME: Replace this when actual page management is implemented
                    return this.value.pages[0];
                },
            },
            methods: {
                countLineLayers(line){
                    let maxLayer = -1;
                    for(let i = 0; i <= this.page.periods; i++){
                        const slot = line.slots[i];
                        // Determine the amount of used layers in a studyline slit
                        for(const ix in line.slots[i].competencies){
                            const item = line.slots[i].competencies[ix];
                            if(item.layer > maxLayer){
                                maxLayer = item.layer;
                            }
                        }
                        for(const ix in line.slots[i].filters){
                            const item = line.slots[i].filters[ix];
                            if(item.layer > maxLayer){
                                maxLayer = item.layer;
                            }
                        }
                    }
                    return (maxLayer >= 0)?(maxLayer+1):1;
                },
                showslot(line,index, layeridx, type){
                    // check if the slot should be hidden because a previous slot has an item with a span
                    // so big that it hides this slot
                    const forGradable = (type == 'gradable')?true:false;
                    const periods = this.page.periods;
                    let show = true;
                    for(let i = 0; i < periods; i++){
                        if(line.slots[index-i] && line.slots[index-i].competencies){
                            const list = line.slots[index-i].competencies;
                            for(const ix in list){ // Really wish that 'for of' would work with the minifier moodle uses
                                const item = list[ix];
                                if(item.layer == layeridx){
                                    if(forGradable){
                                        if(i > 0 && (item.span - i) > 0){
                                            show = false;
                                        }
                                    } else {
                                        if((item.span - i) >  1){
                                            show = false;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    
                    return show;
                }
            },
            mounted() {
                scrollCurrentIntoView(this.value.id);
            },
            updated() {
                scrollCurrentIntoView(this.value.id);
                ItemEventBus.$emit('lineHeightChange', null);

            },
            template: `
                <div class='r-studyplan-content'>
                    <!-- First paint the headings-->
                    <div class='r-studyplan-headings'
                        ><s-studyline-header-heading></s-studyline-header-heading>
                        <r-studyline-heading  v-for="(line,lineindex) in page.studylines"
                            :key="line.id"
                            v-model="page.studylines[lineindex]"
                            :layers='countLineLayers(line)+1'
                            :class=" 't-studyline' + ((lineindex%2==0)?' odd ' :' even ' )
                                    + ((lineindex==0)?' first ':' ') 
                                    + ((lineindex==page.studylines.length-1)?' last ':' ')"
                        ></r-studyline-heading
                    ></div>
                    <!-- Next, paint all the cells in the scrollable -->
                    <div class="r-studyplan-scrollable" >
                        <div class="r-studyplan-timeline" :style="columns_stylerule">
                        <!-- add period information -->
                        <template v-for="(n,index) in (page.periods+1)">
                            <s-studyline-header-period 
                                v-if="index > 0"
                                v-model="page.perioddesc[index-1]"
                                ></s-studyline-header-period>
                            <div class="s-studyline-header-filter"></div>
                        </template>
                             
                        <!-- Line by line add the items -->
                        <!-- The grid layout handles putting it in rows and columns -->
                        <template v-for="(line,lineindex) in page.studylines"
                            ><template v-for="(layernr,layeridx) in countLineLayers(line)"
                                ><template v-for="(n,index) in (page.periods+1)"
                                    ><r-studyline-slot 
                                        v-if="index > 0 && showslot(line, index, layeridx, 'gradable')"
                                        type='gradable'
                                        v-model="line.slots[index].competencies" 
                                        :key="'c-'+lineindex+'-'+index+'-'+layernr" 
                                        :slotindex="index" 
                                        :line="line"
                                        :plan="value"
                                        :page="page"
                                        :period="page.perioddesc[index-1]"
                                        :guestmode='guestmode'
                                        :teachermode='teachermode'
                                        :layer="layeridx"
                                        :class="'t-studyline ' + ((lineindex%2==0)?' odd ':' even ')
                                                + ((lineindex==0 && layernr==1)?' first ':' ')
                                                + ((lineindex==page.studylines.length-1)?' last ':' ')"
                                    ></r-studyline-slot
                                    ><r-studyline-slot 
                                        v-if="showslot(line, index, layeridx, 'gradable')"
                                        type='filter'
                                        v-model="line.slots[index].filters" 
                                        :teachermode='teachermode'
                                        :key="'f-'+lineindex+'-'+index+'-'+layernr" 
                                        :slotindex="index" 
                                        :line="line"
                                        :plan="value"
                                        :page="page"
                                        :layer="layeridx"
                                        :class="'t-studyline ' + ((lineindex%2==0)?' odd ':' even ')
                                                + ((lineindex==0 && layernr==1)?' first ':'')
                                                + ((lineindex==page.studylines.length-1)?' last ':' ')
                                                + ((index==page.periods)?' rightmost':'')"
                                        >
                                    </r-studyline-slot
                                ></template
                            ></template
                        ></template
                        ></div
                    ></div
                ></div>
            `,
        });

        /*
        * R-STUDYLINE-HEADER
        */
        Vue.component('r-studyline-heading', {
            props: {
                value : {
                    type: Object, // Studyline
                    default: function(){ return {};},
                },
                layers: {
                    type: Number,
                    default: 1,
                },
            },
            data() {
                return {
                    layerHeights: {}
                };
            },
            created() {
                    // Listener for the signal that a new connection was made and needs to be drawn
                    // Sent by the incoming item  - By convention, outgoing items are responsible for drawing the lines
                    ItemEventBus.$on('lineHeightChange', this.onLineHeightChange);
            },
            computed: {
                
            },
            methods: {
                onLineHeightChange(lineid){
                    // All layers for this line have the first slot send an update message on layer height change.
                    // When one of those updates is received, record the height and recalculate the total height of the 
                    // header
                    if(this.$refs.mainEl && (lineid == this.value.id || lineid === null)){
                        const items = document.querySelectorAll(
                            `.r-studyline-slot-0[data-studyline='${this.value.id}']`);
                        // determine the height of all the lines and add them up.
                        let heightSum = 0;
                        items.forEach((el) => {
                            // getBoundingClientRect() Gets the actual fractional height instead of rounded to integer pixels
                            const r = el.getBoundingClientRect();
                            const height = r.height;
                            heightSum += height;
                        });

                        const heightStyle=`${heightSum}px`;
                        this.$refs.mainEl.style.height = heightStyle;
                    }
                }
            },
            template: `
            <div class="r-studyline r-studyline-heading " 
                :data-studyline="value.id" ref="mainEl"
                ><div class="r-studyline-handle" :style="'background-color: ' + value.color"></div>
                <div class="r-studyline-title">
                    <abbr v-b-tooltip.hover :title="value.name">{{ value.shortname }}</abbr>
                </div>
            </div>
            `,
        });

        Vue.component('r-studyline-slot', {
            props: {
                value: {
                    type: Array, // item to display
                    default(){ return [];},
                },
                type : {
                    type: String,
                    default: 'gradable',
                },
                slotindex : {
                    type: Number,
                    default: 0,
                },
                line : {
                    type: Object,
                    default(){ return null;},
                },
                layer : {
                    type: Number,
                },   
                plan: {
                    type: Object,
                    default(){ return null;},
                },
                page: {
                    type: Object,
                    default(){ return null;},
                },                
                guestmode: {
                    type: Boolean,
                    default: false,
                },
                teachermode: {
                    type: Boolean,
                    default: false,
                },
                period: { 
                    type: Object,
                    default(){ return null;},
                }
            },
            mounted() {
                const self=this;
                if(self.type == "gradable" && self.slotindex == 1){
                    self.resizeListener = new ResizeObserver(() => {
                        if(self.$refs.sizeElement){
                            const height = self.$refs.sizeElement.getBoundingClientRect().height;
                            ItemEventBus.$emit('lineHeightChange', self.line.id, self.layer, height);
                        }
                    }).observe(self.$refs.sizeElement);
                }
            },
            computed: {
                item(){
                    for(const ix in this.value){
                        const itm = this.value[ix];
                        if(itm.layer == this.layer){
                            return itm;
                        }
                    }
                    return null;
                },
                current(){
                    if( this.period && this.period.startdate && this.period.enddate){
                        const now = new Date();
                        const pstart = new Date(this.period.startdate);
                        const pend = new Date(this.period.enddate);
                        return (now >= pstart && now < pend);
                    }
                    else {
                        return false;
                    }
                },
                spanCss(){
                    if(this.item && this.item.span > 1){
                        const span = (2 * this.item.span) - 1;
                        return `width: 100%; grid-column: span ${span};`;
                    } else {
                        return "";
                    }
                }
            },
            data() {
                return {
                };
            },
            methods: {
                
            },
            template: `
            <div :class="  'r-studyline-slot ' + type + ' ' + (current?'current ':' ') 
                         + 'r-studyline-slot-' + slotindex + ' ' 
                         + ((slotindex==0)?'r-studyline-firstcolumn ':' ')"
                :data-studyline="line.id" ref="sizeElement"
                :style='spanCss'
                ><div class="r-slot-item" v-if="item"
                    ><r-item 
                        v-model="item" 
                        :plan="plan"
                        :guestmode='guestmode'
                        :teachermode='teachermode'></r-item
                    ></div
                ></r-item
            ></div>
            `,
        });


        Vue.component('r-item', {
            props: {
                value :{
                    type: Object,
                    default: function(){ return null;},
                },      
                plan: {
                    type: Object,
                    default(){ return null;}
                },
                guestmode: {
                    type: Boolean,
                    default: false,
                },
                teachermode: {
                    type: Boolean,
                    default: false,
                }
            },
            data() {
                return {
                    lines: [],
                };
            },
            methods: {
                lineColor(){
                    if(this.teachermode){
                        return "var(--gray)";
                    }
                    else{
                        switch(this.value.completion){
                            default: // "incomplete"
                                return "var(--gray)";
                            case "failed":
                                return "var(--danger)";
                            case "progress":
                                return "var(--warning)";
                            case "completed":
                                return "var(--success)";
                            case "good":
                                return "var(--info)";
                            case "excellent":
                                return "var(--blue)";
                        }
                    }
                },
                redrawLine(conn){
                    let lineColor = this.lineColor();

                    // prepare lineinfo link or delete old line
                    let lineinfo = this.lines[conn.to_id];
                    if(lineinfo){
                        if(lineinfo.line){
                            lineinfo.line.remove();
                            lineinfo.line = undefined;
                        }
                    } else {
                        lineinfo = {};
                        this.lines[conn.to_id] = lineinfo;
                    }

                    // draw new line...
                    let start = document.getElementById('studyitem-'+conn.from_id);
                    let end= document.getElementById('studyitem-'+conn.to_id);
                    if(start !== null && end !== null && isVisible(start) && isVisible(end)){
                        lineinfo.line = new SimpleLine(start,end,{
                            color: lineColor,
                            gravity: {
                                start: LINE_GRAVITY,
                                end: LINE_GRAVITY,
                            },
                        });
                    }
                },
                redrawLines(){
                    // Clean all old lines
                    for(let ix in this.lines){
                        let lineinfo = this.lines[ix];
                        if(lineinfo && lineinfo.line){
                            lineinfo.line.remove();
                            lineinfo.line = undefined;
                        }
                    }

                    // Create new lines
                    for(let i in this.value.connections.out){
                        let conn = this.value.connections.out[i];
                        this.redrawLine(conn);
                    }
                },
                onWindowResize(){
                    this.redrawLines();
                }
            },
            computed: {
                hasConnectionsOut() {
                    return !(["finish",].includes(this.value.type));
                },
                hasConnectionsIn() {
                    return !(["start",].includes(this.value.type));
                },
                hasContext() {
                    return ['start','junction','finish'].includes(this.value.type);
                }
            },
            created(){
            
            },
            mounted(){
                // Initialize connection lines when mounting

                this.redrawLines();
                setTimeout(()=>{
                    this.redrawLines();
                },50);

                // Add resize event listener
                window.addEventListener('resize',this.onWindowResize);
            },
            beforeDestroy(){
                for(let i in this.value.connections.out){
                    let conn = this.value.connections.out[i];
                    let lineinfo = this.lines[conn.to_id];
                    if(lineinfo){
                        if(lineinfo.line){
                            if(lineinfo.lineElm ){
                                lineinfo.lineElm.parentNode.removeChild(lineinfo.lineElm);
                                lineinfo.lineElm = undefined;
                            } else {
                                lineinfo.line.remove();
                            }
                            lineinfo.line = undefined;
                        }
                    }            
                }
                // Remove resize event listener
                window.removeEventListener('resize',this.onWindowResize);
            },
            beforeUpdate(){
            },
            updated(){
                if(!this.dummy) {
                    this.redrawLines();
                }
            },
            template: `
            <div class="r-item-base" :id="'studyitem-'+value.id" :data-x='value.type'>
                <r-item-competency    v-if="value.type == 'competency'"
                    v-model="value" :guestmode="guestmode" :teachermode="teachermode" ></r-item-competency>
                <r-item-course        v-if="value.type == 'course' && !teachermode" :plan="plan"
                    v-model="value" :guestmode="guestmode" :teachermode="teachermode" ></r-item-course>
                <r-item-teachercourse v-if="value.type == 'course' && teachermode" :plan="plan"
                    v-model="value" :guestmode="guestmode" :teachermode="teachermode" ></r-item-teachercourse>
                <r-item-junction      v-if="value.type == 'junction'"
                    v-model="value" :guestmode="guestmode" :teachermode="teachermode" ></r-item-junction>
                <r-item-start         v-if="value.type == 'start'"
                    v-model="value" :guestmode="guestmode" :teachermode="teachermode" ></r-item-start>
                <r-item-finish        v-if="value.type == 'finish'"
                    v-model="value" :guestmode="guestmode" :teachermode="teachermode" ></r-item-finish>
                <r-item-badge         v-if="value.type == 'badge'"
                    v-model="value" :guestmode="guestmode" :teachermode="teachermode" ></r-item-badge>
                <r-item-invalid       v-if="value.type == 'invalid' && teachermode" 
                    v-model="value" ></r-item-invalid>
            </div>
            `,
        });

        Vue.component('r-item-invalid', {
            props: {
                'value' :{
                    type: Object,
                    default: function(){ return null;},
                },
            },
            data() {
                return {
                    text: strings.invalid,
                };
            },
            methods: {
            },
            template: `
            <b-card no-body class="r-item-invalid">
                <b-row no-gutters>
                    <b-col md="1">
                        <span class="r-timing-indicator timing-invalid"></span>
                    </b-col>
                    <b-col md="11">
                        <b-card-body class="align-items-center">
                            <i class="fa fa-exclamation"></i> {{ text.error }}
                        </b-card-body>
                    </b-col>
                </b-row>
            </b-card>
            `,
        });

        //TAG: Item Course
        Vue.component('r-item-course', {
            props: {
                value :{
                    type: Object,
                    default(){ return null;},
                },
                guestmode: {
                    type: Boolean,
                    default(){ return false;}
                },
                teachermode: {
                    type: Boolean,
                    default(){ return false;}
                },      
                plan: {
                    type: Object,
                    default(){ return null;}
                }
            },
            data() {
                return {
                    text: strings.course,
                };
            },
            computed: {
                startdate(){
                    return format_date(this.value.course.startdate);
                },
                enddate(){
                    if(this.value.course.enddate){
                        return format_date(this.value.course.enddate);
                    } 
                    else {
                        return this.text.noenddate;
                    }
                }
            },
            created(){
                const self = this;
                // Get text strings for condition settings
                let stringkeys = [];
                for(const key in  this.text){
                    stringkeys.push({ key: key, component: 'local_treestudyplan'});
                }
                get_strings(stringkeys).then(function(strings){
                    let i = 0;
                    for(const key in  self.text){
                        self.text[key] = strings[i];
                        i++;
                    }
                });
            },
            methods: {
                completion_icon(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";
                    }
                },
                circle_icon(completion) {
                    switch(completion){
                        default: // case "incomplete"
                            return null;
                        case "failed":
                            return "times";                            
                        case "progress":
                            return "exclamation";
                        case "completed":
                            return "check";
                        case "good":
                            return "check";
                        case "excellent":
                            return "check";
                    }
                },
            },
            template: `
            <b-card no-body :class="'r-item-competency completion-'+value.completion">
                <b-row no-gutters>
                    <b-col md="1">
                        <span 
                            :title="text['coursetiming_'+value.course.timing]" 
                            v-b-popover.hover.top="startdate+' - '+enddate" 
                            :class="'r-timing-indicator timing-'+value.course.timing"></span>
                    </b-col>
                    <b-col md="11">
                        <b-card-body class="align-items-center">
                            <template v-if='value.course.completion'>
                                <r-progress-circle v-if='["failed", "progress","incomplete"].includes(value.completion)'
                                    :value='value.course.completion.progress'
                                    :max='value.course.completion.count'
                                    :min='0'
                                    :class="'r-course-result r-completion-'+value.completion"
                                    :icon='circle_icon(value.completion)'
                                    :title="text['completion_'+value.completion]"
                                ></r-progress-circle>
                                <i v-else v-b-popover.top 
                                    :class="'r-course-result fa fa-'+completion_icon(value.completion)+
                                            ' r-completion-'+value.completion"
                                    :title="text['completion_'+value.completion]"></i>
                            </template>
                            <template v-else>
                                <i v-b-popover.top 
                                    :class="'r-course-result fa fa-'+completion_icon(value.completion)+
                                            ' r-completion-'+value.completion"
                                    :title="text['completion_'+value.completion]"></i>
                            </template>
                            <a  v-b-modal="'r-item-course-details-'+value.id" 
                                :href="(!guestmode)?('/course/view.php?id='+value.course.id):'#'"
                                @click.prevent.stop=''
                                >{{ value.course.displayname }}</i></a>
                        </b-card-body>
                    </b-col>
                </b-row>
            
                <b-modal
                    :id="'r-item-course-details-'+value.id" 
                    :title="value.course.displayname + ' - ' + value.course.fullname" 
                    size="lg"
                    ok-only
                    centered
                    scrollable
                    >
                    <template #modal-header>
                        <div>
                            <h1><a :href="(!guestmode)?('/course/view.php?id='+value.course.id):undefined" target="_blank"
                                ><i class="fa fa-graduation-cap"></i> {{ value.course.fullname }}</a></h1>
                            {{ value.course.context.path.join(" / ")}}
                        </div>
                        <div class="r-course-detail-header-right">
                            <div class="r-completion-detail-header">
                                <template v-if='value.course.completion'>
                                    {{text['completion_'+value.completion]}}
                                    <r-progress-circle v-if='["failed","progress","incomplete"].includes(value.completion)'
                                        :value='value.course.completion.progress'
                                        :max='value.course.completion.count'
                                        :min='0'
                                        :title="text['completion_'+value.completion]"
                                        :class="'r-progress-circle-popup r-completion-'+value.completion"
                                        :icon='circle_icon(value.completion)'
                                    ></r-progress-circle
                                    ><i v-else v-b-popover.top 
                                    :class="'fa fa-'+completion_icon(value.completion)+
                                            ' r-progress-icon-popup r-completion-'+value.completion"
                                    :title="text['completion_'+value.completion]"></i>
                                </template>
                                <template v-else>
                                    {{text['completion_'+value.completion]}}
                                    <i  :class="'fa fa-'+completion_icon(value.completion)+' r-completion-'+value.completion"
                                        :title="text['completion_'+value.completion]"></i>
                                </template>
                            </div>
                            <div :class="'r-timing-'+value.course.timing">
                                {{text['coursetiming_'+value.course.timing]}}<br>
                                {{ startdate }} - {{ enddate }}
                            </div>
                        </div>
                    </template>
                    <r-item-studentgrades 
                        v-if='!!value.course.grades && value.course.grades.length > 0' 
                        v-model='value'
                        :guestmode='guestmode'></r-item-studentgrades>
                    <r-item-studentcompletion
                        v-if='!!value.course.completion' 
                        v-model='value.course.completion'
                        :course='value.course'
                        :guestmode='guestmode'></r-item-studentcompletion>
                </b-modal>  
            </b-card>
            `,
        });

        //TAG: Selected activities dispaly
        Vue.component('r-item-studentgrades',{
            props: {
                value : {
                    type: Object,
                    default: function(){ return {};},
                },
                guestmode: {
                    type: Boolean,
                    default: false,
                },
            },
            data() {
                return {
                    text: strings.course,
                };
            },
            computed: {
                pendingsubmission(){
                    let result = false;
                    for(const ix in this.value.course.grades){
                        const g = this.value.course.grades[ix];
                        if(g.pendingsubmission){
                            result = true;
                            break;
                        }
                    }
                    return result;
                },
                useRequiredGrades() {
                    if(this.plan && this.plan.aggregation_info && this.plan.aggregation_info.useRequiredGrades !== undefined){
                        return this.plan.aggregation_info.useRequiredGrades;
                    }
                    else {
                        return false;
                    }
                },                
            },
            methods: {
                completion_icon(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";
                    }
                },
            },
            template: `
            <table class="r-item-course-grade-details">
                <tr v-for="g in value.course.grades">
                    <td><span class="r-activity-icon" :title="g.typename" v-html="g.icon"></span
                        ><a
                        :href="(!guestmode)?(g.link):undefined" target="_blank" :title="g.name">{{g.name}}</a>
                        <abbr v-if="useRequiredGrades && g.required" :title="text.required_goal"
                            :class="'s-required ' + g.completion"
                            ><i class='fa fa-asterisk' ></i
                        ></abbr>
                    </td>
                    <td><span :class="' r-completion-'+g.completion">{{g.grade}}</span></td>
                    <td><i :class="'fa fa-'+completion_icon(g.completion)+' r-completion-'+g.completion"
                        :title="text['completion_'+g.completion]"></i>
                        <i v-if='g.pendingsubmission' :title="text['completion_pending']" 
                            class="r-pendingsubmission fa fa-clock-o"></i></td>
                    <td v-if="g.feedback">
                        <a  v-b-modal="'r-grade-feedback-'+g.id" 
                            href="#" 
                        >{{ text["view_feedback"]}}</a>
                        <b-modal
                            :id="'r-grade-feedback-'+g.id" 
                            size="sm"
                            ok-only
                            centered
                            scrollable
                        >
                            <template #modal-header>
                                <h2><i class="fa fa-graduation-cap"></i>{{ value.course.fullname }}</h2><br>
                                <span class="r-activity-icon" :title="g.typename" v-html="g.icon"></span>{{g.name}}
                            </template>                        
                            <span v-html="g.feedback"></span>
                        </b-modal>
                    </td>
                </tr>
            </table>
            `,
        });

        //TAG: Core completion version of student course info
        Vue.component('r-item-studentcompletion',{
            props: {
                value : {
                    type: Object,
                    default: function(){ return {};},
                },
                guestmode: {
                    type: Boolean,
                    default: false,
                },
                course: {
                    type: Object,
                    default: function(){ return {};},
                },
            },
            data() {
                return {
                    text: {
                        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",
                        view_feedback: "view_feedback",
                        coursetiming_past: "coursetiming_past",
                        coursetiming_present: "coursetiming_present",
                        coursetiming_future: "coursetiming_future",
                        required_goal: "required_goal",
                    },
                };
            },
            created(){
                const self = this;
                // Get text strings for condition settings
                let stringkeys = [];
                for(const key in  this.text){
                    stringkeys.push({ key: key, component: 'local_treestudyplan'});
                }
                get_strings(stringkeys).then(function(strings){
                    let i = 0;
                    for(const key in  self.text){
                        self.text[key] = strings[i];
                        i++;
                    }
                });
            },
            computed: {
            },
            methods: {
                completion_icon(completion) {
                    switch(completion){
                        case "progress":
                            return "exclamation-circle";
                        case "complete":
                            return "check-circle";
                        case "complete-pass":
                            return "check-circle";
                        case "complete-fail":
                            return "times-circle";
                        default: // case "incomplete"
                            return "circle-o";
                    }
                },

                completion_tag(cgroup){
                    return cgroup.completion?'completed':'incomplete';
                }
            },
            template: `
            <table class="r-item-course-grade-details">
                <template v-for='cgroup in value.conditions'>
                    <tr>
                        <th colspan='2'>{{cgroup.title}}</th>
                        <th><r-progress-circle v-if="cgroup.progress < cgroup.count"
                                :value='cgroup.progress'
                                :max='cgroup.count'
                                :class="'r-completion-'+cgroup.status"
                                :title="text['completion_'+cgroup.status]"
                            ></r-progress-circle>
                            <i v-else :class="'fa fa-check-circle r-completion-'+cgroup.status"></i>
                            </th>
                    </tr>
                    <tr v-for='ci in cgroup.items'>
                        <td><span v-if='guestmode'>{{ci.title}}</span>
                            <span v-else v-html='ci.details.criteria'></span>
                            <a  href="#" v-b-tooltip.click="{ customClass: 'r-tooltip ' + ci.status}"
                                :title="ci.details.requirement"
                                :class="'s-required ' + ci.status"><i  v-if="ci.details.requirement" 
                                class='fa fa-question-circle' 
                                ></i></a>
                        <td><span :class="' r-completion-'+ci.status">{{ci.grade}}</span></td>
                        <td><i :class="'fa fa-'+completion_icon(ci.status)+' r-completion-'+ci.status"
                            :title="text['completion_'+ci.status]"></i>
                            <i v-if='ci.pending' :title="text['completion_pending']" 
                                class="r-pendingsubmission fa fa-clock-o"></i>
                        </td>
                        <td v-if="ci.feedback">
                            <a  v-b-modal="'r-grade-feedback-'+ci.id" 
                                href="#" 
                            >{{ text["view_feedback"]}}</a>
                            <b-modal
                                :id="'r-grade-feedback-'+ci.id" 
                                size="sm"
                                ok-only
                                centered
                                scrollable
                            >
                                <template #modal-header>
                                    <h2><i class="fa fa-graduation-cap"></i>{{ course.fullname }}</h2><br>
                                    <span class="r-activity-icon" :title="ci.typename" v-html="ci.icon"></span>{{ci.name}}
                                </template>
                                <span v-html="ci.feedback"></span>
                            </b-modal>
                        </td>
                    </tr>
                </template>
            </table>
            `,
        });

        //TAG: Teacher course
        Vue.component('r-item-teachercourse', {
            props: {
                value :{
                    type: Object,
                    default(){ return null;}
                },
                guestmode: {
                    type: Boolean,
                    default(){ return false;}
                },
                teachermode: {
                    type: Boolean,
                    default(){ return false;}
                },
                plan: {
                    type: Object,
                    default(){ return null;}
                }
            },
            data() {
                return {
                    text: strings.teachercourse,
                    txt: {
                        grading: strings.grading,
                    }
                };
            },
            computed: {
                course_grading_needed(){
                    return this.course_grading_state();
                },
                course_grading_icon(){
                    return this.determine_grading_icon(this.course_grading_state());
                },
                filtered_grades(){
                    return this.value.course.grades.filter(g => g.selected);
                },
                useRequiredGrades() {
                    if(this.plan && this.plan.aggregation_info && this.plan.aggregation_info.useRequiredGrades !== undefined){
                        return this.plan.aggregation_info.useRequiredGrades;
                    }
                    else {
                        return false;
                    }
                },
                isCompletable() {
                    let completable = false;
                    if(this.value.course.completion){
                        if(this.value.course.completion.conditions.length > 0){
                            completable = true;
                        }
                    } else if (this.value.course.grades){
                        if(this.value.course.grades.length > 0){
                            completable = true;
                        }
                    }

                    return completable;
                },
                progress_circle() { //INFO:
                    const status = {
                        students: 0,
                        completed: 0,
                        completed_pass: 0,
                        completed_fail: 0,
                        ungraded: 0,
                    };

                    if(this.value.course.completion){
                        for(const cond of this.value.course.completion.conditions){
                            for(const itm of cond.items){
                                if(itm.progress){
                                    status.students += itm.progress.students;
                                    status.completed += itm.progress.completed;
                                    status.completed_pass += itm.progress.completed_pass;
                                    status.completed_fail += itm.progress.completed_fail;
                                    status.ungraded += itm.progress.completed;
                                }
                            }
                        }

                    } else if (this.value.course.grades){
                        for( const g of this.value.course.grades){
                            if(g.grading){
                                status.students += g.grading.students;
                                status.completed += g.grading.completed;
                                status.completed_pass += g.grading.completed_pass;
                                status.completed_fail += g.grading.completed_fail;
                                status.ungraded += g.grading.ungraded;
                            }
                        }
                    }

                    return status;
                },
                startdate(){
                    return format_date(this.value.course.startdate);
                },
                enddate(){
                    if(this.value.course.enddate){
                        return format_date(this.value.course.enddate);
                    } 
                    else {
                        return this.text.noenddate;
                    }
                }
            },
            created(){
                const self = this;
                // Get text strings for condition settings
                let stringkeys = [];
                for(const key in  this.text){
                    stringkeys.push({ key: key, component: 'local_treestudyplan'});
                }
                get_strings(stringkeys).then(function(strings){
                    let i = 0;
                    for(const key in  self.text){
                        self.text[key] = strings[i];
                        i++;
                    }
                });
            },
            methods: {
                course_grading_state(){
                    let ungraded = 0;
                    let unknown = 0;
                    let graded = 0;
                    let allgraded = 0;
                    const grades = this.filtered_grades;

                    if(!Array.isArray(grades) || grades == 0){
                        return 'nogrades';
                    }

                    for(const ix in grades){
                        const grade = grades[ix];
                        if(grade.grading){
                            if(Number(grade.grading.ungraded) > 0){
                                ungraded++;
                            }
                            else if(Number(grade.grading.graded) > 0) {
                                if(Number(grade.grading.graded) == Number(grade.grading.students)){
                                    allgraded++;                                    
                                } else {
                                    graded++;
                                }
                            }
                        } else {
                            unknown = true;
                        }
                    }
                    
                    if(ungraded > 0){
                        return 'ungraded';
                    } else if(unknown) {
                        return 'unknown';
                    } else if(graded){
                        return 'graded';
                    } else if(allgraded){
                        return 'allgraded';
                    } else {
                        return 'unsubmitted';
                    }
                },
                determine_grading_icon(gradingstate){
                    switch(gradingstate){
                        default: // "nogrades":
                            return "circle-o";
                        case "ungraded":
                            return "exclamation-circle";
                        case "unknown":
                            return "question-circle-o";
                        case "graded":
                            return "check";
                        case "allgraded":
                            return "check";
                        case "unsubmitted":
                            return "dot-circle-o";
                    }
                },
            },
            template: `
            <b-card no-body :class="'r-item-competency '+ (value.course.amteacher?'r-course-am-teacher':'')">
                <div class='d-flex flex-wrap mr-0 ml-0'>
                    <div>
                        <span 
                            :title="text['coursetiming_'+value.course.timing]" 
                            v-b-popover.hover.top="startdate+' - '+enddate" 
                            :class="'r-timing-indicator timing-'+value.course.timing"></span>
                    </div>
                    <div class="flex-fill">
                        <b-card-body class="align-items-center">
                            <a  v-b-modal="'r-item-course-details-'+value.id" 
                                :href="(!guestmode)?('/course/view.php?id='+value.course.id):'#'"
                                @click.prevent.stop=''
                                >{{ value.course.displayname }}</i></a>
                            <r-completion-circle class="r-course-graded" :disabled="!isCompletable"
                                v-model="progress_circle"></r-completion-circle>
                        </b-card-body>
                    </div>
                </div>
                <b-modal
                    v-if="true"
                    :id="'r-item-course-details-'+value.id" 
                    :title="value.course.displayname + ' - ' + value.course.fullname" 
                    size="lg"
                    ok-only
                    centered
                    scrollable
                    >
                    <template #modal-header>
                        <div>
                            <h1><a :href="(!guestmode)?('/course/view.php?id='+value.course.id):undefined" target="_blank"
                                ><i class="fa fa-graduation-cap"></i> {{ value.course.fullname }}</a>
                                <r-item-teacher-gradepicker v-model="value.course"
                                    v-if="value.course.grades && value.course.grades.length > 0"
                                    :useRequiredGrades="useRequiredGrades"
                                    :plan="plan"
                                ></r-item-teacher-gradepicker>
                                <a v-if='!!value.course.completion && value.course.amteacher'  
                                    :href="'/course/completion.php?id='+value.course.id"  target="_blank"
                                    :title="text.configure_completion"><i class="fa fa-gear"></i></a>
                            </h1>
                            {{ value.course.context.path.join(" / ")}}
                        </div>
                        <div class="r-course-detail-header-right">
                            <div class="r-completion-detail-header">
                                <r-completion-circle class="r-progress-circle-popup" :disabled="!isCompletable"
                                    v-model="progress_circle"></r-completion-circle>
                            </div>
                            <div :class="'r-timing-'+value.course.timing">
                                {{ text['coursetiming_'+value.course.timing] }}<br>
                                {{ startdate }} - {{ enddate }}
                            </div>
                        </div>
                    </template>
                    <r-item-teachergrades 
                        v-if='!!value.course.grades && value.course.grades.length > 0' 
                        v-model='value.course'
                        :useRequiredGrades="useRequiredGrades"
                        ></r-item-teachergrades>
                    <r-item-teachercompletion
                        v-if='!!value.course.completion' 
                        v-model='value.course.completion'
                        :course='value.course'
                        ></r-item-teachercompletion>
                </b-modal>
 
            </b-card>
            `,
        });


    //TAG: Select activities to use in grade overview
    Vue.component('r-item-teacher-gradepicker', {
        props: {
            value : {
                type: Object,
                default: function(){ return {};},
            },
            useRequiredGrades: {
                type: Boolean,
                default(){ return null;}
            }
        },
        data() {
            return {
            };
        },
        computed: {
        },
        methods: {

        },
        template: `
            <a  v-if="value.canselectgradables" href='#' 
                                        v-b-modal="'r-item-course-config-'+value.id" 
                                        @click.prevent.stop=''
                                        ><i class='fa fa-cog'></i>
                <b-modal v-if='value.canselectgradables'
                    :id="'r-item-course-config-'+value.id" 
                    :title="value.displayname + ' - ' + value.fullname" 
                    ok-only
                    scrollable
                    >
                    <template #modal-header>
                        <div>
                            <h1><a :href="'/course/view.php?id='+value.id" target="_blank"
                                ><i class="fa fa-graduation-cap"></i> {{ value.fullname }}</a></h1>
                            {{ value.course.context.path.join(" / ")}} / {{value.displayname}}
                        </div>
                        <div class="r-course-detail-header-right">
                            <div :class="'r-timing-'+value.timing">
                                {{text['coursetiming_'+value.timing]}}<br>
                                {{ value.startdate }} - {{ value.enddate }}
                            </div>
                        </div>
                    </template>
                    <b-form-group
                        :label="text.select_grades"
                        ><ul class="t-item-module-children">
                            <li class="t-item-course-gradeinfo">
                                <span class='t-item-course-chk-lbl'>{{text.grade_include}}</span
                                ><span v-if="useRequiredGrades"  class='t-item-course-chk-lbl'>{{text.grade_require}}</span>
                            </li>
                            <li class="t-item-course-gradeinfo" v-for="g in value.grades">
                                <b-form-checkbox inline
                                    @change="includeChanged($event,g)" v-model="g.selected"
                                    ></b-form-checkbox>
                                <b-form-checkbox v-if="useRequiredGrades" inline :disabled="!g.selected"
                                    @change="requiredChanged($event,g)" v-model="g.required"
                                    ></b-form-checkbox>
                                <span :title="g.typename" v-html="g.icon"></span><a 
                                    :href="g.link" target="_blank">{{g.name}}</a>
                                <s-edit-mod 
                                    :title="value.fullname"
                                    @saved="(fd) => g.name = fd.get('name')"
                                    v-if="g.cmid > 0" 
                                    :cmid="g.cmid" 
                                    :coursectxid="value.ctxid"
                                    genericonly></s-edit-mod>
                            </li>
                        </ul>
                    </b-form-group>
                </b-modal></a>
        `,
    });



    //TAG: Selected activities dispaly
    Vue.component('r-item-teachergrades',{
        props: {
            value : {
                type: Object,
                default: function(){ return {};},
            },
            useRequiredGrades: {
                type: Boolean,
                default: false,
            },
        },
        data() {
            return {
                text: strings.teachercourse,
                txt: {
                    grading: strings.grading,
                }
            };
        },
        computed: {
            pendingsubmission(){
                let result = false;
                for(const ix in this.value.grades){
                    const g = this.value.grades[ix];
                    if(g.pendingsubmission){
                        result = true;
                        break;
                    }
                }
                return result;
            },
            filtered_grades(){
                return this.value.grades.filter(g => g.selected);
            },
        },
        methods: {
            determine_grading_icon(gradingstate){
                switch(gradingstate){
                    default: // "nogrades":
                        return "circle-o";
                    case "ungraded":
                        return "exclamation-circle";
                    case "unknown":
                        return "question-circle-o";
                    case "graded":
                        return "check";
                    case "allgraded":
                        return "check";
                    case "unsubmitted":
                        return "dot-circle-o";
                }
            },
            grading_icon(grade){
                return this.determine_grading_icon(this.is_grading_needed(grade));
            },
            is_grading_needed(grade){
                if(grade.grading){
                    if(grade.grading.ungraded){
                        return 'ungraded';
                    } 
                    else if(grade.grading.completed_pass || grade.grading.completed || grade.grading.completed_fail) {
                        if(Number(grade.grading.completed) + Number(grade.grading.completed_pass)
                            + Number(grade.grading.completed_fail)
                             == Number(grade.grading.students)){
                            return 'allgraded';
                        }
                        else {
                            return 'graded';
                        }
                    }
                    else {
                        return 'unsubmitted';
                    }
                } else {
                    return 'unknown';
                }
            },
            includeChanged(newValue,g){
                call([{
                    methodname: 'local_treestudyplan_include_grade',
                    args: { 'grade_id': g.id,
                            'item_id': this.value.id, 
                            'include': newValue,
                            'required': g.required,
                            }
                }])[0].fail(notification.exception);
            },
            requiredChanged(newValue,g){
                call([{
                    methodname: 'local_treestudyplan_include_grade',
                    args: { 'grade_id': g.id,
                            'item_id': this.value.id, 
                            'include': g.selected,
                            'required': newValue,
                            }
                }])[0].fail(notification.exception);
            },                
        },
        template: `
        <div>
            <table class="r-item-course-grade-details">
                <tr v-for="g in filtered_grades">
                    <td><span class="r-activity-icon" :title="g.typename" v-html="g.icon"></span
                        ><a
                        :href="g.gradinglink"
                        target="_blank" :title="g.name">{{g.name}}</a>
                        <s-edit-mod 
                            :title="value.fullname"
                            @saved="(fd) => g.name = fd.get('name')"
                            v-if="g.cmid > 0" 
                            :cmid="g.cmid" 
                            :coursectxid="value.ctxid"
                            genericonly></s-edit-mod>
                        <abbr v-if="useRequiredGrades && g.required" :title="text.required_goal"
                            :class="'s-required ' + is_grading_needed(g)"
                            ><i class='fa fa-asterisk' ></i
                        ></abbr>                                
                    </td>
                    <td v-if='g.grading'
                        ><i :class="'r-course-grading fa fa-'+grading_icon(g)+' r-graded-'+is_grading_needed(g)"
                        :title="txt.grading[is_grading_needed(g)]"></i>
                    </td>
                    <td v-if='g.grading'>
                        <r-completion-bar v-model="g.grading" :width="150" :height="15"></r-completion-bar>
                    </td>
                </tr>
            </table>
        </div>
        `,
    });

    //TAG: Core completion version of student course info
    Vue.component('r-item-teachercompletion',{
        props: {
            value : {
                type: Object,
                default: function(){ return {};},
            },
            guestmode: {
                type: Boolean,
                default: false,
            },
            course: {
                type: Object,
                default: function(){ return {};},
            },
        },
        data() {
            return {
                text: strings.completion,
            };
        },
        created(){
            const self = this;
            // Get text strings for condition settings
            let stringkeys = [];
            for(const key in  this.text){
                stringkeys.push({ key: key, component: 'local_treestudyplan'});
            }
            get_strings(stringkeys).then(function(strings){
                let i = 0;
                for(const key in  self.text){
                    self.text[key] = strings[i];
                    i++;
                }
            });
        },
        computed: {
            completionreport(){
                return `${Config.wwwroot}/report/completion/index.php?course=${this.course.id}`;
            }
        },
        methods: {
            hasCompletions() {
                if(this.value.conditions) {
                    for(const cgroup of this.value.conditions){
                        if(cgroup.items && cgroup.items.length > 0){
                            return true;
                        }
                    }
                }
                return false;
            },
        },
        template: `
        <table class="r-item-course-grade-details">
            <tr v-if="hasCompletions">
                <td colspan='2'><span v-if="value.aggregation == 'all'">{{ text.aggregation_overall_all}}</span
                ><span v-else>{{ text.aggregation_overall_any}}</span></td>
            </tr>
            <tr v-else>
                <td colspan='2'>{{text.completion_not_configured}}!
                <span v-if="course.amteacher">
                    <br><a :href="'/course/completion.php?id='+course.id" target='_blank'>{{text.configure_completion}}</a>
                </span>
                </td>
            </tr>
            <template v-for='cgroup in value.conditions'>
                <tr>
                    <th colspan='2'><span v-if="cgroup.items.length > 1"
                    ><span v-if="cgroup.aggregation == 'all'">{{ text.aggregation_all}}</span
                    ><span v-else>{{ text.aggregation_any}}</span></span>
                    {{cgroup.title}}</th>
                </tr>
                <tr v-for='ci in cgroup.items'>
                    <td><span v-html='ci.details.criteria'></span>
                        <a  href="#" v-b-tooltip.click
                            :title="ci.details.requirement"
                            class='text-info'><i  v-if="ci.details.requirement" 
                            class='fa fa-question-circle' 
                            ></i></a>
                    </td>
                    <td>
                        <r-completion-bar v-model="ci.progress" :width="150" :height="15"></r-completion-bar>
                    </td>
                </tr>
            </template>
            <tr><td colspan='2' class='pt-2'>
                <a target="_blank" :href='completionreport'>{{ text.view_completion_report}} 
                <i class='fa fa-external-link'></i></a></td></tr>
        </table>
        `,
    });


        Vue.component('r-grading-bar',{
            props: {
                value : {
                    type: Object,
                    default: function(){ return {};},
                },
                width: {
                    type: Number,
                    default: 150,
                },
                height: {
                    type: Number,
                    default: 15,
                }
            },
            data() {
                return {
                    text: strings.grading,
                };
            },
            computed: {
                width_unsubmitted() {
                    return this.width * this.fraction_unsubmitted();
                },
                width_graded() {
                    return this.width * this.fraction_graded();
                },
                width_ungraded() {
                    return this.width * this.fraction_ungraded();
                },
                count_unsubmitted(){
                    return (this.value.students - this.value.graded - this.value.ungraded);
                }
            },
            methods: {
                fraction_unsubmitted() {
                    if(this.value.students > 0){
                        return 1 - ((this.value.graded + this.value.ungraded) / this.value.students);
                    } else {
                        return 1;
                    }
                },
                fraction_graded() {
                    if(this.value.students > 0){
                        return this.value.graded / this.value.students;
                    } else {
                        return 0;
                    }
                },
                fraction_ungraded() {
                    if(this.value.students > 0){
                        return this.value.ungraded / this.value.students;
                    } else {
                        return 0;
                    }
                },
            },
            template: `
            <span class="r-grading-bar" :style="{height: height+'px'}"
                ><span  :style="{height: height+'px', width: width_ungraded+'px'}"
                        class='r-grading-bar-segment r-grading-bar-ungraded'
                        :title="text.ungraded + ' (' + this.value.ungraded + ')'" v-b-popover.hover.top
                ></span
                ><span  :style="{height: height+'px', width: width_graded+'px'}"
                        class='r-grading-bar-segment r-grading-bar-graded'
                        :title="text.graded+ ' (' + this.value.graded + ')'" v-b-popover.hover.top
                ></span
                ><span  :style="{height: height+'px', width: width_unsubmitted+'px'}"
                        class='r-grading-bar-segment r-grading-bar-unsubmitted'
                        :title="text.unsubmitted + ' (' + count_unsubmitted + ')'" v-b-popover.hover.top
                ></span
            ></span>
            `,
        });

        Vue.component('r-completion-bar',{
            props: {
                value : {
                    type: Object,
                    default: function(){ return {
                        students: 0,
                        completed: 0,
                        completed_pass: 0,
                        completed_fail: 0,
                        ungraded: 0,
                    };},
                },
                width: {
                    type: Number,
                    default: 150,
                },
                height: {
                    type: Number,
                    default: 15,
                }
            },
            data() {
                return {
                    text: strings.completion,
                };
            },
            computed: {
                width_incomplete() {
                    return this.width * this.fraction_incomplete();
                },
                width_completed() {
                    return this.width * this.fraction_completed();
                },
                width_completed_pass() {
                    return this.width * this.fraction_completed_pass();
                },
                width_completed_fail() {
                    return this.width * this.fraction_completed_fail();
                },
                width_ungraded() {
                    return this.width * this.fraction_ungraded();
                },
                count_incomplete(){
                    return (this.value.students - this.value.completed - this.value.completed_pass
                             - this.value.completed_fail - this.value.ungraded);
                }
            },
            methods: {
                fraction_incomplete() {
                    if(this.value.students > 0){
                        return 1 - (
                            (this.value.completed + this.value.completed_pass +
                             this.value.completed_fail + this.value.ungraded) / this.value.students);
                    } else {
                        return 1;
                    }
                },
                fraction_completed() {
                    if(this.value.students > 0){
                        return this.value.completed / this.value.students;
                    } else {
                        return 0;
                    }
                },
                fraction_completed_pass() {
                    if(this.value.students > 0){
                        return this.value.completed_pass / this.value.students;
                    } else {
                        return 0;
                    }
                },
                fraction_completed_fail() {
                    if(this.value.students > 0){
                        return this.value.completed_fail / this.value.students;
                    } else {
                        return 0;
                    }
                },
                fraction_ungraded() {
                    if(this.value.students > 0){
                        return this.value.ungraded / this.value.students;
                    } else {
                        return 0;
                    }
                },
            },
            template: `
            <span class="r-grading-bar" :style="{height: height+'px'}"
                ><span  :style="{height: height+'px', width: width_ungraded+'px'}"
                        class='r-grading-bar-segment r-completion-bar-ungraded'
                        :title="text.ungraded + ' (' + this.value.ungraded + ')'" v-b-popover.hover.top
                ></span
                ><span  :style="{height: height+'px', width: width_completed+'px'}"
                        class='r-grading-bar-segment r-completion-bar-completed'
                        :title="text.completed + ' (' + this.value.completed + ')'" v-b-popover.hover.top
                ></span
                ><span  :style="{height: height+'px', width: width_completed_pass+'px'}"
                        class='r-grading-bar-segment r-completion-bar-completed-pass'
                        :title="text.completed_pass + ' (' + this.value.completed_pass + ')'" v-b-popover.hover.top
                ></span
                ><span  :style="{height: height+'px', width: width_completed_fail+'px'}"
                        class='r-grading-bar-segment r-completion-bar-completed-fail'
                        :title="text.completed_fail + ' (' + this.value.completed_fail + ')'" v-b-popover.hover.top
                ></span
                ><span  :style="{height: height+'px', width: width_incomplete+'px'}"
                        class='r-grading-bar-segment r-completion-bar-incomplete'
                        :title="text.incomplete + ' (' + count_incomplete + ')'" v-b-popover.hover.top
                ></span
            ></span>
            `,
        });

        Vue.component('r-completion-circle',{
            props: {
                value : {
                    type: Object,
                    default: function(){ return {
                        students: 10,
                        completed: 2,
                        completed_pass: 2,
                        completed_fail: 2,
                        ungraded: 2,
                    };},
                },
                stroke: {
                    type: Number,
                    default: 0.2,
                },
                disabled: {
                    type: Boolean,
                    default: false,
                },
                title: {
                    type: String,
                    default: "",
                }
            },
            computed: {
                radius() {
                    return 50 - (50*this.stroke);
                },

                arcpath_ungraded() {
                    const begin = 0;
                    return this.arcpath(begin,this.fraction_ungraded());
                },
                arcpath_completed() {
                    const begin = this.fraction_ungraded();
                    return this.arcpath(begin,this.fraction_completed());
                },
                arcpath_completed_pass() {
                    const begin = this.fraction_ungraded()
                                + this.fraction_completed();
                    return this.arcpath(begin,this.fraction_completed_pass());
                },
                arcpath_completed_fail() {
                    const begin = this.fraction_ungraded()
                                + this.fraction_completed()
                                + this.fraction_completed_pass();
                    return this.arcpath(begin,this.fraction_completed_fail());
                },
                arcpath_incomplete() {
                    const begin = this.fraction_ungraded() 
                                + this.fraction_completed()
                                + this.fraction_completed_pass()
                                + this.fraction_completed_fail();
                    return this.arcpath(begin,this.fraction_incomplete());
                },

            },
            methods: {
                arcpath(start, end) {
                    const r = 50 - (50*this.stroke);

                    const t1  = start * 2*π;
                    const Δ = end * 2*π;
                    return svgarcpath([50,50],[r,r],[t1,Δ], 1.5*π);
                },
                fraction_incomplete() {
                    if(this.value.students > 0){
                        return 1 - (
                            (this.value.completed + this.value.completed_pass +
                                this.value.completed_fail + this.value.ungraded) / this.value.students);
                    } else {
                        return 1;
                    }
                },
                fraction_completed() {
                    if(this.value.students > 0){
                        return this.value.completed / this.value.students;
                    } else {
                        return 0;
                    }
                },
                fraction_completed_pass() {
                    if(this.value.students > 0){
                        return this.value.completed_pass / this.value.students;
                    } else {
                        return 0;
                    }
                },
                fraction_completed_fail() {
                    if(this.value.students > 0){
                        return this.value.completed_fail / this.value.students;
                    } else {
                        return 0;
                    }
                },
                fraction_ungraded() {
                    if(this.value.students > 0){
                        return this.value.ungraded / this.value.students;
                    } else {
                        return 0;
                    }
                },
            },
            template: `
            <svg width="1em" height="1em" viewBox="0 0 100 100">
                <title>{{title}}</title>
                <circle cx="50" cy="50" :r="radius" 
                    :style="'stroke-width: ' + (stroke*100)+'; stroke: #ccc; fill: none;'"/>
                <path :d="arcpath_ungraded" 
                    :style="'stroke-width: ' + (stroke*100) +'; stroke: var(--warning); fill: none;'"/>
                <path :d="arcpath_completed" 
                    :style="'stroke-width: ' + (stroke*100) +'; stroke: var(--info); fill: none;'"/>
                <path :d="arcpath_completed_pass" 
                    :style="'stroke-width: ' + (stroke*100) +'; stroke: var(--success); fill: none;'"/>
                <path :d="arcpath_completed_fail" 
                    :style="'stroke-width: ' + (stroke*100) +'; stroke: var(--danger); fill: none;'"/>
                
                <circle v-if="disabled" cx="50" cy="50" :r="radius/2" 
                    :style="'fill: var(--dark);'"/>
                <circle v-else-if="value.ungraded > 0" cx="50" cy="50" :r="radius/2" 
                    :style="'fill: var(--warning);'"/>
            </g>
            </svg>
            `,
        });

        Vue.component('r-item-junction',{
            props: {
                value : {
                    type: Object,
                    default: function(){ return {};},
                },
                guestmode: {
                    type: Boolean,
                    default: false,
                },
                teachermode: {
                    type: Boolean,
                    default: false,
                }
            },
            data() {
                return {
                };
            },
            computed: {
                completion(){
                    if(this.value.completion){
                        return this.value.completion;
                    } else {
                        return "incomplete";
                    }
                }
            },
            methods: {

            },
            template: `
            <div :class="'r-item-junction r-item-filter completion-'+completion"> 
                <i v-if="value.completion=='incomplete'" class="fa fa-circle-o"></i>
                <i v-else-if="value.completion=='failed'" class="fa fa-times-circle"></i>
                <i v-else-if="value.completion=='progress'" class="fa fa-exclamation-circle"></i>
                <i v-else class="fa fa-check-circle"></i>
            </div>
            `,
        });

        Vue.component('r-item-finish',{
            props: {
                value : {
                    type: Object,
                    default: function(){ return {};},
                },
                guestmode: {
                    type: Boolean,
                    default: false,
                },
                teachermode: {
                    type: Boolean,
                    default: false,
                }
            },
            data() {
                return {
                };
            },
            computed: {
                completion(){
                    if(this.value.completion){
                        return this.value.completion;
                    } else {
                        return "incomplete";
                    }
                }
            },
            methods: {
            },
            template: `
            <div :class="'r-item-finish r-item-filter completion-'+completion"> 
                <i class="fa fa-stop-circle"></i>
            </div>    
            `,
        });

        Vue.component('r-item-start',{
            props: {
                value : {
                    type: Object,
                    default: function(){ return {};},
                },
                guestmode: {
                    type: Boolean,
                    default: false,
                },
                teachermode: {
                    type: Boolean,
                    default: false,
                }
            },
            data() {
                return {
                };
            },
            computed: {
                completion(){
                    if(this.value.completion){
                        return this.value.completion;
                    } else {
                        return "incomplete";
                    }
                }
            },    
            created(){
        
            },
            methods: {
            },
            template: `
            <div :class="'r-item-start r-item-filter completion-'+completion">
                <i class="fa fa-play-circle"></i>
            </div>
            `,
        });

        Vue.component('r-item-badge',{
            props: {
                value : {
                    type: Object,
                    default: function(){ return {};},
                },
                guestmode: {
                    type: Boolean,
                    default: false,
                },
                teachermode: {
                    type: Boolean,
                    default: false,
                }
            },
            data() {
                return {
                    txt: strings
                };
            },
            computed: {
                completion() {
                    return this.value.badge.issued?"completed":"incomplete";
                },
                issued_icon(){
                    switch(this.value.badge.issued){
                        default: // "nogrades":
                            return "circle-o";
                        case true:
                            return "check";
                    }
                },
                issuestats(){
                    // so the r-completion-bar can be used to show issuing stats
                    return {
                        students: (this.value.badge.studentcount)?this.value.badge.studentcount:0,
                        completed: (this.value.badge.issuedcount)?this.value.badge.issuedcount:0,
                        completed_pass: 0,
                        completed_fail: 0,
                        ungraded: 0,
                    };
                },
                arcpath_issued(){
                    if(this.value.badge.studentcount){
                        const fraction = this.value.badge.issuedcount/this.value.badge.studentcount;
                        return this.arcpath(0,fraction);
                    } else {
                        return ""; // no path
                    }
                }

            },
            methods: {
                arcpath(start, end) {
                    const r = 44;

                    const t1  = start * 2*π;
                    const Δ = end * 2*π;
                    return svgarcpath([50,50],[r,r],[t1,Δ], 1.5*π);
                },
            },
            template: `
            <div :class="'r-item-badge r-item-filter r-completion-'+completion" v-b-tooltip.hover :title="value.badge.name"> 
                <a v-b-modal="'r-item-badge-details-'+value.id" 
                ><svg class="r-badge-backdrop " width='50px' height='50px' viewBox="0 0 100 100">
                    <title>{{value.badge.name}}</title>
                    <template v-if="teachermode">
                        <circle cx="50" cy="50" r="44" 
                            style="stroke: #ccc; stroke-width: 8; fill: #ddd; fill-opacity: 0.8;"/>
                        <path :d="arcpath_issued" 
                            :style="'stroke-width: 8; stroke: var(--info); fill: none;'"/>
                    </template>
                    <circle v-else-if="value.badge.issued" cx="50" cy="50" r="46" 
                        style="stroke: currentcolor; stroke-width: 4; fill: currentcolor; fill-opacity: 0.5;"/>
                    <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="value.badge.imageurl" x="12" y="12" width="76" height="76"
                        :style="(value.badge.issued||teachermode)?'':'opacity: 0.4;'" />
                </svg></a>

                <b-modal
                    :id="'r-item-badge-details-'+value.id" 
                    :title="value.badge.name" 
                    size="lg"
                    ok-only
                    centered
                    scrollable
                    >
                    <template #modal-header>
                        <div>
                            <h1><i class="fa fa-certificate"></i>
                                <a :href="(!guestmode)?(value.badge.infolink):undefined" target="_blank"
                                >{{ value.badge.name }}</a
                            ></h1>
                        </div>
                        <div class="r-course-detail-header-right" v-if="!teachermode">
                            <div class="r-completion-detail-header">
                                {{ txt.completion['completion_'+completion] }}
                                <i v-b-popover.hover :class="'fa fa-'+issued_icon+' r-completion-'+completion"
                                    :title="txt.completion['completion_'+completion]"></i>
                            </div>
                        </div>
                    </template>
                    <b-container fluid>
                        <b-row><b-col cols="3">
                            <img :src="value.badge.imageurl"/>
                        </b-col><b-col cols="9">
                            <p>{{value.badge.description}}</p>
                            <ul v-if="value.badge.issued" class="list-unstyled pt-1 mb-1 border-grey border-top">
                            <li><strong><i class="fa fa-calendar-check-o r-completion-complete-pass"></i>
                                {{txt.badge.dateissued}}:</strong> {{ value.badge.dateissued }}</li>
                            <li v-if='value.badge.dateexpired'
                            ><strong><i class="fa fa-calendar-times-o r-completion-complete"></i>
                                {{txt.badge.dateexpired}}:</strong> {{ value.badge.dateexpired }}</li>
                            <li><strong><i class="fa fa-share-alt r-completion-complete-pass"></i>
                                <a :href="value.badge.issuedlink">{{txt.badge.share_badge}}</a></strong> </li>
                            </ul>
                            <ul class="list-unstyled w-100 border-grey border-top border-bottom pt-1 pb-1 mb-1"
                             v-if="value.badge.criteria"><li v-for="crit in value.badge.criteria"
                             ><span v-html='crit'></span></li></ul>
                            <p v-if="(!guestmode)"><strong><i class="fa fa-link"></i>
                                <a :href="value.badge.infolink" target="_blank"
                                    >{{ txt.badge.badgeinfo }}</a></strong></p>
                            <p v-if="teachermode && !guestmode"
                                >{{txt.badge.badgeissuedstats}}:<br>
                                <r-completion-bar v-model="issuestats" :width="150" :height="15"></r-completion-bar>
                            </p>
                        </b-col></b-row>
                    </b-container>
                </b-modal>
            </div>    

            `,
        });
    },
};