/**
 * Meta data collections utility class for Sparc
 * 
 * @author Michael Fallise
 * @version 1.0
 * @category MyEic
 * @subcategory Libraries
 */
class WindozMetaData {

    collections = {};

    /**
     * Adds a collection to the metadata set
     * @param {string} ref 
     * @param {array} collection 
     */
    add(ref, collection) { if(!this.collections.hasOwnProperty(ref)) this.collections[ref] = collection; }

    /**
     * Returns a collection
     * @param {string} ref 
     * @returns {Array<object>}
     */
    getCollection(ref) { return this.collections.hasOwnProperty(ref) ? this.collections[ref].content: []; }

    /**
     * Return a collection item object
     * @param {*} ref 
     * @param {*} id 
     * @returns {object|null}
     */
    getItem(collection, id) {
        // if collection is a string ref, fetch matching collection
        if(!Array.isArray(collection)) collection = this.getCollection(collection);
        // parse recursively to find matching item id
        return collection ? this.getItemRecurse(collection, id) : null;
    }

    /**
     * 
     * @param {*} tree 
     * @param {*} id 
     * @returns {object|null}
     */
    getItemRecurse(tree, id) {
        
        if (Array.isArray(tree)) { 
            for(let i = 0; i < tree.length; i++) {
                let item = this.getItemRecurse(tree[i], id);
                if(item) { return item; }
            }
        } else if (typeof tree === 'object') { 
            if (tree.id && tree.id == id) return tree;
        }
        if (tree.children !== undefined && tree.children.length > 0) { 
            return this.getItemRecurse(tree.children, id);
        } else {
            return null; 
        }
    }

    /**
     * Returns a collection item label
     * @param {string} ref 
     * @param {string} id 
     * @returns {string}
     */
    toString(ref, id) {
        let item = this.getItem(ref, id);
        return item ? item.label: `(${ref}.${id})`;
    }

    /**
     * Converts a collection into a list of OPTION tags
     * @param {string} ref 
     * @returns {Array<Element>}
     */
    toOptions(collection, selectedIds=[], placeHolder) {
        if(!Array.isArray(collection)) collection = this.getCollection(collection);
        if(!Array.isArray(selectedIds)) selectedIds = [selectedIds];
        let options = [];
        if(placeHolder) options.push(ui.create(`<option value=""><option>`))
        
        if(collection)
            for (const item of collection) {
                options.push(ui.create(`<option value="${item.id}" ${(selectedIds.indexOf(item.id)>-1) ? 'selected':''}>${item.label}</option>`));
            }

        return options;
    }

    /**
     * 
     * @param {*} collection 
     * @param {*} selectedId 
     * @param {*} placeHolder 
     * @param {*} parentId 
     * @returns {Array<Element>}
     */
    toOptionsRecurse(collection, selectedId, placeHolder, parentId) {
        if(!Array.isArray(collection)) collection = this.getCollection(collection);
        let options = [];
        let children = [];
        if(placeHolder) options.push(`<option value=""><option>`)
        
        if(collection)
            for (const item of collection) {
                options.push(`<option ${item.children ? `data-ref="${item.id}"`: ''} value="${item.id}" ${selectedId ? (selectedId == item.id ? 'selected':'') :''}>${item.label}</option>`);
                if(item.children) children.push({parent: item.id, children: item.children})
            }

        let html = parentId ? `<optgroup data-parent="${parentId}">${options.join('')}</optgroup>`: `${options.join('')}`;
        for(let item of children) {
            html += `${this.toOptionsRecurse(item.children, selectedId, false, item.parent)}`;
        }

        return html;
    }
}

app.registerClass('WindozMetaData',WindozMetaData);
app.meta = new WindozMetaData();