Kanshin.graph = {
	createField: function(elm, options) {
		return new Kanshin.graph.BasicField(elm, options)

	},
	
	options: function(options, moreOptions) {
		if (!options) options = {}
		if (moreOptions) Object.extend(options, moreOptions)
		return options;
	},
	
	createCanvas: function(parentElm) {
		var canvas = document.createElement('canvas')
		parentElm.appendChild(canvas)
		if (window.G_vmlCanvasManager) canvas = G_vmlCanvasManager.initElement(canvas)
		return $(canvas)
	}
}

Kanshin.graph.IField = Class.create()
Kanshin.graph.IField.prototype = {
	initialize: function(elm, options) {
		this._nodes = new Array()
		this._connections = new Array()
		this._origin = new Kanshin.graph.Point(0, 0)
		
		var opts = Kanshin.graph.options(options)
		
		this.initializeField(elm, options)
	},
	
	initializeField: function(elm, options) {
	},
	
	getOrigin: function() {
		return this._origin.clone()
	},
	
	setOrigin: function(pos) {
		this._origin = pos.clone()
	},
	
	getDimensions: function() {
		return { width: 0, height: 0 }
	},
	
	createNode: function(elm, options) {
	},
	
	nodes: function() {
		return this._nodes
	},
	
	resized: function() {
	},
	
	connectNodes: function(node1, node2, options) {
	},
	
	connections: function() {
		return this._connections
	}
}

Kanshin.graph.INode = Class.create()
Kanshin.graph.INode.prototype = {
	initialize: function(field, elm, options) {
		this._field = field
		this._contentElement = $(elm)
		this._connections = new Array()
		
		var opts = Kanshin.graph.options(options)
		
		this.initializeNode(elm, opts)
		
		var pos = new Kanshin.graph.Point(0, 0)
		if (opts.x) pos.x = opts.x
		if (opts.y) pos.y = opts.y
		if (opts.position) pos = opts.position
		
		this._pos = pos.clone()
	},
	
	initializeNode: function(elm, options) {
	},
	
	content: function() {
		return this._contentElement
	},
	
	position: function() {
		return this._pos.clone()
	},
	
	setPosition: function(pos) {
		this._pos = pos.clone()
		this.nodeChanded()
	},
	
	connections: function() {
		return this._connections
	},
	
	nodes: function() {
		return this._connections.collect(function(conn) { return conn.otherNode(this) }.bind(this) )
	},
	
	nodeChanded: function() {
	}
}

Kanshin.graph.IConnection = Class.create()
Kanshin.graph.IConnection.prototype = {
	initialize: function(field, node1, node2, options) {
		this._field = field
		this._node1 = node1
		this._node2 = node2
		
		var opts = Kanshin.graph.options(options)
		
		this.initializeConnection(node1, node2, opts)
		if (opts.label) this.setLabel(opts.label)
	},
	
	initializeConnection: function(elm, options) {
	},
	
	node1: function() {
		return this._node1
	},
	
	node2: function() {
		return this._node2
	},
	
	nodes: function() {
		return [this._node1, this._node2]
	},
	
	otherNode: function(node) {
		return (node == this._node1 ? this._node2 : this._node1)
	},
	
	label: function() {
		return this._label
	},
	
	setLabel: function(label) {
		this._label = label
	},
	
	connectionChanded: function() {
	}
}

Kanshin.graph.Point = Class.create()
Kanshin.graph.Point.prototype = {
	initialize: function(x, y) {
		this.x = x
		this.y = y
	},
	
	add: function(pt) {
		var pt2 = this.clone()
		pt2.x += pt.x
		pt2.y += pt.y
		return pt2
	},
	
	scale: function(v) {
		var pt = this.clone()
		pt.x *= v
		pt.y *= v
		return pt
	},
	
	centerPoint: function(pt) {
		var pt2 = this.add(pt)
		return pt2.scale(0.5)
	},
	
	clone: function() {
		return new Kanshin.graph.Point(this.x, this.y)
	}
}

// ======================== 実装

