#-------------------------------------------------------------------------------
# canvas.Group
#-------------------------------------------------------------------------------
# Class for a group element on a canvas
#
var Group = {
    new: func(ghost) {
        var obj = {
            parents: [Group, Element.new(ghost)],
        };
        return obj;
    },

    # Create a child of given type with specified id.
    # type can be group, text
    createChild: func(type, id = nil) {
        var ghost = me._createChild(type, id);
        var factory = me._getFactory(type);
        if (factory == nil) {
            return ghost;
        }
        return factory(ghost);
    },

    # Create multiple children of given type
    createChildren: func(type, count) {
        var factory = me._getFactory(type);
        if (factory == nil) {
            return [];
        }
        var nodes = props._addChildren(me._node._g, [type, count, 0, 0]);
        for (var i = 0; i < count; i += 1) {
            nodes[i] = factory(me._getChild(nodes[i]));
        }
        return nodes;
    },

    # Create a path child drawing a (rounded) rectangle
    #
    # @param x        Position of left border
    # @param y        Position of top border
    # @param w        Width
    # @param h        Height
    # @param cfg    Optional settings (eg. {"border-top-radius": 5})
    rect: func(x, y, w, h, cfg = nil) {
        return me.createChild("path").rect(x, y, w, h, cfg);
    },

    # Get a vector of all child elements
    getChildren: func() {
        var children = [];
        foreach(var c; me._node.getChildren()) {
            if (me._isElementNode(c)) {
                append(children, me._wrapElement(c));
            }
        }
        return children;
    },

    # Recursively get all children of class specified by first param
    getChildrenOfType: func(type, array = nil) {
        var children = array;
        if (children == nil) {
            children = [];
        }
        var my_children = me.getChildren();
        if (!isvec(type)) {
            type = [type];
        }
        foreach(var c; my_children) {
            foreach(var t; type) {
                if (isa(c, t)) {
                    append(children, c);
                }
            }
            if (isa(c, canvas.Group)) {
                c.getChildrenOfType(type, children);
            }
        }
        return children;
    },

    # Set color to children of type Path and Text. It is possible to optionally
    # specify which types of children should be affected by passing a vector as
    # the last agrument, ie. my_group.setColor(1,1,1,[Path]);
    setColor: func() {
        var color = arg;
        var types = [Path, Text];
        var arg_c = size(color);
        if (arg_c > 1 and isvec(color[-1])) {
            types = color[-1];
            color = subvec(color, 0, arg_c - 1);
        }
        var children = me.getChildrenOfType(types);
        if (isvec(color)) {
            var first = color[0];
            if (isvec(first)) {
                color = first;
            }
        }
        foreach(var c; children) {
            c.setColor(color);
        }
    },

    # Get first child with given id (breadth-first search)
    #
    # @note Use with care as it can take several miliseconds (for me eg. ~2ms).
    #             TODO check with new C++ implementation
    getElementById: func(id) {
        var ghost = me._getElementById(id);
        if (ghost == nil) { return nil; }

        var node = props.wrapNode(ghost._node_ghost);
        var factory = me._getFactory(node.getName());
        if (factory == nil) { return ghost; }
        return factory(ghost);
    },

    # Remove all children
    removeAllChildren: func() {
        foreach(var type; keys(me._element_factories)) {
            me._node.removeChildren(type, 0);
        }
        return me;
    },

    # private:
    # element nodes have type NONE and valid element names (those in the factory
    # list)
    _isElementNode: func(el) {
        return el.getType() == "NONE" and me._element_factories[el.getName()] != nil;
    },

    # Create element from existing node
    _wrapElement: func(node) {
        var factory = me._getFactory(node.getName());
        return factory(me._getChild(node._g));
    },

    _getFactory: func(type) {
        var factory = me._element_factories[type];
        if (factory == nil) {
            logprint(DEV_ALERT, "canvas.Group.createChild(): unknown type ("~type~")");
        }
        return factory;
    }
};