"use strict";

/**
 * Created by Ilja.Kirillov on 18.03.14.
 */
var g_oMathSettings = {};
function MathMenu (type)
{
	this.Type = para_Math;
	this.Menu = type;
}
function ParaMath()
{
    this.Id = g_oIdCounter.Get_NewId();
    this.Type  = para_Math;

    this.MathPara = true;  // false - внутристроковая формула, true - формула на отдельной строке (w:oMath/w:oMathPara)

    this.OldMathPara = null;

    this.Jc       = undefined;
    //this.Math = new CMathComposition();
    //this.Math.Parent = this;
    //this.Root = this.Math.Root;

    this.Root       = new CMathContent();
    this.Root.bRoot = true;

    this.X          = 0;
    this.Y          = 0;

    //this.CurrentContent    = this.RootComposition;
    //this.SelectContent     = this.RootComposition;
    this.bSelectionUse     = false;


    //this.State      = new CParaRunState();       // Положение курсора и селекта для данного run
    this.Paragraph  = null;

    this.StartLine  = 0;
    this.StartRange = 0;

    this.Lines       = []; // Массив CParaRunLine
    this.Lines[0]    = new CParaRunLine();
    this.LinesLength = 0;

    this.Range = this.Lines[0].Ranges[0];

    this.NearPosArray = [];

    this.Width        = 0;
    this.WidthVisible = 0;
    this.Height       = 0;
    this.Ascent       = 0;
    this.Descent      = 0;

    this.DefaultTextPr = new CTextPr();
    //this.DefaultTextPr.Init_Default();

    this.DefaultTextPr.Italic     = true;
    this.DefaultTextPr.FontFamily = {Name  : "Cambria Math", Index : -1 };
    this.DefaultTextPr.RFonts.Set_All("Cambria Math", -1);


    /*this.MathPr =
    {
        naryLim:    NARY_UndOvr,
        intLim:     NARY_SubSup,
        brkBin:     BREAK_BEFORE,
        brkSubBin:  BREAK_MIN_MIN,
        wrapIndent: 0,
        smallFrac:  false,
        wrapRight:  false
    };*/

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
	g_oTableId.Add( this, this.Id );
}