Kanshin.graph.BasicField = Class.create()
Kanshin.graph.BasicField.prototype = Object.extend(new Kanshin.graph.IField(), {
	
	initializeField: function(elm, options) {
		this._frameElement = $(elm)
		
		this._connectionFieldElement = this._frameElement.down('canvas')
		
		this._fieldElement = this._frameElement.down('div')
	},
	
	getDimensions: function() {
		return this._fieldElement.getDimensions()
	},
	
	createNode: function(elm, options) {
		var node = new Kanshin.graph.BasicNode(this, elm, options)
		
		this._nodes.push(node)
		return node
	},
	
	connectNodes: function(node1, node2, options) {
		var conn = new Kanshin.graph.BasicConnection(this, node1, node2, options)
		
		this._connections.push(conn)
		return conn
	},
	
	setOrigin: function(pos) {
		this._origin = pos.clone()
		
		$('domLayer').setStyle({
			left: this._origin.x + 'px',
			top: this._origin.y + 'px'
		})
		
		this.redrawConnections()
	},
	
	resized: function() {
		var size = this._frameElement.getDimensions()
		this._connectionFieldElement.width = size.width
		this._connectionFieldElement.height = size.height
		this.redrawConnections()
		
		var style = {
			width: size.width + 'px', 
			height: size.height + 'px'
		}
		
		this._fieldElement.setStyle(style)
		
		this._nodes.each(function(node) { node.nodeChanded() })
		this._connections.each(function(conn) { conn.connectionChanded() })
	},
	
	redrawConnections: function() {
		var canvas = this._connectionFieldElement
		// canvas is a reference to a <canvas> element
		var context = canvas.getContext('2d');
		
		context.save()
		
		context.lineWidth = "1";
		context.strokeStyle = "rgb(160,160, 160)";
		context.clearRect(0, 0, canvas.width, canvas.height)
		context.translate(canvas.width / 2  + this._origin.x, canvas.height / 2 + this._origin.y)
		
		this._connections.each(function(conn) {
			var pos = conn.node1().position()
			context.moveTo(pos.x, pos.y)
			
			pos = conn.node2().position()
			context.lineTo(pos.x, pos.y)
		})
		
		context.stroke()
		
		context.restore()
	},
	
	placeElement: function(elm, position) {
		var size = elm.getDimensions()
		var fieldSize = this.getDimensions()
		elm.setStyle({
			left: ((fieldSize.width - size.width) / 2 + position.x + this._origin.x) + 'px', 
			top: ((fieldSize.height - size.height) / 2 + position.y + this._origin.y) + 'px'
		})
	},
	
	placeImage: function(url, position) {
		var img = document.createElement('img');
		img.src = url;
		
		var elm = $(document.createElement('div'));
		elm.appendChild(img);
		
		elm.setStyle({ position: 'absolute' });
		
		this._fieldElement.appendChild(elm);
		elm.show();
		
		
		setTimeout(function() { this.placeElement(elm, position) }.bind(this), 100);
	},
	
	placeBackground: function(url, position) {
		var img = document.createElement('img');
		img.src = url;
		
		var elm = $(document.createElement('div'));
		elm.appendChild(img);
		
		var fieldSize = this.getDimensions();
		elm.setStyle({
			position: 'absolute',
			zIndex: -1,
			left: (fieldSize.width / 2 + position.x + this._origin.x) + 'px', 
			top: (fieldSize.height / 2 + position.y + this._origin.y) + 'px'
		});
		
		this._fieldElement.appendChild(elm);
	}
})

Kanshin.graph.BasicNode = Class.create()
Kanshin.graph.BasicNode.prototype = Object.extend(new Kanshin.graph.INode(), {
	
	initializeNode: function(elm, options) {
		elm.show()
	},
	
	nodeChanded: function() {
		this._field.placeElement(this._contentElement, this._pos)
	}
})

Kanshin.graph.BasicConnection = Class.create()
Kanshin.graph.BasicConnection.prototype = Object.extend(new Kanshin.graph.IConnection(), {
	
	initializeConnection: function(node1, node2, options) {
	},
	
	setLabel: function(elm) {
		if (this._labelElement) this._labelElement.remove()
		this._labelElement = elm
		elm.show()
		// this.connectionChanded()
	},
	
	connectionChanded: function() {
		if (this._labelElement) {
			var pos = this._node1.position().centerPoint(this._node2.position())
//			pos.y -= 10
			this._field.placeElement(this._labelElement, pos)
		}
	}
})

