// Пересчитывает положения атомов на поле
CMolecule.prototype.calcPositions=function()
{
	this.board.clear();
	this.calculationError=false;
	this.calcTopDown( this.sortChildrenByMainLineFlag);
	var success = this.calculateLocations( this.root);
	if( visualDebugInfo)
	{
		if( success)
			trace("// ----- Positions calculated OK -----");
		else
			trace("// ----- Positions calculated FAILED -----");
	}
}
// Сортирует потомков по признаку главной линии
CMolecule.prototype.sortChildrenByMainLineFlag=function(atom)
{
	var tempArray = atom.children;
	for(var i=0; i<tempArray.length; i++)
	{
		for(var j=i+1; j<tempArray.length; j++)
		{
			var child1 = tempArray[i];
			var child2 = tempArray[j];
			if( !child1.isOnMainLine && child2.isOnMainLine)
			{
				tempArray[j] = child1;
				tempArray[i] = child2;
			}
		}
	}
}
// Функция добавляет альтернативные элементы в массив
CMolecule.prototype.growDirections=function(aArray, str)
{
	for( var i=0; i<aArray.length; i++)
	{
		if( aArray[i] == str)	return;
	}
	aArray.push( str);
}
CMolecule.prototype.growDirectionsForStr=function(str, aArray)
{
	if( str.indexOf("left")!=-1){this.growDirections( aArray, "left");		this.growDirections( aArray, "left-up");		this.growDirections( aArray, "left-down");}
	else	if( str.indexOf("right")!=-1){this.growDirections( aArray, "right");		this.growDirections( aArray, "right-up");		this.growDirections( aArray, "right-down");}

	if( str.indexOf("down")!=-1){this.growDirections( aArray, "down");		this.growDirections( aArray, "right-down");		this.growDirections( aArray, "left-down");}
	else	if( str.indexOf("up")!=-1){this.growDirections( aArray, "up");		this.growDirections( aArray, "right-up");		this.growDirections( aArray, "left-up");}
}
CMolecule.prototype.growDirectionsForAll=function(aArray)
{
//trace("1. aArray.length=" + aArray.length);
	this.growDirections( aArray, "left");	this.growDirections( aArray, "left-up");	this.growDirections( aArray, "left-down");
	this.growDirections( aArray, "right");	this.growDirections( aArray, "right-up");	this.growDirections( aArray, "right-down");
	this.growDirections( aArray, "up");		this.growDirections( aArray, "left-up");	this.growDirections( aArray, "right-up");
	this.growDirections( aArray, "down");	this.growDirections( aArray, "left-down");	this.growDirections( aArray, "right-down");
//trace("2. aArray.length=" + aArray.length);
}
// Основная функция пересчета положения атомов на поле
CMolecule.prototype.calculateLocations=function(atom)
{
	if( atom == null)	return;
	if( this.calculationError == true)	return;

	if( visualDebugInfo)
	{
		if( atom.parent!=null)
		{
			trace( "calculateLocations for atom "+atom.type+"["+atom.rootDistance+"] parent is ["+atom.parent.type+"]");
			trace( "parent parameters "+atom.parent.type+"["+atom.parent.x+","+atom.parent.y+"]");
		}
		else
			trace( "calculateLocations for root atom "+atom.type);
	}

	// Если это самый первый атом
	if( atom.parent == null)
	{
		atom.x = 0;
		atom.y = 0;
		atom.setFirstChildDirection("right");
		this.placeAtomRelative(atom, 0, 0);

		if( atom.children.length!=0)
		{
			var childrenCount=0;
			for( ;childrenCount<atom.children.length; childrenCount++)
			{
				var child = atom.children[childrenCount];
				this.calculateLocations(child);
			}
		}
		return;
	}

//trace("atom.parent.isFlipped="+atom.parent.isFlipped + " atom type = " + atom.type);

	var add = this.getChildrenDirections( atom);
	if( add.length == 0)
	{
		trace("mc2d calculateLocations error: add.length==0");
		if( atom.parent!=null)
		{
			trace(atom.parent.firstChildDirection);
		}
	}
	var addLength = add.length;
	for( var t=0; t<addLength; t++)
	{
		var str = add[t];
		this.growDirectionsForStr(str, add);
	}
	this.growDirectionsForAll(add);

	var i=0;
	for(; i<add.length; i++)
	{
		var	adx=0;
		var	ady=0;
		if( add[i].indexOf("right")!=-1){	adx=2;}
		else	if( add[i].indexOf("left")!=-1){	adx=-2;}
		if( add[i].indexOf("up")!=-1){	ady=-2;}
		else	if( add[i].indexOf("down")!=-1){	ady=2;}


//trace("add[i]="+add[i]+":ady[i]="+ady);
//trace("adx[i]="+adx+":ady[i]="+ady);
//trace("atom.parent.x="+atom.parent.x+":atom.parent.y="+atom.parent.y);

		//  Размещаем атом
		if( visualDebugInfo)
		{
			trace("adx[i]="+adx+":ady[i]="+ady);
			trace("atom.parent.x="+atom.parent.x+":atom.parent.y="+atom.parent.y);
		}

		atom.setFirstChildDirection( add[i]);
		if( this.placeAtomRelative(atom, atom.parent.x + adx, atom.parent.y + ady))
		{
			if( visualDebugInfo)
				trace("Atom placing SUCCEEDED");
			//atom.setFirstChildDirection( add[i]);
			//  Если разместили атом, то попытаемся разместить всех дочерних элементов
			var childrenCount=0;
			if( visualDebugInfo)
			{
				trace("["+atom.type+"] atom.firstChildDirection="+atom.firstChildDirection);
			}
			for( ;childrenCount<atom.children.length; childrenCount++)
			{
				var child = atom.children[childrenCount];
				var res = this.calculateLocations(child);
				// если не смогли добавить одного из сыновей
				if( res == false)
				{
					break;
				}
			}
			if(childrenCount == atom.children.length)
			{
				// Если разместили всех
				break;
			}
			else
			{
				this.removeAtomFromBoard( atom);
			}
		}
		else
		{
			if( visualDebugInfo)
				trace("Atom placing FAILED");
		}
	}
	if( i == add.length)
	{
		if( visualDebugInfo)
			trace( "HOPS: can`t place atom"+atom.type+"["+atom.rootDistance+"]");
		return false;
	}
	if( visualDebugInfo)
		trace("HOPS: !"+atom.type+"["+atom.rootDistance+"]");
	return true;
}

