const isExist = (ref) => typeof ref != 'undefined' && ref!=null;
const isArray = (ref) => typeof ref == 'object' && ref!=null;
const isObject = (ref) => typeof ref == 'object' && ref!=null;
const objectClone = (obj) => JSON.parse(JSON.stringify(obj));	// nepouzivat Object.assign({}, obj), nefunguje spravne u parseru!
const arrayFindById = (list, id) => list.find(ref => ref.id === id);

Vue.component('characters-bar-item', {
    props: ['item', 'index'],
    template: `
      <a v-bind:href="'#' + escape(item.info.info.Name)"
               v-on:click="this.app.sheetImport(item);"
		style="margin-right: 5px;">
	{{ item.info.info.Name }}
    </a>`
  });

Vue.component('info-category', {
    props: ['group_id', 'category', 'category_index'],
    template: `
    <div class="AttributeClass">
    <table>
        <tr is="info-item"
            v-for="(item, index) in category.list"
            v-bind:group_id="group_id"
            v-bind:attr="item"
            v-bind:category_index="category_index"
            v-bind:category_id="category.id"
        ></tr>
    </table>
    </div>`
  });

Vue.component('info-item', {
    props: ['group_id', 'attr', 'category_index', 'category_id'],
    data: function() {
           return  {
	      for_id: 'field[' + this.category_id + '][' + this.attr.id + ']',
	   }},
    template: `
    <tr>
        <td><label for="{{for_id}}">{{ attr.id }}</label></td>
        <td class="input"><input type="text" id="{{for_id}}" name="{{for_id}}"
		v-bind:value="attr.value"
        ></td>
    </tr>`
  });

Vue.component('attribute-category', {
    props: ['category'],
    computed: {
        tooMany: function() {
            return this.category.sum > (this.category.allowed)
        }
    },
    methods: {
        recomputeSum: function() { 
            newsum = 0
            for(var i = 0; i < this.category.list.length; i++) {
                newsum = newsum + this.category.list[i].value
            }            
            this.category.sum = newsum
            this.$emit('sumchanged')
        }        
    },
    template: `
    <div class="AttributeClass">
    <h3>{{ category.id }}
    <span 
        v-bind:class="{textred: tooMany}"> 
        {{ category.sum }}
    </span> of {{ category.allowed }}</h3>
    <table>
        <tr is="attribute-item"
            v-for="item in category.list"
            v-bind:attr="item"
            v-bind:key="item.id"
            v-on:attrchanged="recomputeSum"
        ></tr>
    </table>
    </div>
    `
})

Vue.component('attribute-item', {
    props: ['attr'],
    data: function() { return {
	hover: -1
    } },
    methods: {
        setAttrValue: function(attr, index) {
            attr.value = attr.value==index ? index-1 : index
            if (isExist(attr.value_range))
                {
                attr.value = attr.value<attr.value_range[0] ? attr.value_range[0] : attr.value>attr.value_range[1] ? attr.value_range[1] : attr.value
                }
        },
        setClass: function(value, index, hover) { return {
	    'circle'     : true,
	    'circleBlack': index<=value,
	    'circleGreen': hover>=0 && hover >value && index>value  && index<=hover,
	    'circleRed'  : hover>=0 && hover<=value && index>=hover && index<=value
        } },
        mouseOver: function(event) {
	    this.hover = event.target.attributes.index.value * 1
	    this.$forceUpdate()
        },
        mouseOut: function(event) {
            this.hover = -1
	    this.$forceUpdate()
        }
    },
    template: `
    <tr>
        <td>{{ attr.id }}</td>
        <td>{{ attr.value }}</td>
        <td>
            <div v-for="n in 5" 
                v-bind:index="n"
                v-bind:class="setClass(attr.value, n, hover)"
                v-on:click="setAttrValue(attr, n); $emit('attrchanged')"
                v-on:mouseover="mouseOver"
                v-on:mouseout="mouseOut"
            ></div>
        </td>
    </tr>`
  })