ParaMath.prototype =
{
    Get_Id : function()
    {
        return this.Id;
    },

    Copy : function(Selected)
    {
        // TODO: ParaMath.Copy

        var NewMath = new ParaMath();

        if(Selected)
        {
            var result = this.GetSelectContent();
            NewMath.Root = result.Content.Copy(Selected);
            NewMath.Root.bRoot = true;
        }
        else
        {
            NewMath.Root = this.Root.Copy(Selected);
            NewMath.Root.bRoot = true;
        }

        /// argSize, bDot и bRoot выставить на объединении контентов

        return NewMath;
    },

    Set_Paragraph : function(Paragraph)
    {
        this.Paragraph = Paragraph;
    },

    Is_Empty : function()
    {
        return this.Root.content.length == 0;
    },

    Is_StartFromNewLine : function()
    {
        return false;
    },

    Get_TextPr : function(_ContentPos, Depth)
    {
        // TODO: ParaMath.Get_TextPr

        var TextPr = new CTextPr();

        var mTextPr = this.Root.Get_TextPr(_ContentPos, Depth);
        TextPr.Merge( mTextPr );


        return TextPr;
    },
    Get_CompiledTextPr : function(Copy)
    {
        // TODO: ParaMath.Get_CompiledTextPr

        var TextPr = new CTextPr();

        var oContent = this.GetSelectContent();
        var mTextPr = oContent.Content.Get_CompiledTextPr(Copy);
        TextPr.Merge( mTextPr );

        return TextPr;
    },
    Add : function(Item)
    {
		var Type = Item.Type;
		var oContent = this.GetSelectContent();
		var oStartContent = oContent.Content.content[oContent.Start];
		var oEndContent = oContent.Content.content[oContent.End];

		if ( para_Text === Type)
		{
			var oText = new CMathText(false);
			oText.addTxt(Item.Value);
			oStartContent.Add(oText, true);
		}
		else if ( para_Space === Type )
		{
			//var oSpace = new ParaSpace(1);
			var oText = new CMathText(false);
			oText.addTxt(" ");
			oStartContent.Add(oText, true);
		}
		else if ( para_Math === Type )
		{
			if (oStartContent.Type == para_Math_Run && oStartContent.IsPlaceholder())
			{
				History.Create_NewPoint();
				
				var Items = [];
				Items.push(oContent.Content.content[0]);
				oContent.Content.content.splice( 0, 1 );
				History.Add(oContent.Content, {Type: historyitem_Math_RemoveItem, Items:Items, Pos: 0});
				
				oContent.Content.Load_FromMenu(Item.Menu, this.Paragraph);
			}
			else
			{
				var nPosStart = oStartContent.State.ContentPos,
					nLenStart = oStartContent.Content.length,
					nPosEnd = oEndContent.State.ContentPos;
				
				History.Create_NewPoint();
				
				if(nPosStart != nLenStart) //вставка идет в mathcontent
				{
					var oMRun = new ParaRun(this.Paragraph, true);
					oMRun.Pr = oStartContent.Pr;

					for (var i=nLenStart-1; i>=nPosStart; i--)
					{
						var Pos = oMRun.Content.length;
						var EndPos = Pos + 1;
						var oItem = oStartContent.Content[i];
						oMRun.Add(oItem, true);
						oStartContent.Remove_FromContent(i, 1, false);
					}
				}

				oContent.Content.Load_FromMenu(Item.Menu, this.Paragraph);

				if(nPosStart != nLenStart)
				{
					var items = [];
					oContent.Content.Add(oMRun,oContent.Content.CurPos+1);
					items.push(oMRun);
					var Pos = oContent.Content.CurPos,
						PosEnd = Pos + 1;
					History.Add(oContent.Content, {Type: historyitem_Math_AddItem, Items: items, Pos: Pos, PosEnd: PosEnd});
				}
				
				
			}
			oContent.Content.SetRunEmptyToContent(true);
		}
	},

    Remove : function(Direction, bOnAddText)
    {
		var oContent = this.GetSelectContent();
		if (oContent.Start == oContent.End)
		{
			var oElem = oContent.Content.getElem(oContent.Start);
			
			if (oElem.Type == para_Math_Composition)
				this.RemoveElem(oContent, Direction, bOnAddText);
			else if (oElem.Type == para_Math_Run && oElem.IsPlaceholder() && bOnAddText == false)
			{
				var Comp = oContent.Content.GetParent();
				Comp.SetSelectAll();
				Comp.SelectToParent();
				this.bSelectionUse = true;
			}
			else if (oElem.Type == para_Math_Run && oElem.IsPlaceholder() && bOnAddText == true)
			{
				History.Create_NewPoint();
				
				var Items = [];
				Items.push(oContent.Content.content[0]);
				oContent.Content.content.splice( 0, 1 );
				History.Add(oContent.Content, {Type: historyitem_Math_RemoveItem, Items:Items, Pos: 0});
				
				var oMRun = new ParaRun(this.Paragraph, true);
				oMRun.StartLine = 0; oMRun.StartRange = 0;
				oContent.Content.addElementToContent(oMRun);
				var items = [];
				items.push(oMRun);
				var Pos = oContent.Content.CurPos,
					PosEnd = Pos + 1;
				History.Add(oContent.Content, {Type: historyitem_Math_AddItem, Items: items, Pos: Pos, PosEnd: PosEnd});
			}
			else	//pararun
			{
				if (Direction < 0 && oElem.State.ContentPos - 1 < 0) //backspase
				{
					if (oContent.Content.CurPos - 1 >= 0)//слева есть элементы
					{
						var prevElem = oContent.Content.getElem(oContent.Start - 1);
						if (prevElem.Type == para_Math_Composition) //слева композиция
						{
							this.Set_Select_ToMComp(Direction);
							return;
						}
						else //слева ран
						{
							History.Create_NewPoint();
							prevElem.Remove(Direction, bOnAddText);
							
							if(prevElem.Content.length == 0 && !bOnAddText) //тк pararun пустой, удаляем его
							{
								var Items = [];
								Items.push(prevElem.Parent.content[0]);
								prevElem.Parent.content.splice( 0, 1 );
								History.Add(prevElem.Parent, {Type: historyitem_Math_RemoveItem, Items:Items, Pos: 0});
								prevElem.Parent.CurPos--;
							}
							return;
						}
					}
					else //переходим на уровень выше и выделяем композицию
					{
						var Comp = oContent.Content.GetParent();
						Comp.SetSelectAll();
						Comp.SelectToParent();
						this.bSelectionUse = true;
					}
				}
				else if (Direction > 0 && oElem.State.ContentPos + 1 > oElem.Content.length) //delete
				{
					if (oContent.Content.CurPos + 1 >= oContent.Content.content.length) //переходим на уровень выше и выделяем композицию
					{
						var Comp = oContent.Content.GetParent();
						Comp.SetSelectAll();
						Comp.SelectToParent();
						this.bSelectionUse = true;						
					}
					else //справа есть элемент
					{
						var nNextElem = oContent.Start + 1;
						var nextElem = oContent.Content.getElem(nNextElem);
						if (nextElem.Type == para_Math_Composition) //справа композиция
						{
							this.Set_Select_ToMComp(Direction);
							return;
						}
						else //справа ран
						{
							History.Create_NewPoint();
							nextElem.State.ContentPos = 0;
							nextElem.Remove(Direction, bOnAddText);
							if(nextElem.Content.length == 0 && !bOnAddText) //тк pararun пустой, удаляем его
							{
								var Items = [];
								Items.push(nextElem);
								nextElem.Parent.content.splice( nNextElem, 1 );
								History.Add(nextElem.Parent, {Type: historyitem_Math_RemoveItem, Items:Items, Pos: 0});
							}
							return;
						}
					}
				}

				History.Create_NewPoint();
				oElem.Remove(Direction, bOnAddText);
				if(oElem.Content.length == 0 && !bOnAddText) //тк pararun пустой, удаляем его
				{
					var Items = [];
					Items.push(oElem.Parent.content[oContent.Start]);
					oElem.Parent.content.splice( oContent.Start, 1 );
					History.Add(oElem.Parent, {Type: historyitem_Math_RemoveItem, Items:Items, Pos: oContent.Start});
					if (Direction < 0)
						oContent.Content.CurPos--;
				}
			}
		}
		else
			return this.RemoveElem(oContent, Direction, bOnAddText);
		
    },
		
	RemoveElem: function(oContent, Direction, bOnAdd)
    {
        var start = oContent.Start,
            end   = oContent.End,
            oMathContent = oContent.Content;
		var len = end - start + 1;

        History.Create_NewPoint();		
        History.Create_NewPoint();
		var oStartContent = oContent.Content.content[start];
		var oEndContent = oContent.Content.content[end];
		var Items = [];
		for (var i=start; i<=end; i++)
			Items.push(oContent.Content.content[i]);
			
		oContent.Content.CurPos -= len;

		oContent.Content.content.splice( oContent.Start, len );
		History.Add(oContent.Content, {Type: historyitem_Math_RemoveItem, Items:Items, Pos: oContent.Start});
		return;
    },
	
    GetSelectContent: function()
    {
        return this.Root.GetSelectContent();
    },

    Get_CurrentParaPos : function()
    {
        //var CurPos = this.State.ContentPos;

        /*if ( CurPos >= 0 && CurPos < this.Content.length )
            return this.Content[CurPos].Get_CurrentParaPos();*/

        return new CParaPos( this.StartRange, this.StartLine, 0, 0 );
    },

    Apply_TextPr : function(TextPr, IncFontSize, ApplyToAll)
    {
        // TODO: ParaMath.Apply_TextPr

        if(ApplyToAll == true) // для ситуации, когда ApplyToAll = true, в Root формулы при этом позиции селекта не проставлены
        {
            this.Root.Apply_TextPr(TextPr, IncFontSize, true);
        }
        else
        {
            var content = this.GetSelectContent().Content;
            content.Apply_TextPr(TextPr, IncFontSize, ApplyToAll);
        }

    },

    Clear_TextPr : function()
    {

    },

    Check_NearestPos : function(ParaNearPos, Depth)
    {
        /*var MathNearPos = new CParagraphElementNearPos();
        MathNearPos.NearPos = ParaNearPos.NearPos;
        MathNearPos.Depth   = Depth;

        // CParagraphNearPos for ParaNearPos
        this.NearPosArray.push( MathNearPos );
        ParaNearPos.Classes.push( this );

        var CurPos = ParaNearPos.NearPos.ContentPos.Get(Depth);
        this.Content[CurPos].Check_NearestPos( ParaNearPos, Depth + 1 );*/
    },

    Get_DrawingObjectRun : function(Id)
    {
        return null;
    },

    Get_DrawingObjectContentPos : function(Id, ContentPos, Depth)
    {
        return false;
    },

    Get_Layout : function(DrawingLayout, UseContentPos, ContentPos, Depth)
    {
    },

    Get_NextRunElements : function(RunElements, UseContentPos, Depth)
    {
    },

    Get_PrevRunElements : function(RunElements, UseContentPos, Depth)
    {
    },

    Collect_DocumentStatistics : function(ParaStats)
    {
        // TODO: ParaMath.Collect_DocumentStatistics
    },

    Create_FontMap : function(Map)
    {
        // TODO: ParaMath.Create_FontMap

        // Styles.js
        // Document_CreateFontMap

        this.Root.Create_FontMap(Map);

    },

    Get_AllFontNames : function(AllFonts)
    {
        // TODO: ParaMath.Get_AllFontNames

        // выставить для всех шрифтов, к-ые используются в AllFonts true
        AllFonts["Cambria Math"] = true;

        this.Root.Get_AllFontNames(AllFonts);
    },

    Get_SelectedText : function(bAll, bClearText)
    {
        if ( true === bAll || true === this.Selection_IsUse() )
        {
            if ( true === bClearText )
                return null;

            return "";
        }
        
        return "";
    },

    Clear_TextFormatting : function( DefHyper )
    {
    },
    
    Can_AddDropCap : function()
    {
        return false;
    },
    
    Get_TextForDropCap : function(DropCapText, UseContentPos, ContentPos, Depth)
    {
        if ( true === DropCapText.Check )
            DropCapText.Mixed = true;
    },

    Get_StartTabsCount : function(TabsCounter)
    {
        return false;
    },

    Remove_StartTabs : function(TabsCounter)
    {
        return false;
    },

    Add_ToContent : function(Pos, Item, UpdatePosition)
    {

    },
//-----------------------------------------------------------------------------------
// Функции пересчета
//-----------------------------------------------------------------------------------

    Recalculate_Reset : function(StartRange, StartLine)
    {
        this.StartLine   = StartLine;
        this.StartRange  = StartRange;
        this.LinesLength = 0;
    },

    Recalculate_Range : function(PRS, ParaPr, Depth)
    {
        // TODO: Пока у нас контент здесь состоит из 1 элемента (всего элемента Math). Поэтому у нас в данном
        //       контенте есть 2 позиции 0 и 1, т.е. до или после Math.

        if ( this.Paragraph !== PRS.Paragraph )
        {
            this.Paragraph = PRS.Paragraph;
            this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );
        }

        var CurLine  = PRS.Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );

        var Para      = PRS.Paragraph;
        var ParaLine  = PRS.Line;
        var ParaRange = PRS.Range;

        var TextPr = new CTextPr();
        TextPr.Init_Default();

        var RPI = new CRPI();
        RPI.bInline       = this.MathPara === false;
        RPI.bChangeInline = this.MathPara != this.OldMathPara;

        var ArgSize = new CMathArgSize();

        this.Root.Resize(g_oTextMeasurer, null, this, RPI/*recalculate properties info*/, ArgSize,  TextPr);

        //this.Root.Resize(null, this, g_oTextMeasurer, RPI/*recalculate properties info*/, TextPr);
        this.OldMathPara = this.MathPara;


        var pos = new CMathPosition();
        pos.x = 0;
        pos.y = 0;

        this.Root.setPosition(pos);

        this.Width        = this.Root.size.width;
        this.Height       = this.Root.size.height;
        this.WidthVisible = this.Root.size.width;
        this.Ascent       = this.Root.size.ascent;
        this.Descent      = this.Root.size.height - this.Root.size.ascent;

        //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        // TODO: ParaMath.Recalculate_Range
        // Пока логика пересчета здесь аналогична логике пересчета отдельного символа в ParaRun. В будущем надо будет
        // переделать с разбиванием на строки.
        //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

        // Если это первый отрезок в данной строке, тогда нам надо добавить строку (первую строку не добавляем,
        // т.к. она всегда есть)
        if ( 0 === CurRange )
        {
            if ( 0 !== CurLine )
            {
                this.Lines[CurLine] = new CParaRunLine();
                this.LinesLength    = CurLine + 1;
            }
            else
            {
                this.LinesLength  = CurLine + 1;
            }
        }

        // Отмечаем, что началось слово
        PRS.StartWord = true;

        // При проверке, убирается ли слово, мы должны учитывать ширину предшествующих пробелов.
        var LetterLen = this.Width;
        if ( true !== PRS.Word )
        {
            // Слово только началось. Делаем следующее:
            // 1) Если до него на строке ничего не было и данная строка не
            //    имеет разрывов, тогда не надо проверять убирается ли слово в строке.
            // 2) В противном случае, проверяем убирается ли слово в промежутке.

            // Если слово только началось, и до него на строке ничего не было, и в строке нет разрывов, тогда не надо проверять убирается ли оно на строке.
            if ( true !== PRS.FirstItemOnLine || false === Para.Internal_Check_Ranges(ParaLine, ParaRange) )
            {
                if ( PRS.X + PRS.SpaceLen + LetterLen > PRS.XEnd )
                {
                    PRS.NewRange  = true;
                }
            }

            if ( true !== PRS.NewRange )
            {
                // Отмечаем начало нового слова
                PRS.Set_LineBreakPos( 0 );
                PRS.WordLen = this.Width;
                PRS.Word    = true;
            }
        }
        else
        {
            if ( PRS.X + PRS.SpaceLen + PRS.WordLen + LetterLen > PRS.XEnd )
            {
                if ( true === PRS.FirstItemOnLine )
                {
                    // Слово оказалось единственным элементом в промежутке, и, все равно,
                    // не умещается целиком. Делаем следующее:
                    //
                    // 1) Если у нас строка без вырезов, тогда ставим перенос строки на
                    //    текущей позиции.
                    // 2) Если у нас строка с вырезом, и данный вырез не последний, тогда
                    //    ставим перенос внутри строки в начале слова.
                    // 3) Если у нас строка с вырезом и вырез последний, тогда ставим перенос
                    //    строки в начале слова.

                    if ( false === Para.Internal_Check_Ranges(ParaLine, ParaRange)  )
                    {
                        // Слово не убирается в отрезке. Переносим слово в следующий отрезок
                        PRS.MoveToLBP = true;
                        PRS.NewRange  = true; // перенос на новую строку
                    }
                    else
                    {
                        PRS.EmptyLine   = false;
                        //PRS.X          += WordLen;

                        // Слово не убирается в отрезке, но, поскольку, слово 1 на строке и отрезок тоже 1,
                        // делим слово в данном месте
                        PRS.NewRange = true; // перенос на новую строку
                    }
                }
                else
                {
                    // Слово не убирается в отрезке. Переносим слово в следующий отрезок
                    PRS.MoveToLBP = true;
                    PRS.NewRange  = true;
                }
            }

            if ( true !== PRS.NewRange )
            {
                // Мы убираемся в пределах данной строки. Прибавляем ширину буквы к ширине слова
                PRS.WordLen += LetterLen;
            }
        }

        if(PRS.NewRange  == false)
            this.Root.Recalculate_Reset(PRS.Range, PRS.Line);



        var RangeStartPos = 0;
        var RangeEndPos   = 0;

        if ( true !== PRS.NewRange )
        {
            RangeEndPos = this.Root.content.length; // RangeEndPos = 1;    to    RangeEndPos = this.Content.length;

            // Удаляем лишние строки, оставшиеся после предыдущего пересчета в самом конце
            if ( this.Lines.length > this.LinesLength )
                this.Lines.length = this.LinesLength;

            // Обновляем метрику строки
            if ( PRS.LineAscent < this.Ascent )
                PRS.LineAscent = this.Ascent;

            if ( PRS.LineDescent < this.Descent )
                PRS.LineDescent = this.Descent;
        }

        if ( 0 === CurLine && 0 === CurRange )
        {
            this.Range.StartPos = RangeStartPos;
            this.Range.EndPos   = RangeEndPos;

            /*this.Lines[0].RangesLength = 1;
             this.Lines[0].Ranges.length = this.Content.length - 1;*/

            this.Lines[0].RangesLength = 1;

            if ( this.Lines[0].Ranges.length > 1 )
                this.Lines[0].Ranges.length = 1;
        }
        else
            this.Lines[CurLine].Add_Range( CurRange, RangeStartPos, RangeEndPos );

        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    },

    Recalculate_Set_RangeEndPos : function(PRS, PRP, Depth)
    {
        var CurLine  = PRS.Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );
        var CurPos   = PRP.Get(Depth);

        this.Lines[CurLine].Ranges[CurRange].EndPos = CurPos;
    },

    Recalculate_Range_Width : function(PRSC, _CurLine, _CurRange)
    {
        var CurLine = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

        var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
        var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;

        if ( EndPos >= 1 )
        {
            PRSC.Range.Letters++;

            if ( true !== PRSC.Word )
            {
                PRSC.Word = true;
                PRSC.Range.Words++;
            }

            PRSC.Range.W += this.Width;
            PRSC.Range.W += PRSC.SpaceLen;

            PRSC.SpaceLen = 0;

            // Пробелы перед первым словом в строке не считаем
            if ( PRSC.Range.Words > 1 )
                PRSC.Range.Spaces += PRSC.SpacesCount;
            else
                PRSC.Range.SpacesSkip += PRSC.SpacesCount;

            PRSC.SpacesCount = 0;
        }
    },

    Recalculate_Range_Spaces : function(PRSA, _CurLine, _CurRange, _CurPage)
    {
        var CurLine = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

        var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
        var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;

        if ( EndPos >= 1 )
        {
            if ( 0 !== PRSA.LettersSkip )
            {
                this.WidthVisible = this.Width;
                PRSA.LettersSkip--;
            }
            else
                this.WidthVisible = this.Width + PRSA.JustifyWord;

            // Позиция в документе для формулы
            //this.Math.absPos = {x: PRSA.X, y: PRSA.Y - this.Root.size.ascent};
            this.X     = PRSA.X;
            this.Y     = PRSA.Y - this.Root.size.ascent;

            PRSA.X    += this.WidthVisible;
            PRSA.LastW = this.WidthVisible;
        }
    },

    Recalculate_PageEndInfo : function(PRSI, _CurLine, _CurRange)
    {
    },

    Save_RecalculateObject : function(Copy)
    {
        var RecalcObj = new CRunRecalculateObject(this.StartLine, this.StartRange);
        RecalcObj.Save_Lines( this, Copy );
        
        // TODO: Сделать сохранение пересчета у формулы
        
        return RecalcObj;
    },

    Load_RecalculateObject : function(RecalcObj)
    {
        RecalcObj.Load_Lines(this);
        RecalcObj.Load_ZeroRange(this);
    },

    Prepare_RecalculateObject : function()
    {
        this.Lines       = [];
        this.Lines[0]    = new CParaRunLine();
        this.LinesLength = 0;

        this.Range = this.Lines[0].Ranges[0];
    },

    Is_EmptyRange : function(_CurLine, _CurRange)
    {
        var CurLine = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

        var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
        var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;

        if ( EndPos >= 1 )
            return false;

        return true;
    },

    Check_Range_OnlyMath : function(Checker, CurRange, CurLine)
    {
        if (null !== Checker.Math)
        {
            Checker.Math   = null;
            Checker.Result = false;
        }
        else
            Checker.Math = this;
    },

    Check_MathPara : function(Checker)
    {
        Checker.Found  = true;
        Checker.Result = false;
    },    

    Check_BreakPageInRange : function(_CurLine, _CurRange)
    {
        return false;
    },

    Check_BreakPageEnd : function(PBChecker)
    {
        return false;
    },

    Get_ParaPosByContentPos : function(ContentPos, Depth)
    {
        var Pos = ContentPos.Get(Depth);

        var CurLine  = 0;
        var CurRange = 0;

        var LinesCount = this.LinesLength;
        for ( ; CurLine < LinesCount; CurLine++ )
        {
            var RangesCount = this.Lines[CurLine].RangesLength;
            for ( CurRange = 0; CurRange < RangesCount; CurRange++ )
            {
                var Range = this.Lines[CurLine].Ranges[CurRange];
                if ( Pos < Range.EndPos && Pos >= Range.StartPos )
                    return new CParaPos( ( CurLine === 0 ? CurRange + this.StartRange : CurRange ), CurLine + this.StartLine, 0, 0 );
            }
        }

        return new CParaPos( ( LinesCount === 1 ? this.Lines[0].RangesLength - 1 + this.StartRange : this.Lines[0].RangesLength - 1 ), LinesCount - 1 + this.StartLine, 0, 0 );
    },

    Recalculate_CurPos : function(_X, Y, CurrentRun, _CurRange, _CurLine, _CurPage, UpdateCurPos, UpdateTarget, ReturnTarget)
    {
        var CurLine  = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

        //var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
        var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;


        var result = {X: _X + this.Root.size.width};


        if ( EndPos >= 1 && CurrentRun == true)
        {
            result = this.Root.Recalculate_CurPos(_X, Y, CurrentRun, _CurRange, _CurLine, _CurPage, UpdateCurPos, UpdateTarget, ReturnTarget);
        }


        return result;
    },

    Refresh_RecalcData : function(Data)
    {
        this.Paragraph.Refresh_RecalcData2(0);
    },
	
    Refresh_RecalcData2 : function(Data)
    {
        this.Paragraph.Refresh_RecalcData2(0);
    },

    Recalculate_MinMaxContentWidth : function(MinMax)
    {
        // TODO: Если формула не измерена, тогда здесь её надо измерить

        if ( false === MinMax.bWord )
        {
            MinMax.bWord    = true;
            MinMax.nWordLen = this.Width;
        }
        else
        {
            MinMax.nWordLen += this.Width;
        }

        if ( MinMax.nSpaceLen > 0 )
        {
            MinMax.nCurMaxWidth += MinMax.nSpaceLen;
            MinMax.nSpaceLen     = 0;
        }

        MinMax.nCurMaxWidth += this.Width;
    },

    Get_Range_VisibleWidth : function(RangeW, _CurLine, _CurRange)
    {
        var CurLine = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

        var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
        var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;

        if ( EndPos >= 1 )
        {
            RangeW.W += this.Width;
        }
    },
    
    Shift_Range : function(Dx, Dy, _CurLine, _CurRange)
    {
        var CurLine = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

        var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
        var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;

        if ( EndPos >= 1 )
        {
            // TODO: Сделать смещение на Dx, Dy
        }        
    },
