CMolecule.prototype.optimize=function()
{
	var maxLength = 0;
	if( optimizeDebugInfo)
		trace("BEGIN OPTIMIZATION");

	// 0. Сотрем информацию о "главной линии"
	this.calcBottomUp( this.freeMainLineFlags);

	// 1. Рассчитаем длины поддеревьев по всем атомам
	this.calcBottomUp( this.calculateLengths);

	// 2. Определим дерево у которого наибольшая длина подцепочек у одного или двух дочерних узлов
	maxLength = this.maxSubtreeLength;

	// 3. Попробуем определить новую длинную поcледовательность
	this.findNewRoot();

	if( this.maxSubtreeItem == null)
	{
		return;
	}

	if( this.maxSubtreeItem != null && optimizeDebugInfo)
	{
		trace( "**** New root is atom with id=[" + this.maxSubtreeItem.type + "]");
		trace( "**** New subtree length=[" + this.maxSubtreeLength + "]");
		trace( "**** Old subtree length=[" + maxLength + "]");
	}

	// Проверим, нет "сверху" претендента (на новый корень) какого-нибудь цикла
	if( this.maxSubtreeItem != null)
	{
		var temp = this.maxSubtreeItem;
		while( temp.parent != null)
		{
			temp = temp.parent;
			if( temp instanceof CCycleAtom)
			{
				this.maxSubtreeItem = null;
				break;
			}
		}
	}

	/*if( this.maxSubtreeItem != this.root ||
		(maxLength != this.maxSubtreeLength))*/
	if( this.maxSubtreeItem != null && maxLength!=this.maxSubtreeLength)
	{
		if( optimizeDebugInfo)
			trace("Optimization complete");
		trace(" this.maxSubtreeItem="+this.maxSubtreeItem);
		this.maxSubtreeItem.sortLongestChildren();
		this.droopTree(this.maxSubtreeItem);
		this.root = this.maxSubtreeItem;
		this.calcTopDown( this.setMainLineFlags);
		this.calculateDistances();
		this.optimize();

		if( optimizeDebugInfo)
			this.print();
	}
	else
	{
		if( optimizeDebugInfo)
			trace("No optimization needed");
		this.calcTopDown( this.setMainLineFlags);
		this.print();
	}
	this.setStyles();
	if( optimizeDebugInfo)
		trace("END OPTIMIZATION");
trace("***BEGIN PRINT****************************************************");
this.print();
trace("***PRINTED****************************************************");
}

CMolecule.prototype.freeMainLineFlags=function(atom)
{
	//trace("isOnMainLine is FALSE for " + atom.type);
	atom.isOnMainLine = false;
	atom.setDrawStyle( atom);
}

// Расстановка флагов "главной" линии
CMolecule.prototype.setMainLineFlags=function(atom)
{
	if( atom instanceof CCycle)	return;
	if( atom.parent == null)
	{
		atom.isOnMainLine = true;
		atom.setDrawStyle( 2);
		if( atom.children.length>1)
		{
			atom.children[0].isOnMainLine = true;
			atom.children[0].setDrawStyle( 2);
			atom.children[1].isOnMainLine = true;
			atom.children[1].setDrawStyle( 2);
		}
		else	if( atom.children.length==1)
		{
			atom.children[0].isOnMainLine = true;
			atom.children[0].setDrawStyle( 2);
		}
		return;
	}
	if( atom.isOnMainLine)
	{
		if( atom.longestChild != null)
		{
			atom.longestChild.isOnMainLine = true;
			atom.longestChild.setDrawStyle( 2);
		}
	}
}

// Расчет длинн поддеревьев
CAtom.prototype.calculateLengths=function()
{
	if( this.children.length == 0)
	{
		this.longestChildCount = this.getOptimizeWeight();
		this.longestChild = null;
		return;
	}
	this.longestChildCount = this.children[0].longestChildCount;
	this.longestChild = this.children[0];
	var i=1;
	for(; i<this.children.length; i++)
	{
		if( this.children[i].longestChildCount > this.longestChildCount)
		{
			this.longestChildCount = this.children[i].longestChildCount;
			this.longestChild = this.children[i];
		}
	}
	//  Добавляем "свой" уровень
	this.longestChildCount += this.getOptimizeWeight();
}

// Расчет длинн поддеревьев
CMolecule.prototype.calculateLengths=function(atom)
{
	atom.calculateLengths();
}