CMolecule.prototype.removeAtomFromBoard = function( atom)
{
	var cells = atom.getOccupiedBoardCells();
	for(var i=0;i<cells.length;i++)
	{
		this.board.markCellAsEmpty(cells[i].x, cells[i].y);
	}
}

// Функция проверяет свободно ли место на доске по указанным координатам
CMolecule.prototype.placeAtomRelative=function(atom, dx, dy)
{
	if( atom.molecule==null)
	{
		trace("mc2D arrange error: incorrect molecule");
		return false;
	}
	var atomX = dx;
	var atomY = dy;

	atom.setX( dx);
	atom.setY( dy);

	var i=0;
	var cells = atom.getOccupiedBoardCells();
//trace("cells.length="+cells.length);
	for(;i<cells.length;i++)
	{
//trace("cells[i].x="+cells[i].x+", cells[i].y="+cells[i].y);
		if( !this.board.cellIsEmpty(cells[i].x, cells[i].y))
		{
			//trace("cells is busy");
			break;
		}
		else
		{
			//trace("cells is empty");
		}
	}
	if( i==cells.length)
	{
		i=0;
		for(;i<cells.length;i++)
		{
			this.board.markCellAsBusy(cells[i].x, cells[i].y);
		}
		return true;
	}

	atom.setX( atomX);
	atom.setY( atomY);
	return false;
}
// Функция обеспечивает расчет новых положений атомов на доске и создание и размещение графических элементов
CMolecule.prototype.visualize = function()
{
	this.calcPositions();
	this.create();
	this.setStyles();
}
// Функция добавляет значение к флагу визуализации
CMolecule.prototype.wfAddDrawStyle = function(atom)
{
	atom.addDrawType(this.temp);
}
// Функция убирает значение от флага визуализации
CMolecule.prototype.wfRemoveDrawStyle = function(atom)
{
	atom.removeDrawType(this.temp);
}
// Функция устанавливает флаг
CMolecule.prototype.wfSetDrawStyle = function(atom)
{
	atom.setDrawStyle( this.temp);
}
// Функция показывает/прячет все атомы H
CMolecule.prototype.showH = function(val)
{
	this.isShowH = val;
	var bounds = this.getScreenBounds();
	if( this.isShowH)
		this.board.cellSizeX = gvBigCellSize;
	else
		this.board.cellSizeX = gvCellSize;
trace("this.board.cellSizeX="+this.board.cellSizeX);
	this.calcTopDown( this.wfShowH);
	this.create();
	this.setStyles();
	var afterBounds = this.getScreenBounds();
	this.board.x += (bounds.left - afterBounds.left);
	this.board.y += (bounds.top - afterBounds.top);
	this.board.onMoleculeChanged();
}

CMolecule.prototype.getText = function(type, count)
{
	if( count == 0)	return "";
	if( count == 1)	return type;
	return type+"<font size=\"10px\">" + count + "</font>";
}

