function SceneElement() {
    this.children = [];
}

SceneElement.prototype.set = function(to) {
    to.transformOrigin = this.transformOrigin;
	to.immediateRender = false;
    return TweenMax.set(this.div, to);
}

SceneElement.prototype.to = function(duration, to) {
    to.transformOrigin = this.transformOrigin;
    return TweenMax.to(this.div, duration, to);
}
 
SceneElement.prototype.from = function(duration, from) {
    from.transformOrigin = this.transformOrigin;
    return TweenMax.from(this.div, duration, from);
}

SceneElement.prototype.fromTo = function(duration, from, to) {
    to.transformOrigin = this.transformOrigin;
    return TweenMax.fromTo(this.div, duration, from, to);
}

function LoadCounter(initval, doneHandler) {
	this.count = initval;
	this.doneHandler = doneHandler;
	this.success = true;
}

LoadCounter.prototype.add = function() {
	this.count++;
}

LoadCounter.prototype.done = function() {
	this.count--;
	if (this.count == 0)
		this.doneHandler(this.success);
}

LoadCounter.prototype.fail = function() {
	this.success = false;
	this.done();
}

function _getLeaf(root, path) {
    for (var element of path) {
        if (root.children.indexOf(element) < 0)
            root.children.push(element);
        var sub = root[element];
        if (!sub)
            sub = root[element] = new SceneElement();
        root = sub;        
    }
    return root;
}

function _populateTree(domParent, tree, id, sceneName, counter) {
    tree.id = id;
    tree.div = document.createElement("div");
    tree.div.id = id;
    tree.div.style.position = "absolute";
    domParent.appendChild(tree.div);

    if (tree.layer) {
        var image = tree.image = document.createElement("img");
		counter.add();
		image.onload = function() { counter.done(); };
		image.onerror = function() { counter.fail(); };
        image.src = "gfx/" + sceneName + "/" + tree.layer + ".png";
        image.width = tree.size.x;
        image.height = tree.size.y;
        image.style.position = "absolute";
        tree.div.appendChild(image);
    }
    if (tree.children && tree.children.length) {
        if (!tree.topLeft) {
            tree.topLeft = new Victor(9999999, 9999999);
            tree.botRight = new Victor(0, 0);
        }
        for (var childName of tree.children) {
            var child = tree[childName];
            _populateTree(tree.div, child, id + "." + childName, sceneName, counter);
            tree.topLeft.x = Math.min(tree.topLeft.x, child.topLeft.x);
            tree.topLeft.y = Math.min(tree.topLeft.y, child.topLeft.y);
            tree.botRight.x = Math.max(tree.botRight.x, child.botRight.x);
            tree.botRight.y = Math.max(tree.botRight.y, child.botRight.y);
        }
        tree.size = tree.botRight.clone().subtract(tree.topLeft);
        if (!tree.center)
            tree.center = tree.topLeft.clone().add(tree.botRight).divideScalar(2);
    }
}

function _makeCoordsRelative(tree, parentOrigin) {
    if (tree.children) {
        for (var child of tree.children) {
            _makeCoordsRelative(tree[child], tree.topLeft);
        }
    }

    tree.center.subtract(tree.topLeft);
    tree.topLeft.subtract(parentOrigin);
    tree.botRight.subtract(parentOrigin);

    if(tree.div) {
        tree.div.style.left = tree.topLeft.x + "px";
        tree.div.style.top = tree.topLeft.y + "px";
        tree.div.style.width = tree.size.x + "px";
        tree.div.style.height = tree.size.y + "px";
        if(tree.origTopLeft && tree.image) {
            tree.origTopLeft.subtract(parentOrigin);
            var offset = tree.origTopLeft.clone().subtract(tree.topLeft);
            tree.image.style.left = offset.x + "px";
            tree.image.style.top = offset.y + "px";
        }
    }
    tree.transformOrigin = tree.center.x + "px " + tree.center.y + "px";
}

function loadScenes(scenes, sceneNames, onDone) {
	/* Start count at 1 so we don't decrease to 0 prematurely */
	var count = new LoadCounter(1 + sceneNames.length, onDone);
	for (var i in sceneNames) {
		(function(zIndex, sceneName) {
			$.getJSON("gfx/" + sceneName + "/Spine.json", function(data) {
				var root = new SceneElement();
				scenes[sceneName] = root;
				
				/* Transform the flat JSON into hierarchical layer objects */
				var stageHeight = 1080;
				if (data.skins.default.background)
					stageHeight = data.skins.default.background.background.height;
				$.each(data.slots, function(layerId, layer) {
					var layerName = data.slots[layerId].name;
					layer = data.skins.default[layerName];
					layer = layer[layerName];
					var path = layerName.split(".");
					layer.y = stageHeight - layer.y;

					var setCenter = path[path.length - 1] == "center";
					if (setCenter)
						path.pop();

					var leaf = _getLeaf(root, path);
					if (!setCenter) {
						var size = new Victor(layer.width, layer.height);
						leaf.topLeft = new Victor(layer.x, layer.y).subtract(size.clone().divideScalar(2));
						leaf.botRight = new Victor(layer.width, layer.height).add(leaf.topLeft);
						leaf.size = leaf.botRight.clone().subtract(leaf.topLeft);
						leaf.center = leaf.topLeft.clone().add(leaf.botRight).divideScalar(2);
						leaf.layer = layerName;
						leaf.origTopLeft = leaf.topLeft.clone();
						//delete leaf.children;
					} else {
						leaf.center = new Victor(layer.x, layer.y);
					}                
				});

				/* Recursively traverse the hierarchy, calculate bounding boxes and generate DOM elements */
				_populateTree(document.getElementById("stage"), root, sceneName, sceneName, count);
				root.div.style.zIndex = zIndex
				root.div.style.opacity = 0;
				
				/* Now that we have the bounding boxes, make all coordinates relative to the parent */
				_makeCoordsRelative(root, new Victor(0, 0));
				
				count.done();
			}).fail(function() {
				count.fail();
			});
		})(i, sceneNames[i]);
	}
	/* Now adjust count to eventually (or right now?) reach 0 */
	count.done();
}