// Определение нового корня
CMolecule.prototype.findNewRoot=function()
{
	this.maxSubtreeLength = -1;
	this.maxSubtreeItem = this.root;
	this.calcTopDown( this.wfFindNewRoot);
}

// Сортирует атомы главной цепочки
CAtom.prototype.sortLongestChildren = function()
{
	var tempArray = this.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.longestChildCount < child2.longestChildCount)
			{
				tempArray[j] = child1;
				tempArray[i] = child2;
			}
		}
	}
}
// Возвращает длину максимальной цепочки, возможно из двух поддеревьев и сортирует ветки
CAtom.prototype.optimizeLongestChildCount = function()
{
	var maxSum = 0;
	if( this.children.length == 1)
	{
		maxSum = this.longestChildCount;
	}
	else
	{
		//var tempArray = this.children;
		var tempArray = new Array();
		for(var i=0; i<this.children.length; i++)
			tempArray.push(this.children[i]);
		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.longestChildCount < child2.longestChildCount)
				{
					tempArray[j] = child1;
					tempArray[i] = child2;
				}
			}
		}
		// После сортировки берем первые 2 дочерних элемента как наиболее длинные

		maxSum = tempArray[0].longestChildCount + tempArray[1].longestChildCount + 1;
		//trace("isOnMainLine is TRUE for " + tempArray[0].type);
		//trace("isOnMainLine is TRUE for " + tempArray[1].type);
		this.longestChild = tempArray[0];
	}
	return maxSum;
}
CMolecule.prototype.wfFindNewRoot=function(atom)
{
	if( optimizeDebugInfo)
	{
		trace("***** wfFindNewRoot for " + atom.type);
		trace("atom.children.length=" + atom.children.length);
	}
	if( atom.children.length == 0)
	{
		return;
	}

	var maxSum = atom.optimizeLongestChildCount();

//	trace("maxSum=" + maxSum);

	if( maxSum > this.maxSubtreeLength)
	{
		this.maxSubtreeLength = maxSum;
		this.maxSubtreeItem = atom;
	}
//	trace("*********************");
}
// Переводит все вышерасположенное дерево в разряд ветвей
CMolecule.prototype.droopTree = function(atom)
{
trace("*************droopTree********:" + atom.type);
	var	parentChain = new Array();
	var temp = atom.getVisualInstance();
	while( temp != null)
	{
//trace("temp="+temp.type);
		parentChain.push(temp);
		temp = temp.parent;
		if( temp != null)
			temp = temp.getVisualInstance();
	}
//trace("parentChain.length="+parentChain.length);
	for( var i=parentChain.length-1; i>=0; i--)
	{
//trace("*********************");
		var child = parentChain[i];
//trace("child.type="+child.type+":"+child.parent);
		var realChildParent = child.parent;
		var childParent = child.parent;
		if( childParent == null)	continue;
		childParent = childParent.getVisualInstance();
//trace("11. childParent.children.length="+childParent.children.length);
		if( child.parent instanceof CCycleAtom)
		{
			childParent.makeHead(child.parent);
		}
		var linkType = child.linkType;
		if( optimizeDebugInfo)
			trace( "Atom type is " + parentChain[i].type);
//trace("1. childParent.children.length="+childParent.children.length);
//for(var o=0; o<childParent.children.length;o++)
//trace("childParent.children[i] = "+childParent.children[o].type);
		if( child.parent.removeChild( child))
		{
//trace("0");
//trace("child.type="+child.type);
			if( child instanceof CCycle)
			{
				child.cycleChildren[0].addChild( childParent);
			}
			else
				child.addChild( childParent);
			childParent.linkType = linkType;
			if( childParent instanceof CCycle)
			{
				childParent.head().linkType = linkType;
			}
		}
//trace("2. childParent.children.length="+childParent.children.length);

//break;
	}

//this.print();
//exit();
}
// Возвращает количество атомов в дереве
CMolecule.prototype.getAtomsCount = function()
{
	this.atomsCount = 0;
	this.calcBottomUp( this.wfCalcCount);
	return this.atomsCount;
}
CMolecule.prototype.wfCalcCount = function(atom)
{
	this.atomsCount++;
}
// Функция расчета длины поддерева
CMolecule.prototype.wfCalcSubtreeLength = function(atom)
{
	atom.subtreeLength = 0;
	var i=0;
	for(; i<atom.children.length; i++)
	{
		atom.subtreeLength += atom.children[i].subtreeLength;
	}
	atom.subtreeLength += i;
}