CMolecule.prototype.wfShowH = function(atom)
{
	atom.showH();
}
// Функция возвращает атом, который сейчас подсвечен
CMolecule.prototype.getAtomUnderMouse = function()
{
	this.temp = null;
	this.calcTopDown( this.wfGetAtomUnderMouse);
	return this.temp;
}
CMolecule.prototype.wfGetAtomUnderMouse = function(atom)
{
	if( (atom.drawType&32)==32 || (atom.oLink!=null && atom.oLink.isHighlighted))
	{
		this.temp = atom;
	}
}
// Функция возвращает атом, который сейчас подсвечен
CMolecule.prototype.cropImages = function()
{
	this.calcTopDown( this.wfCropImages);
}
CMolecule.prototype.wfCropImages = function(atom)
{
	if( atom.oLink != null)
	{
		atom.oLink.cropMe();
	}
}
// Функция вырезает меньшее поддерево и приклеивает его к атому
CMolecule.prototype.spliceSmallestSubtree = function(slicedAtom, parentAtom)
{
	trace("Try splice "+slicedAtom.type+" to " + parentAtom.type);

	var spliceDifferent=false;
	if( slicedAtom.molecule != parentAtom.molecule)
	{
		trace("mc2d splice error: cannot glue different molecules");
		spliceDifferent = true;
		if( slicedAtom.molecule.getAtomsCount() + parentAtom.molecule.getAtomsCount() > gvMaxAtomsCount)
		{
			trace("mc2D spliceSmallestSubtree error: max atoms count exceed");
			return false;
		}
	}

	// Посчитаем количество свободных связей у атома, к которому пробуем прикрепить
	var baseFreeLinksParent = CAtom.prototype.getDescription(parentAtom.getType()).freeLinks - parentAtom.getLockedLinks();
	trace("baseFreeLinksParent="+baseFreeLinksParent);

	// Посчитаем количество свободных связей у атома, который пробуем оторвать
	var baseFreeLinksChild = CAtom.prototype.getDescription(slicedAtom.getType()).freeLinks - slicedAtom.getLockedLinks();
	trace("baseFreeLinksChild="+baseFreeLinksChild);

	// Если между атомами УЖЕ существует связь, то ничего не делаем
	if( parentAtom.hasChild( slicedAtom) || slicedAtom.hasChild( parentAtom))	return false;

	// Склеивать можно, если у нового родителя есть хотя бы одна свободная связь
	if( baseFreeLinksParent > 0)
	{
		var biggestRoot = this.getBiggestSubtreeRoot( slicedAtom);
//trace("biggestRoot=" + biggestRoot.type + ":" + biggestRoot.parent);
		if( biggestRoot == null)
		{
			if( slicedAtom.parent == null)
			{
				// пытаемся оторвать "корень" дерева
				this.root = null;
				parentAtom.molecule.calcTopDown( parentAtom.molecule.wfAttach, slicedAtom);
				parentAtom.addChild( slicedAtom);
			}
		}
		else
		{
			if( biggestRoot == slicedAtom.parent)
			{
				trace("biggestRoot = slicedAtom.parent");
				slicedAtom.parent.removeChild( slicedAtom);
				slicedAtom.linkType = 1;
				parentAtom.molecule.calcTopDown( parentAtom.molecule.wfAttach, slicedAtom);
				parentAtom.addChild( slicedAtom);
			}
			else
			{
				trace("biggestRoot != slicedAtom.parent");
				this.droopTree( slicedAtom);
				slicedAtom.removeChild( biggestRoot);
				slicedAtom.linkType = 1;
				parentAtom.molecule.calcTopDown( parentAtom.molecule.wfAttach, slicedAtom);
				parentAtom.addChild( slicedAtom);
				this.root = biggestRoot;
			}
		}
	}
	this.onStructureChanged();
	this.optimize();
	this.visualize();
	this.print();

	if( spliceDifferent)
	{
		parentAtom.molecule.onStructureChanged();
		parentAtom.molecule.optimize();
		parentAtom.molecule.setDefaultStyles();
		parentAtom.molecule.visualize();
		parentAtom.molecule.print();
	}

	if( this.root == null)
	{
		this.board.workspace.removeBoard( this.board);
	}
}

// Функция приклеивает визуальные элементы к себе
CMolecule.prototype.wfAttach = function(atom)
{
trace("wfAttach atomType="+atom.type);
	atom.molecule = this;
	if( atom.oText!=null)
	{
		atom.oText.parent = this.board;
		atom.oText.atom = atom;
	}
	if( atom.oLink!=null)
	{
		atom.oLink.parent = this.board;
		atom.oLink.atom = atom;
	}
}