//-----------------------------------------------------------------------------------
// Функция для работы с формулой
// в тч с  дефолтными текстовыми настройками и argSize
//-----------------------------------------------------------------------------------
    MathToImageConverter: function()
    {
        window.IsShapeToImageConverter = true;

        var dKoef = g_dKoef_mm_to_pix;
        var w_mm = this.Width;
        var h_mm = this.Height;
        var w_px = (w_mm * dKoef) >> 0;
        var h_px = (h_mm * dKoef) >> 0;

        var _canvas = document.createElement('canvas');
        _canvas.width = w_px;
        _canvas.height = h_px;

        var _ctx = _canvas.getContext('2d');

        var g = new CGraphics();
        g.init(_ctx, w_px, h_px, w_mm, h_mm);
        g.m_oFontManager = g_fontManager;

        g.m_oCoordTransform.tx = 0;
        g.m_oCoordTransform.ty = 0;
        g.transform(1,0,0,1,0,0);

        this.Root.draw(0, 0, g);

        window.IsShapeToImageConverter = false;

        var _ret = { ImageNative : _canvas, ImageUrl : "" };
        try
        {
            _ret.ImageUrl = _canvas.toDataURL("image/png");
        }
        catch (err)
        {
            _ret.ImageUrl = "";
        }
        return _ret;
    },
    ApplyArgSize : function(oWPrp, argSize)
    {
        var tPrp = new CTextPr();

        tPrp.Merge(this.DefaultTextPr);
        tPrp.Merge(oWPrp);

        //var FSize = tPrp.FontSize;

        if(argSize == -1)
        {
            //FSize = 0.0009*FSize*FSize + 0.68*FSize + 0.26;
            tPrp.FontSize   = 0.76*tPrp.FontSize;
            tPrp.FontSizeCS = 0.76*tPrp.FontSizeCS;
        }
        else if(argSize == -2)
        {
            //FSize = -0.0004*FSize*FSize + 0.66*FSize + 0.87;
            tPrp.FontSize   = 0.76*0.855*tPrp.FontSize;
            tPrp.FontSizeCS = 0.76*0.855*tPrp.FontSizeCS;
        }

        //tPrp.FontSize = FSize;

        oWPrp.Merge(tPrp);

    },
    /*GetDefaultTxtPrp: function()
    {
        var txtPrp = new CTextPr();

        var defaultTxtPr =
        {
            FontFamily:     {Name  : "Cambria Math", Index : -1 },
            FontSize:       11,
            Italic:         true,
            Bold:           false
        };

       txtPrp.Set_FromObject(defaultTxtPr);

        return txtPrp;
    },*/
    GetFirstRPrp: function()
    {
        return this.Root.getFirstRPrp(this);
    },
    GetShiftCenter: function(oMeasure, font)
    {
        oMeasure.SetFont(font);
        var metrics = oMeasure.Measure2Code(0x2217); // "+"

        return 0.6*metrics.Height;
    },
    SetMathProperties: function(props)
    {
        //*****  FOR FORMULA  *****//

        // В документации везде, где нет примера использования свояства, означает, что Word не поддерживает это свойство !

        if(props.naryLim == NARY_UndOvr || props.naryLim  == NARY_SubSup)
            this.MathPr.naryLim = props.naryLim;

        if(props.intLim == NARY_UndOvr || props.intLim  == NARY_SubSup)
            this.MathPr.intLim = props.intLim;

        if(props.brkBin == BREAK_BEFORE || props.brkBin == BREAK_AFTER || props.brkBin == BREAK_REPEAT)
            this.MathPr.brkBin = props.brkBin;

        // for minus operator
        // when brkBin is set to repeat
        if(props.brkSubBin == BREAK_MIN_MIN || props.brkSubBin == BREAK_PLUS_MIN || props.brkSubBin == BREAK_MIN_PLUS)
            this.MathPr.brkSubBin = props.brkSubBin;

        // в случае если smallFrac = true,
        if(props.smallFrac == true || props.smallFrac == false)
            this.MathPr.smallFrac = props.smallFrac;

        if(props.wrapIndent + 0 == props.wrapIndent && isNaN(props.wrapIndent)) // проверка на число
            this.MathPr.wrapIndent = props.wrapIndent/1440;

        //********  check for element 0x1FFD - 0xA721  *******//
        // This element specifies the right justification of the wrapped line of an instance of mathematical text
        // Instance : Arrows 0x2190-0x21B3, 0x21B6, 0x21B7, 0x21BA-0x21E9, 0x21F4-0x21FF,
        // 0x3D, 0x2234 - 0x2237, 0x2239, 0x223B - 0x228B, 0x228F - 0x2292, 0x22A2 - 0x22B9,
        // 0x22C8-0x22CD, 0x22D0, 0x22D1, 0x22D5 - 0x22EE,0x22F0-0x22FF, 0x27F0 - 0x297F (arrows and fishes), 0x29CE - 0x29D5
        // 0x2A66 - 0x2AF0 (equals), 0x2AF2-0x2AF3, 0x2AF7 - 0x2AFA


        if(props.wrapRight == true || props.wrapRight == false)
            this.MathPr.wrapRight = props.wrapRight;


        //*****  FOR DOCUMENT  *****//

        // defaultJc
        // выравнивание формулы в документе

        this.MathPr.defJc = props.defJc;

        // dispDef
        // свойство: применять/ не применять paragraph settings (в тч defaultJc)

        this.MathPr.dispDef = props.dispDef;

        // added to paragraph settings for margins
        // rMargin
        // lMargin

        this.MathPr.lMargin = props.lMargin;
        this.MathPr.rMargin = props.rMargin;

        //*****  НЕПОДДЕРЖИВАЕМЫЕ Вордом свойства  *****//

        // mathFont: в качестве font поддерживается только Cambria Math
        // остальные шрифты  возможно будут поддержаны MS в будущем

        this.MathPr.mathFont = props.mathFont;

        // Default font for math zones
        // Gives a drop-down list of math fonts that can be used as the default math font to be used in the document.
        // Currently only Cambria Math has thorough math support, but others such as the STIX fonts are coming soon.

        // http://blogs.msdn.com/b/murrays/archive/2008/10/27/default-document-math-properties.aspx


        //*****  FOR FORMULA  *****//

        // http://msdn.microsoft.com/en-us/library/ff529906(v=office.12).aspx
        // Word ignores the interSp attribute and fails to write it back out.
        this.MathPr.interSp = props.interSp;

        // http://msdn.microsoft.com/en-us/library/ff529301(v=office.12).aspx
        // Word does not implement this feature and does not write the intraSp element.
        this.MathPr.intraSp = intraSp;

        //*****  FOR DOCUMENT  *****//

        // http://msdn.microsoft.com/en-us/library/ff533406(v=office.12).aspx
        // Word ignores and discards postSp
        this.MathPr.postSp = props.postSp;
        this.MathPr.preSp = props.preSp;

        // RichEdit Hot Keys
        // http://blogs.msdn.com/b/murrays/archive/2013/10/30/richedit-hot-keys.aspx

    },
    GetMathPr: function()
    {
        return this.MathPr;
    },
    Get_Default_TPrp: function()
    {
        /*var TextPrp = new CTextPr();
        TextPrp.Init_Default();

        var mathFont = new CTextPr();

        var obj =
        {
            FontFamily:     {Name  : "Cambria Math", Index : -1 },
            RFonts:
            {
                Ascii:      {Name  : "Cambria Math", Index : -1 }
            }
        };

        mathFont.Set_FromObject(obj);


        TextPrp.Merge(mathFont);*/


        /*var DefaultPrp =
         {
         FontFamily:     {Name  : "Cambria Math", Index : -1 },
         RFonts:
         {
         Ascii:      {Name  : "Cambria Math", Index : -1 }
         },
         FontSize:       11,
         FontSizeCS:     11,
         Italic:         true,
         Bold:           false
         };

         TextPrp.Set_FromObject(DefaultPrp);*/

        var DefaultTextPrp = this.DefaultTextPr.Copy();
        DefaultTextPrp.Italic = false;

        return DefaultTextPrp;
    },
    Set_Select_ToMComp: function(Direction)
    {
        this.bSelectionUse = true;
        this.Root.Set_Select_ToMComp(Direction);
    },
