function Nester(panel, canvas) {
    this.panel = new Panel(html_node(panel))
    this.canvas = canvas
    this.board = new NBoard(this, "groups", html_node(panel), {
        id: groups
    })

    this.group = {}             /* Dictionary holding Wizards */
    this.cast("panel_change")
}

Nester.prototype.iterate_over_wizards = function (yielding, initial) {
    initial = initial || []
    Object.keys(this.group).forEach((gr, i) => {
        if (this.group[gr])
        Object.keys(this.group[gr]).forEach( (wz, j) => {
            if (this.board.group[gr].entity[wz])
        	if (this.board.group[gr].entity[wz].is("show"))
            	initial = yielding(this.group[gr][wz], initial)
        })
    })
    return initial
}

Nester.prototype.picture_all = function () {
    var x_min, y_min
    var boundary = this.iterate_over_wizards( (wizard, boundary) => {
        if (wizard.por_x < boundary[0])
            boundary[0] = wizard.por_x
        if (wizard.por_y < boundary[1])
            boundary[1] = wizard.por_y

        return boundary
    }, [1000000, 10000000] )

    var program = "data:,"
    program += "%\n\
;DIM 1500 500\n\
;PINZE X325 Y565\n\
MOV X-999.99 Y350\n\
MOV XPIN Y350\n"
    program += this.iterate_over_wizards( (wizard, prg) => {
        prg += wizard.subroutine(boundary[0], boundary[1])
        prg +="\n"
        return prg
    })
    program += "%\n"
    window.open(encodeURI(program))
}

Nester.prototype.canvas_refresh = function () {
	this.canvas.reset ()
	var result = this.iterate_over_wizards( (wizard, views) => {
        return views.concat(wizard.get_canvas_views())
    } )
	
	for (var i=0; i<result.length; i++)
		this.canvas.add( result[i][0], result[i][1])

	this.canvas.redraw()
}

Nester.prototype.focus = function ()  {
     var result = this.iterate_over_wizards( (wizard, result) => {
        if (!wizard.boundary)
            return result
        var cur = wizard.boundary
        if (!result.length)
            return cur
        if (cur[0] < result[0])
            result[0] = cur[0]
        if (cur[2] < result[2])
            result[2] = cur[2]
        if (cur[1] > result[1])
            result[1] = cur[1]
        if (cur[3] > result[3])
            result[3] = cur[3]
        return result
     } ) 
     return result
}

Nester.prototype.cast = function (mssg, data, sender) {
    switch (mssg) {
        case "focus_canvas":
            this.canvas.focus.apply(this.canvas, this.focus())
            break
        case "view_extent":
            this.cast("focus_canvas")
            this.cast("canvas_change")
            break
        case "picture_all":
            this.picture_all()
            break
        case "canvas_update": /* Number of elements in canvas have changed */
            this.canvas_refresh ()
            break
        case "canvas_change": /* The elements may have changed internally */
            this.canvas.redraw ()
            break
        case "panel_change":
            this.panel.refresh ()
            break
        case "toggle_view_profile":
            this.canvas_refresh()
            break
        case "group_added":
            this.group[data.underscore()] = {}
            this.cast("panel_change")
            break
        case "profile_added":
            this.group[data.group][data.profile] = new Profiler(data.group + "_" + data.profile, 
            	"specimen_tree", 
            	this, 
            	data.data) 
            this.cast("panel_change")
            this.canvas.focus.apply(this.canvas, this.group[data.group][data.profile].boundary)
            this.canvas_refresh()
            break
         case "work_profile":
         	   this.cast("panel_change")
         	   this.group[data.group][data.profile].panel.refresh()
         	   this.cast("canvas_change")
         	   break
        case "delete_profile":
            delete this.group[data.group][data.profile]
            break

    }
}