<script>

    export default {
        name: 'tree-view',

        inheritAttrs: false,

        props: {
            inputType: String,

            nameField: String,

            idField: String,

            captionField: String,

            childrenField: String,

            valueField: String,

            items: {
                type: [Array, String, Object],
                required: false,
                default: null
            },

            value: {
                type: Array,
                required: false,
                default: null
            },

            behavior: {
                type: String,
                required: false,
                default: 'reactive'
            },

            savedValues: {
                type: Array,
                required: false,
                default: null
            }
        },

        created () {
            if (! this.savedValues)
                return;

            var self = this;

            var found = this.savedValues.filter(function(value) {
                if (value == self.items[self.valueField])
                    return true;
            });

            if(found.length) {
                this.value.push(this.items);
            }
        },

        computed: {
            caption () {
                return this.items[this.captionField]
            },

            allChildren () {
                let leafs = [];
                let searchTree = items => {
                    if(!! items[this.childrenField] && this.getLength(items[this.childrenField]) > 0) {
                        if(typeof items[this.childrenField] == 'object') {
                            for(let key in items[this.childrenField]) {
                                searchTree(items[this.childrenField][key])
                            }
                        } else {
                            items[this.childrenField].forEach(child => searchTree(child))
                        }
                    } else {
                        leafs.push(items)
                    }
                }

                searchTree(this.items)
                
                return leafs;
            },

            hasChildren () {
                return !! this.items[this.childrenField] && this.getLength(this.items[this.childrenField]) > 0;
            },

            hasSelection () {
                return !! this.value && this.value.length > 0;
            },

            isAllChildrenSelected () {
                return this.hasChildren && this.hasSelection && this.allChildren.every(leaf => this.value.some(sel => sel[this.idField] === leaf[this.idField]))
            },

            isSomeChildrenSelected () {
                return this.hasChildren && this.hasSelection && this.allChildren.some(leaf => this.value.some(sel => sel[this.idField] === leaf[this.idField]))
            }
        },

        methods: {
            getLength (items) {
                if(typeof items == 'object') {
                    let length = 0;

                    for(let item in items) {
                        length++;
                    }

                    return length;
                }

                return items.length;
            },

            generateRoot () {
                if(this.inputType == 'checkbox') {
                    if(this.behavior == 'reactive') {
                        return this.$createElement('tree-checkbox', {
                            props: {
                                id: this.items[this.idField],
                                label: this.caption,
                                nameField: this.nameField,
                                modelValue: this.items[this.valueField],
                                inputValue: this.hasChildren ? this.isSomeChildrenSelected : this.value,
                                value: this.hasChildren ? this.isAllChildrenSelected : this.items
                            },
                            on: {
                                change: selection => {
                                    if(this.hasChildren) {
                                        if(this.isAllChildrenSelected) {
                                            this.allChildren.forEach(leaf => {
                                                let index = this.value.indexOf(leaf)
                                                this.value.splice(index, 1)
                                            })
                                        } else {
                                            this.allChildren.forEach(leaf => {
                                                let exists = false;
                                                this.value.forEach(item => {
                                                    if(item['key'] == leaf['key']) {
                                                        exists = true;
                                                    }
                                                })

                                                if(!exists) {
                                                    this.value.push(leaf);
                                                }
                                            })
                                        }

                                        this.$emit('input', this.value)
                                    } else {
                                        this.$emit('input', selection);
                                    }
                                }
                            }
                        })
                    } else {
                        return this.$createElement('tree-checkbox', {
                            props: {
                                id: this.items[this.idField],
                                label: this.caption,
                                nameField: this.nameField,
                                modelValue: this.items[this.valueField],
                                inputValue: this.value,
                                value: this.items
                            }
                        })
                    }
                } else if(this.inputType == 'radio') {
                    return this.$createElement('tree-radio', {
                        props: {
                            id: this.items[this.idField],
                            label: this.caption,
                            nameField: this.nameField,
                            modelValue: this.items[this.valueField],
                            value: this.savedValues
                        }
                    })
                }
            },

            generateChild (child) {
                return this.$createElement('tree-item', {
                    on: {
                        input: selection => {
                            this.$emit('input', selection)
                        }
                    },
                    props: {
                        items: child,
                        value: this.value,
                        savedValues: this.savedValues,
                        nameField: this.nameField,
                        inputType: this.inputType,
                        captionField: this.captionField,
                        childrenField: this.childrenField,
                        valueField: this.valueField,
                        idField: this.idField,
                        behavior: this.behavior
                    }
                })
            },

            generateChildren () {
                let childElements = [];
                if(this.items[this.childrenField]) {
                    if(typeof this.items[this.childrenField] == 'object') {
                        for(let key in this.items[this.childrenField]) {
                            childElements.push(this.generateChild(this.items[this.childrenField][key]));
                        }
                    } else {
                        this.items[this.childrenField].forEach(child => {
                            childElements.push(this.generateChild(child));
                        })
                    }
                }

                return childElements;
            },

            generateIcon () {
                return this.$createElement('i', {
                    class: ['icon arrow-down-icon'],
                    on: {
                        click: selection => {
                            this.$el.classList.toggle("active")
                        }
                    }
                })
            },

            generateFolderIcon () {
                return this.$createElement('i', {
                    class: ['icon', 'folder-icon']
                })
            }
        },

        render (createElement) {
            return createElement('div', {
                    class: [
                        'tree-item',
                        'active',
                        this.hasChildren ? 'has-children' : ''
                    ]
                }, [
                    this.generateIcon(), this.generateFolderIcon(), this.generateRoot(), ... this.generateChildren()
                ]
            )
        }
    }
</script>