// MovieClip this;
class Page extends MovieClip {
	private static var pages:Object = new Object();
	private static var levels_array:Array;
	private static var centerX:Number;
	private static var centerY:Number;
	private static var radius:Number;
	private static var original_mc:MovieClip;
	private static var drawing_mc:MovieClip;
	private static var process_array:Array = new Array();
	private static var loading_mc:MovieClip = _root.loading_mc;
	private static var tooltip_mc:MovieClip = _root.tooltip_mc;
	static var nDegsToRads:Number = Math.PI/180;
	private var data:Object;
	private var depth:Number;
	private var radians:Number;
	private var children_array:Array;
	// constructor
	function Page() {
		if (!original_mc) {
			original_mc = this;
		}
		this.enabled = false;
		children_array = new Array();
	}
	// static method
	static function reset():Void {
		dispatchEvent("removeMovieClip");
		drawing_mc.clear();
		initProperties();
	}
	static function initProperties():Void {
		pages = new Object();
		process_array = new Array();
	}
	static function radsToDegs(nRadians:Number):Number {
		var nDegrees:Number = nRadians/nDegsToRads;
		return nDegrees;
	}
	static function degsToRads(nDegrees:Number):Number {
		var nRadians:Number = nDegrees*nDegsToRads;
		return nRadians;
	}
	static function getPage(id_str:String):MovieClip {
		var _mc:MovieClip = pages[id_str];
		return _mc;
	}
	static function dispatchEvent(event_str:String):Void {
		arguments.shift();
		for (var i in pages) {
			var _mc:MovieClip = pages[i];
			_mc[event_str].apply(_mc, arguments);
		}
	}
	static function drawLinks():Void {
		drawing_mc.clear();
		dispatchEvent("drawLinkToParent", drawing_mc);
	}
	static function setPagesData(pages_array:Array):Void {
		levels_array = pages_array;
		var nLength:Number = pages_array.length;
		for (var i:Number = 0; i<nLength; i++) {
			var _array:Array = pages_array[i];
			var nLength2:Number = _array.length;
			for (var j:Number = 0; j<nLength2; j++) {
				// *if needed, it is able to find the last element of children
				var _mc:MovieClip = getPage(_array[j].id);
			}
		}
	}
	static function setBaseData(nCenterX:Number, nCenterY:Number, nRadius:Number, _mc:MovieClip):Void {
		centerX = nCenterX;
		centerY = nCenterY;
		radius = nRadius;
		drawing_mc = _mc;
	}
	static function createPage(name_str:String, nDepth:Number, oData:Object):MovieClip {
		var _mc:MovieClip = original_mc.duplicateMovieClip(name_str, nDepth, {data:oData});
		_mc.depth = nDepth;
		pages[oData.id] = oData.mc=_mc;
		return _mc;
	}
	static function getOriginal():MovieClip {
		return original_mc;
	}
	static function shiftUp(nLevel:Number, nID:Number, nPixels:Number, bSelf:Boolean):Void {
		var _array:Array = levels_array[nLevel-1];
		var nLength:Number = _array.length;
		for (var i:Number = nID; i<nLength; i++) {
			var _mc:MovieClip = _array[i].mc;
			_mc.shiftPosition(nPixels, bSelf);
		}
	}
	static function delayProcess(target:Object, process:Function, args_array:Array):Void {
		process_array.push({target:target, func:process, args:args_array});
		if (!original_mc.onEnterFrame) {
			original_mc.onEnterFrame = executeProcess;
		}
	}
	static function executeProcess():Void {
		if (process_array.length) {
			var oProcess:Object = process_array.shift();
			oProcess.func.apply(oProcess.target, oProcess.args);
		} else {
			delete original_mc.onEnterFrame;
			complete();
		}
	}
	static function complete():Void {
		Page.drawLinks();
		loading_mc.hide();
		enablePages();
	}
	static function enablePages():Void {
		dispatchEvent("setEnabled", true);
	}
	static function getRadius(nLevel) {
		return radius*(nLevel-1);
	}
	// instance methods
	function setScale(nScale:Number):Void {
		this._xscale = this._yscale=nScale;
	}
	function shiftPosition(nPixels:Number, bSelf:Boolean):Void {
		var nLevel:Number = data.level;
		var nPixelsToShift:Number = radians*getRadius(nLevel)+nPixels;
		setPosition(nPixelsToShift, true);
		if (bSelf && nLevel>2 && isKeyChild()) {
			getParent().centerAmongChildren();
		}
	}
	function setPosition(nRadians:Number, bPixels:Boolean):Void {
		var nRadius:Number = getRadius(data.level);
		if (bPixels) {
			nRadians = (nRadius == 0 || isNaN(nRadius)) ? 0 : nRadians/nRadius;
		}
		radians = nRadians;
		var nX:Number = nRadius*Math.cos(nRadians);
		var nY:Number = nRadius*Math.sin(nRadians);
		this._x = centerX+nX;
		this._y = centerY+nY;
	}
	function getParent():MovieClip {
		var _mc:MovieClip = getPage(data.parent);
		return _mc;
	}
	function drawLinkToParent():Void {
		var parent_mc:MovieClip = getParent();
		if (parent_mc) {
			drawing_mc.lineStyle(0, 0x999999);
			drawing_mc.moveTo(this._x, this._y);
			drawing_mc.lineTo(parent_mc._x, parent_mc._y);
		}
	}
	function setEnabled(bStatus:Boolean):Void {
		this.enabled = bStatus;
	}
	function bringToFront():Number {
		var nDepth:Number = this._parent.getNextHighestDepth();
		this.swapDepths(nDepth);
		return this.getDepth();
	}
	function sendToBack():Number {
		this.swapDepths(depth);
		return this.getDepth();
	}
	function addToParent():Void {
		var parent_mc:MovieClip = getParent();
		parent_mc.children_array.push(this);
	}
	function centerAmongChildren():Void {
		delayProcess(this, _centerAmongChildren);
	}
	function _centerAmongChildren():Void {
		var nLength:Number = children_array.length;
		if (nLength) {
			var firstChild_mc = children_array[0];
			var nRadians:Number = (nLength == 1) ? firstChild_mc.radians : (firstChild_mc.radians+children_array[nLength-1].radians)/2;
			var nRadiansToShift:Number = nRadians-radians;
			var nLevel:Number = data.level;
			var nPixelsToShift:Number = nRadiansToShift*getRadius(nLevel);
			if (nPixelsToShift>=1) {
				nLevel = firstChild_mc.data.level;
				nPixelsToShift = nRadiansToShift*getRadius(nLevel);
				shiftUp(nLevel, getIdInLevel(firstChild_mc), -nPixelsToShift, false);
			} else if (nPixelsToShift<=-1) {
				shiftUp(nLevel, getIdInLevel(this), nPixelsToShift, true);
			}
		}
	}
	function getIdInLevel(_mc:MovieClip):Number {
		var _array:Array = levels_array[_mc.data.level-1];
		var nLength:Number = _array.length;
		for (var i:Number = 0; i<nLength; i++) {
			if (_array[i].mc == _mc) {
				return i;
			}
		}
		return -1;
	}
	function isKeyChild():Boolean {
		var _array:Array = getParent().children_array;
		return (_array[0] == this || _array[_array.length-1] == this);
	}
	// mouse event handlers
	function onRollOver():Void {
		var nDepth:Number = bringToFront();
		PageInfo.showPageInfo(this.data);
		tooltip_mc.showToolTip(this.data.title, nDepth);
	}
	function onRollOut():Void {
		var nDepth:Number = sendToBack();
		PageInfo.clearPageInfo();
		tooltip_mc.hideToolTip();
	}
	function onRelease():Void {
		trace(data.path);
		this.getURL(data.path, "_blank");
	}
	// for testing
	static function showPages() {
		for (var page in pages) {
			var _mc:MovieClip = pages[page];
			trace([_mc, _mc.data.id, _mc.data.level, _mc.depth]);
		}
	}
	static function dump(obj:Object):Object {
		return mx.data.binding.ObjectDumper.toString(obj);
	}
}