var app = new Vue({ 
    el: '#chargen',
    data: function() {
        var data = {
            props: {}, 
            form: {}, 
            form_structure: {
                info: {
                    id: "header-id",
                    list: [
                        { id: "item-id", value: "" }
                    ]
                },
                attributes: {
                    id: "header-id",
                    list: [
                        { id: "item-id", value: 1, value_range: [1, 5] }
                    ],
                    //priority: "C",
                    sum: 3,
                    allowed: 5
                },
                skills: {
                    id: "header-id",
                    list: [
                        { id: "item-id", value: 0 }
                    ],
                    sum: 0
                },
                disciplines: {
                    id: "header-id",
                    list: [
                        { id: "item-id", value: 0 }
                    ],
                    sum: 0
                }
            }
        }
	data.props = config;	// load config
	// load blank sheet to structure
	var
	blank      = objectClone(data.props.blank),
	structure  = objectClone(data.form_structure);
	this.formStructureParserFromSheet(data.form, structure, blank);
// todo:        this.computeAttrAll(data.form);
    return data;
    },

    methods: {

        error: function (source, text) {
            console.log(['Error app', source].join('.') + ': ' + text); // document.getElementById('error').innerHTML()
        },

        RecomputeAttributePriorities: function() { 
            /*
             * We compute how many attribute points are allowed based on highest assigned points
             * which will get most allowed points, other lower similarly
             * algorithm uses AttrAllowed as a source of restrictions
             * sorted AttrSums is used to recognize which Attribute category has most points assigned
             * changed array is used to track which categories were already modified to avoid double assigments 
             * and leaving other categories unchanged
             */
            AttrAllowed = [7,6,5]
            AttrSums = [
                app.form.attributes[0].sum,
                app.form.attributes[1].sum,
                app.form.attributes[2].sum
            ]            
            AttrSums.sort(function(a,b) {return a-b}).reverse()
            changed = []
            while (AttrSums.length > 0) {
                for (i=0; i < app.form.attributes.length; i++) {
                    if (app.form.attributes[i].sum == AttrSums[0] && !(changed.includes(i))) {
                        app.form.attributes[i].allowed = AttrAllowed[0]
                        AttrSums.shift()
                        AttrAllowed.shift()
                        changed.push(i)
                    }
                }
            }  
        },

        sheetImport: function(imported_sheet)
            {
            var fn = 'sheetImport';
//console.log(fn);
            var 
            sheet = isObject(imported_sheet) ? imported_sheet : {},
            blank = objectClone(this.props.blank);
            this.sheetParser(blank, sheet); // update blank-sheet by sheet
            this.formStructureParserFromSheet(this.form, this.form_structure, blank); // update form-data by sheet
//            this.computeAttrAll();
            },

        sheetExport: function()
            {
            var fn = 'sheetExport';
//console.log(fn);
            var 
            sheet = objectClone(this.props.blank);
            sheet = this.formStructureParserToSheet(this.form, sheet);
            console.log(JSON.stringify(sheet))
	    },

        sheetParser: function (blank, sheet)
            {
            var fn, i;
            fn = 'sheetParser';
//console.log(fn);
            if (!isObject(blank) || !isObject(sheet))
                {
                return;
                }
            for(i in blank)
                {
                if (!isObject(sheet) || !(i in sheet))
                    {
                    continue;
                    }
                if (isObject(blank[i]))	// object, repeat
                    {
                    if (!isObject(sheet[i]))
                        {
                        this.error(fn, 'Value in "parsed object" is not type Object.');
                        }
                    this.sheetParser(blank[i], sheet[i]);
                    }
                else
                    {
                    blank[i] = sheet[i];	// copy value
                    }
                }
            },

	// parse sheet to form-structure
        formStructureParserFromSheet: function(form, structure, sheet)
            {
//console.log('formStructureParserFromSheet');
            var group, cat, attr, jj, kk, temp, key, keys = {'sum':1, 'priority':1, 'allowed':1};
            for (group in structure) // example: group = 'attributes'
                {
                if (!isObject(structure[group]) || !isObject(sheet[group]))
                    {
                    return;
                    }
                if (!isArray(form[group]))
                    {
                    form[group] = [];
                    }
                jj = 0;
                for (cat in sheet[group]) // example: category = 'physical'
                    {
                    if (!isObject(sheet[group][cat]))
                        {
                        return;
                        }
                    if (!isObject(form[group][jj]))
                        {
                        form[group][jj] = objectClone(structure[group]);
                        }
                    form[group][jj].id = cat;							// copy group-id
                    if (isExist(structure[group].list) && (!isExist(form[group][jj].list) || !isArray(form[group][jj].list)))	// create plistriority, if not exist
                        {
                        form[group][jj].list = objectClone(structure[group].list);
                        }
                    for (key in keys)	// create [sum, priority, allowed] if not exist
			{
                        if (isExist(structure[group][key]) && !isExist(form[group][jj][key]))		
                            {
                            form[group][jj][key] = structure[group][key];
                            }
			}
                    temp = objectClone(structure[group].list[0]);
                    kk = 0;
                    for (attr in sheet[group][cat])
                        {
                        if (!isExist(form[group][jj].list[kk]))
                            {
                            form[group][jj].list[kk] = objectClone(temp);
                            }
                         form[group][jj].list[kk].id    = attr;
                         form[group][jj].list[kk].value = sheet[group][cat][attr];
                         kk++;
                        }
                    jj++;
                    }
                }
//console.log(JSON.stringify(out))
//console.log(JSON.stringify(this.formStructureParserToSheet(out, sheet)))
        return form;
	},

        formStructureParserToSheet: function(form, sheet)	// parse sheet to form-structure
            {
//console.log('formStructureParserToSheet');
            // example sheet: sheet = { group: { cat: { attr: value } } }
            var group, cat, cat_data, attr, attr_data;
            for (group in sheet) // example: group = 'attributes'
                {
                if (!isObject(sheet[group]) || !isArray(form[group]))
                    {
                    continue;
                    }
                for (cat in sheet[group]) // example: category = 'physical'
                    {
                    if (!isObject(sheet[group][cat]))
                        {
                        continue;
                        }
                    cat_data = arrayFindById(form[group], cat);
                    if (!isExist(cat_data))
                        {
                        continue;
                        }
                    if (!isArray(cat_data.list))
                        {
                        continue;
                        }
                    for (attr in sheet[group][cat])
                        {
                        attr_data = arrayFindById(cat_data.list, attr);
                        if (!isExist(attr_data))
                            {
                            continue;
                            }
                        if (!isExist(attr_data.value))
                            {
                            continue;
                            }
			sheet[group][cat][attr] = attr_data.value
                        }
                    }
                }
            return sheet;
            }
    }
});