//-----------------------------------------------------------------------------------
// Функции отрисовки
//-----------------------------------------------------------------------------------
    Draw_HighLights : function(PDSH)
    {
        var CurLine  = PDSH.Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? PDSH.Range - this.StartRange : PDSH.Range );

        var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
        var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;

        if ( EndPos >= 1 )
        {
            PDSH.X += this.Width;
        }
    },

    Draw_Elements : function(PDSE)
    {
        var CurLine  = PDSE.Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? PDSE.Range - this.StartRange : PDSE.Range );

        var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
        var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;

        /*PDSE.Graphics.p_color(255,0,0, 255);
        PDSE.Graphics.drawHorLine(0, PDSE.Y - this.Ascent, PDSE.X - 30, PDSE.X + this.Width + 30 , 1);*/

        if ( EndPos >= 1 )
        {
            //this.Math.Draw( PDSE.X, PDSE.Y, PDSE.Graphics );
            // CMathComposition     =>   this.Root.draw(this.absPos.x, this.absPos.y , pGraphics);
            // this.absPos.x ~> this.X
            // this.absPos.y ~> this.Y

            this.Root.draw( PDSE.X, PDSE.Y - this.Ascent, PDSE.Graphics);

            PDSE.X += this.Width;


        }

        /*PDSE.Graphics.p_color(255,0,0, 255);
        PDSE.Graphics.drawHorLine(0, PDSE.Y - this.Ascent + this.Height, PDSE.X - 30, PDSE.X + this.Width + 30 , 1);*/
    },

    Draw_Lines : function(PDSL)
    {
        var CurLine  = PDSL.Line - this.StartLine;
        var CurRange = ( 0 === CurLine ? PDSL.Range - this.StartRange : PDSL.Range );

        var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
        var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;

        if ( EndPos >= 1 )
        {
            PDSL.X += this.Width;

        }
    },

//-----------------------------------------------------------------------------------
// Функции для работы с курсором
//-----------------------------------------------------------------------------------
    Is_CursorPlaceable : function()
    {
        return true;
    },

    Cursor_Is_Start : function()
    {
        // TODO: ParaMath.Cursor_Is_Start

        return this.Root.Cursor_Is_Start();
    },

    Cursor_Is_NeededCorrectPos : function()
    {
        return false;
    },

    Cursor_Is_End : function()
    {
        // TODO: ParaMath.Cursor_Is_End

        return this.Root.Cursor_Is_End();
    },

    Cursor_MoveToStartPos : function()
    {
        // TODO: ParaMath.Cursor_MoveToStartPos

        this.Root.Cursor_MoveToStartPos();
    },

    Cursor_MoveToEndPos : function(SelectFromEnd)
    {
        // TODO: ParaMath.Cursor_MoveToEndPos

        this.Root.Cursor_MoveToEndPos(SelectFromEnd);
    },

    Get_ParaContentPosByXY : function(SearchPos, Depth, _CurLine, _CurRange, StepEnd, Flag) // получить логическую позицию по XY
    {
        // TODO: ParaMath.Get_ParaContentPosByXY

        var Result = false;

        var CurLine  = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); // если находимся в нулевой строке (для текущей позиции), то CurRange мб ненулевой

        var Range = this.Lines[CurLine].Ranges[CurRange];
        var StartPos = Range.StartPos;  //  0
        var EndPos   = Range.EndPos;    //  this.content.length

        // TODO: реализовать поиск по Y (для случая, когда формула занимает больше одной строки)

        // Проверяем, попали ли мы в формулу

        if ( EndPos >= 1 )
        {
            var Dx = this.Root.size.width;
            var D = SearchPos.X - SearchPos.CurX;

            var CurX = SearchPos.CurX;

            Result = this.Root.Get_ParaContentPosByXY(SearchPos, Depth, _CurLine, _CurRange, StepEnd);

            if ( D >= - 0.001 && D <= Dx + 0.001 )
            {
                SearchPos.DiffX =  0.001;
            }

            SearchPos.CurX = CurX + Dx;
        }


        return Result;
    },

    Get_ParaContentPos : function(bSelection, bStart, ContentPos) // получить текущую логическую позицию
    {
        // TODO: ParaMath.Get_ParaContentPos

        this.Root.Get_ParaContentPos(bSelection, bStart, ContentPos);


        return ContentPos;
    },
    Set_ParaContentPos : function(ContentPos, Depth) // выставить логическую позицию в контенте
    {
        // TODO: ParaMath.Set_ParaContentPos

        //this.State.ContentPos = ContentPos.Get(Depth);

        /*console.log("Set_ParaContentPos");
        var str = "";
        for(var i = 0; i < ContentPos.Data.length; i++)
        {
            str += ContentPos.Data[i] + "  ";
        }

        console.log(str);*/

        //console.log("Set_ParaContentPos");

        this.Root.Set_ParaContentPos(ContentPos, Depth);

    },
    Get_PosByElement : function(Class, ContentPos, Depth, UseRange, Range, Line)
    {
        if ( this === Class )
            return true;

        // TODO: ParaMath.Get_PosByElement
    },

    Get_PosByDrawing : function(Id, ContentPos, Depth)
    {
        return false;
    },

    Get_RunElementByPos : function(ContentPos, Depth)
    {
        return null;
    },

    Get_LastRunInRange : function(_CurLine, _CurRange)
    {
        return null;
    },

    Get_LeftPos : function(SearchPos, ContentPos, Depth, UseContentPos)
    {
        // TODO: ParaMath.Get_LeftPos

        return this.Root.Get_LeftPos(SearchPos, ContentPos, Depth, UseContentPos, false);
    },

    Get_RightPos : function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
    {
        // TODO: ParaMath.Get_RightPos

        return this.Root.Get_RightPos(SearchPos, ContentPos, Depth, UseContentPos, StepEnd, false);
    },

    Get_WordStartPos : function(SearchPos, ContentPos, Depth, UseContentPos)
    {
        // TODO: ParaMath.Get_StartEndPos
        this.Root.Get_WordStartPos(SearchPos, ContentPos, Depth, UseContentPos, false);
    },

    Get_WordEndPos : function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
    {
        // TODO: ParaMath.Get_WordEndPos
        this.Root.Get_WordEndPos(SearchPos, ContentPos, Depth, UseContentPos, StepEnd, false);
    },

    Get_EndRangePos : function(_CurLine, _CurRange, SearchPos, Depth)
    {
        // TODO: ParaMath.Get_EndRangePos

        // Сделать для случая, когда формула будет занимать несколько строк

        return this.Root.Get_EndRangePos(_CurLine, _CurRange, SearchPos, Depth);

    },

    Get_StartRangePos : function(_CurLine, _CurRange, SearchPos, Depth)
    {
        // TODO: ParaMath.Get_StartRangePos

        // Сделать для случая, когда формула будет занимать несколько строк, переделать

        return this.Root.Get_StartRangePos(_CurLine, _CurRange, SearchPos, Depth);
        //this.Root.Get_StartPos(SearchPos.Pos, Depth);

    },

    Get_StartRangePos2 : function(_CurLine, _CurRange, ContentPos, Depth)
    {
        // TODO: ParaMath.Get_StartRangePos2

        // Сделать для случая, когда формула будет занимать несколько строк, переделать

        this.Root.Get_StartRangePos2(_CurLine, _CurRange, ContentPos, Depth);

    },

    Get_StartPos : function(ContentPos, Depth)
    {
        // TODO: ParaMath.Get_StartPos

        this.Root.Get_StartPos(ContentPos, Depth);
    },

    Get_EndPos : function(BehindEnd, ContentPos, Depth)
    {
        // TODO: ParaMath.Get_EndPos
        this.Root.Get_EndPos(BehindEnd, ContentPos, Depth);
    },
//-----------------------------------------------------------------------------------
// Функции для работы с селектом
//-----------------------------------------------------------------------------------
    Set_SelectionContentPos : function(StartContentPos, EndContentPos, Depth, StartFlag, EndFlag)
    {
        // TODO: ParaMath.Set_SelectionContentPos

        //console.log("Set_SelectionContentPos");

        /*if(this.bSelectionUse)
            this.Selection_Remove();*/

        this.Root.Set_SelectionContentPos(StartContentPos, EndContentPos, Depth, StartFlag, EndFlag);
        this.bSelectionUse = true;
    },

    Selection_IsUse : function()
    {
        // TODO: ParaMath.Selection_IsUse
        return this.bSelectionUse;
    },

    Selection_Stop : function()
    {

    },
    Selection_Remove : function()
    {
        // TODO: ParaMath.Selection_Remove

        this.bSelectionUse = false;
        console.log("Selection_Remove");

        this.Root.Selection_Remove();
    },
    Select_All : function(Direction)
    {
        // TODO: ParaMath.Select_All
        this.bSelectionUse = true;
        this.Root.Select_All();
    },

    Selection_DrawRange : function(_CurLine, _CurRange, SelectionDraw)
    {
        var CurLine = _CurLine - this.StartLine;
        var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

        var StartPos = this.Lines[CurLine].Ranges[CurRange].StartPos;
        var EndPos   = this.Lines[CurLine].Ranges[CurRange].EndPos;


        if ( EndPos >= 1 )
        {
            if ( true === this.bSelectionUse )
            {
            // TODO: ParaMath.Selection_Draw_Range

                var result = this.GetSelectContent();

                result.Content.Selection_DrawRange(_CurLine, _CurRange, SelectionDraw);

                /*

                var Start = result.Start,
                    End = result.End,
                    oCont = result.Content;


                SelectionDraw.StartX += oCont.pos.x + oCont.WidthToElement[Start];


                if(Start == End)
                {
                    oCont.content[Start].Selection_DrawRange(_CurLine, _CurRange, SelectionDraw);
                }
                else
                {
                    oCont.content[Start].Selection_DrawRange(_CurLine, _CurRange, SelectionDraw);

                    SelectionDraw.FindStart = false; // выставляем здесь флаг, для того чтобы правильно отрисовался селект для случая пустой ран мат. объект пустой ран
                    SelectionDraw.W += oCont.WidthToElement[End] - oCont.WidthToElement[Start + 1]; // startPos < endPos !

                    oCont.content[End].Selection_DrawRange(_CurLine, _CurRange, SelectionDraw);
                }

                if(!oCont.bRoot)
                {
                    //SelectionDraw.StartY = this.Math.absPos.y + oCont.pos.y; // выставляем так, чтобы для формул с различной высотой в одной строке, всё было ok
                    SelectionDraw.StartY = this.Y + oCont.pos.y; // выставляем так, чтобы для формул с различной высотой в одной строке, всё было ok
                    SelectionDraw.H = oCont.size.height;
                }*/

            }
            else
            {
                if ( true === SelectionDraw.FindStart )
                {
                    SelectionDraw.StartX += this.Width;
                }
            }

        }

    },

    Selection_IsEmpty : function(CheckEnd)
    {
        // TODO: ParaMath.Selection_IsEmpty

        return this.Root.Selection_IsEmpty();
    },
    Selection_IsPlaceholder : function()
    {
        var bPlaceholder = false;
        var result = this.GetSelectContent(),
            SelectContent = result.Content;
        var start = result.Start,
            end = result.End;

        if(start == end)
        {
            bPlaceholder = SelectContent.IsPlaceholder();
        }

        return bPlaceholder;
    },
    Selection_CheckParaEnd : function()
    {
        return false;
    },

    Is_SelectedAll : function(Props)
    {
        // TODO: ParaMath.Is_SelectedAll
        return this.Root.Is_SelectedAll(Props);
    },

    Selection_CorrectLeftPos : function(Direction)
    {
        return false;
    },
//----------------------------------------------------------------------------------------------------------------------
// Функции совместного редактирования
//----------------------------------------------------------------------------------------------------------------------
    Save_Changes : function(Data, Writer)
    {
		Writer.WriteLong( historyitem_type_Math );
    },

    Load_Changes : function(Reader)
    {
				
    },
	Write_ToBinary : function(Writer)
    {
        // Long   : Type
        // String : Id
        Writer.WriteLong( this.Type );
        Writer.WriteString2( this.Id );
    },
	Write_ToBinary2 : function(Writer)
    {
		Writer.WriteLong( historyitem_type_Math );
		Writer.WriteString2( this.Root.Id );
	},

    Read_FromBinary2 : function(Reader)
    {
		var Element = g_oTableId.Get_ById( Reader.GetString2() );
		Element.bRoot = true;
		this.Root = Element;
		
	}
};