"use strict";

/**
 * Created by Ilja.Kirillov on 18.03.14.
 */

var g_dMathArgSizeKoeff_1 = 0.76;
var g_dMathArgSizeKoeff_2 = 0.6498; // 0.76 * 0.855

function CMathPropertiesSettings()
{
    this.brkBin     = null;

    this.defJc      = null;
    this.dispDef    = null;

    this.intLim     = null;

    this.lMargin    = null;

    this.naryLim    = null;

    this.rMargin    = null;

    this.wrapIndent = null;

    //   не реализовано    //
    this.brkBinSub  = null;

    this.interSp    = null;

    this.intraSp    = null;

    this.mathFont   = null;

    this.postSp     = null;
    this.preSp      = null;

    this.smallFrac  = null;

    this.wrapRight  = null;

    //*********************//
}
CMathPropertiesSettings.prototype.SetDefaultPr = function()
{
    this.brkBin     = BREAK_BEFORE;
    this.defJc      = align_Justify;
    this.dispDef    = true;
    this.intLim     = NARY_SubSup;
    this.mathFont   = {Name  : "Cambria Math", Index : -1 };
    this.lMargin    = 0;
    this.naryLim    = NARY_UndOvr;
    this.rMargin    = 0;
    this.wrapIndent = 25; // mm
};
CMathPropertiesSettings.prototype.Merge = function(Pr)
{
    if(Pr.wrapIndent !== null && Pr.wrapIndent !== undefined)
        this.wrapIndent = Pr.wrapIndent;

    if(Pr.lMargin !== null && Pr.lMargin !== undefined)
        this.lMargin = Pr.lMargin;

    if(Pr.rMargin !== null && Pr.rMargin !== undefined)
        this.rMargin = Pr.rMargin;

    if(Pr.intLim !== null && Pr.intLim !== undefined)
        this.intLim = Pr.intLim;

    if(Pr.naryLim !== null && Pr.naryLim !== undefined)
        this.naryLim = Pr.naryLim;

    if(Pr.defJc !== null && Pr.defJc !== undefined)
        this.defJc = Pr.defJc;

    if(Pr.brkBin !== null && Pr.brkBin !== undefined)
        this.brkBin = Pr.brkBin;

    if(Pr.dispDef !== null && Pr.dispDef !== undefined)
        this.dispDef = Pr.dispDef;
	
    if(Pr.mathFont !== null && Pr.mathFont !== undefined)
        this.mathFont = Pr.mathFont;
};

function CMathSettings()
{
    this.Pr        = new CMathPropertiesSettings();
    this.CompiledPr= new CMathPropertiesSettings();
    this.DefaultPr = new CMathPropertiesSettings();

    this.DefaultPr.SetDefaultPr();

    this.bNeedCompile = true;
}
CMathSettings.prototype.SetPr = function(Pr)
{
    this.bNeedCompile = true;
    this.Pr.Merge(Pr);
    this.SetCompiledPr();
};
CMathSettings.prototype.GetPr = function()
{
    return this.Pr;
};
CMathSettings.prototype.SetCompiledPr = function()
{
    if(this.bNeedCompile)
    {
        this.CompiledPr.Merge(this.DefaultPr);
        this.CompiledPr.Merge(this.Pr);

        this.bNeedCompile = false;
    }
};
CMathSettings.prototype.GetPrDispDef = function()
{
    var Pr;
    if(this.CompiledPr.dispDef ==  false)
        Pr = this.DefaultPr;
    else
        Pr = this.CompiledPr;

    return Pr;
};
CMathSettings.prototype.Get_WrapIndent = function(WrapState)
{
    this.SetCompiledPr();

    var wrapIndent = 0;
    if(WrapState == ALIGN_MARGIN_WRAP || WrapState == ALIGN_WRAP)
        wrapIndent = this.GetPrDispDef().wrapIndent;

    return wrapIndent;
};
CMathSettings.prototype.IsWrap = function(WrapState)
{
    return WrapState == ALIGN_MARGIN_WRAP || WrapState == ALIGN_WRAP;
};
CMathSettings.prototype.Get_LeftMargin = function(WrapState)
{
    this.SetCompiledPr();

    var lMargin = 0;
    if(WrapState == ALIGN_MARGIN_WRAP || WrapState == ALIGN_MARGIN)
        lMargin = this.GetPrDispDef().lMargin;

    return lMargin;
};
CMathSettings.prototype.Get_RightMargin = function(WrapState)
{
    this.SetCompiledPr();
    var rMargin    =  0;
    if(WrapState == ALIGN_MARGIN_WRAP || WrapState == ALIGN_MARGIN)
        rMargin = this.GetPrDispDef().rMargin;

    return rMargin;
};
CMathSettings.prototype.Get_IntLim = function()
{
    this.SetCompiledPr();
    return this.CompiledPr.intLim;
};
CMathSettings.prototype.Get_NaryLim = function()
{
    this.SetCompiledPr();
    return this.CompiledPr.naryLim;
};
CMathSettings.prototype.Get_DefJc = function()
{
    this.SetCompiledPr();
    return this.GetPrDispDef().defJc;
};
CMathSettings.prototype.Get_DispDef = function()
{
    this.SetCompiledPr();
    return this.CompiledPr.dispDef;
};
CMathSettings.prototype.Get_BrkBin = function()
{
    this.SetCompiledPr();
    return this.CompiledPr.brkBin;
};

function Get_WordDocumentDefaultMathSettings()
{
    if (!editor)
        return new CMathSettings();

    return editor.WordControl.m_oLogicDocument.Settings.MathSettings;
}

function MathMenu(type)
{
	this.Type = para_Math;
	this.Menu = type;
}
MathMenu.prototype =
{
	Get_Type : function()
    {
        return this.Type;
    }
};

function CMathParametersWidth()
{
    this.Measure = 0;
    this.bMathWordLarge = false;
}

function CParaMathLineWidths()
{
    this.FirstLineOnPage  = -1;
    this.WrapState        = ALIGN_EMPTY;

    this.Widths           = [];

    this.MaxW             = 0; // without first line

    this.bWordLarge       = false;
    this.NeedUpdateWrap   = true;
}
CParaMathLineWidths.prototype.UpdateWidth = function(Line, W)
{
    var bUpdMaxWidth = false;

    if(Line >= this.Widths.length)
    {
        this.Widths[Line] = new CMathParametersWidth();
        this.Widths[Line].Measure = W;
        bUpdMaxWidth = this.UpdateMinMax(Line);
    }
    else if(Math.abs(this.Widths[Line].Measure - W) > 0.00001)
    {
        var lng = this.Widths.length;
        var Max = this.MaxW;

        this.Widths[Line].Measure = W;

        if(lng > 0)
        {
            this.MaxW = this.Widths[0].Measure;

            for(var i = 1; i < lng; i++)
            {
                this.UpdateMinMax(i);
            }
        }

        bUpdMaxWidth = Math.abs(Max - this.MaxW) > 0.0001;
    }

    return bUpdMaxWidth;
};
CParaMathLineWidths.prototype.SetWordLarge = function(Line, bWordLarge)
{
    if(Line >= this.Widths.length)
    {
        this.Widths[Line] = new CMathParametersWidth();
        this.Widths[Line].bMathWordLarge = bWordLarge;

        if(bWordLarge)
            this.bWordLarge = true;
    }
    else
    {
        if(this.Widths[Line].bMathWordLarge !== bWordLarge)
        {
            this.Widths[Line].bMathWordLarge = bWordLarge;

            var Lng = this.Widths.length;

            this.bWordLarge = false;
            for(var Pos = 0; Pos < Lng; Pos++)
            {
                if(this.Widths[Pos].bMathWordLarge == true)
                {
                    this.bWordLarge = true;
                    break;
                }
            }
        }
    }
};
CParaMathLineWidths.prototype.IsLarge = function()
{
    return this.bWordLarge;
};
CParaMathLineWidths.prototype.Get = function(Line)
{
    return this.private_GetW(Line);
};
CParaMathLineWidths.prototype.GetFirst = function()
{
    return this.private_GetW(0);
};
CParaMathLineWidths.prototype.GetMax = function()
{
    return this.MaxW;
};
CParaMathLineWidths.prototype.UpdateMinMax = function(Pos)
{
    var bUpdMaxWidth = false;

    var ItemW = this.Widths[Pos].Measure;

    if(this.MaxW < ItemW)
    {
        this.MaxW = ItemW;
        bUpdMaxWidth = true;
    }

    return bUpdMaxWidth;
};
CParaMathLineWidths.prototype.private_GetW = function(Line)
{
    var W;

    if(Line < this.Widths.length)
        W = this.Widths[Line].Measure;

    return W;
};
CParaMathLineWidths.prototype.GetCountLines = function()
{
    return this.Widths.length;
};
CParaMathLineWidths.prototype.GetNumberLine = function(Line)
{
    return Line - this.FirstLineOnPage;
};

function CMathPageInfo()
{
    this.WPages      = [];          // widths on page
    this.StartLine   = -1;
    this.StartPage   = -1;
    this.CurPage     = -1;
}
CMathPageInfo.prototype.Reset = function()
{
    this.StartLine     = -1;
    this.StartPage     = -1;
    this.CurPage       = -1;
    this.WPages.length =  0;
};
CMathPageInfo.prototype.Reset_Page = function(_Page)
{
    if(this.StartPage >= 0) // если нет, то только начали расчет формулы
    {
        var Page = _Page - this.StartPage;

        if(Page < this.WPages.length) // если нет, то только начали расчет страницы
        {
            // уберем из массива информацию о страницах, начиная с текущей
            // не делаем Reset для текущей страницы, т.к. это приведет к тому, что выставятся только параметры по умолчанию
            // а проверка на стартовую позицию рассчитана именно на длину массива this.WPages
            this.WPages.length = Page;
        }
    }
};
CMathPageInfo.prototype.SetStartPos = function(Page, StartLine)
{
    this.StartPage   = Page;
    this.StartLine   = StartLine;
};
CMathPageInfo.prototype.UpdateCurrentPage = function(Page, ParaLine)
{
    this.CurPage = Page - this.StartPage;

    var Lng = this.WPages.length;
    if(this.CurPage >= Lng)
    {
        var FirstLineOnPage = ParaLine - this.StartLine;

        this.WPages[this.CurPage] = new CParaMathLineWidths();
        this.WPages[this.CurPage].FirstLineOnPage = FirstLineOnPage;
    }
};
CMathPageInfo.prototype.UpdateCurrentWrap = function(DispDef, bInline)
{
    if(this.WPages[this.CurPage].NeedUpdateWrap == true)
    {
        var WrapState;

        if(DispDef == false || bInline == true)
            WrapState = ALIGN_EMPTY;
        else if(this.CurPage == 0)
            WrapState = ALIGN_MARGIN_WRAP;
        else
            WrapState = ALIGN_MARGIN;

        this.WPages[this.CurPage].WrapState = WrapState;
        this.WPages[this.CurPage].NeedUpdateWrap = false;
    }
};
CMathPageInfo.prototype.SetNeedUpdateWrap = function()
{
    this.WPages[this.CurPage].NeedUpdateWrap = true;
};
CMathPageInfo.prototype.SetCurrentWrapState = function(WrapState)
{
    this.WPages[this.CurPage].WrapState = WrapState;
};
CMathPageInfo.prototype.SetNextWrapState = function()
{
    var InfoPage = this.WPages[this.CurPage];

    if(InfoPage.WrapState !== ALIGN_EMPTY)
        InfoPage.WrapState++;
};
CMathPageInfo.prototype.SetStateWordLarge = function(_Line, bWordLarge)
{
    var Line = this.WPages[this.CurPage].GetNumberLine(_Line - this.StartLine);
    this.WPages[this.CurPage].SetWordLarge(Line, bWordLarge);
};
CMathPageInfo.prototype.GetCurrentWrapState = function()
{
    return this.WPages[this.CurPage].WrapState;
};
CMathPageInfo.prototype.GetWrapStateOnPage = function(_Page)
{
    var Page = _Page - this.StartPage;
    return this.WPages[Page].WrapState;
};
CMathPageInfo.prototype.GetCurrentStateWordLarge = function()
{
    return this.WPages[this.CurPage].IsLarge();
};
CMathPageInfo.prototype.GetStartLinetWidth = function()
{
    return this.WPages[0].GetFirst();
};
CMathPageInfo.prototype.UpdateCurrentWidth = function(_Line, Width)
{
    var Line = this.WPages[this.CurPage].GetNumberLine(_Line - this.StartLine);

    return this.WPages[this.CurPage].UpdateWidth(Line, Width);
};
CMathPageInfo.prototype.GetCurrentMaxWidthAllLines = function()
{
    var MaxW = 0;
    if(this.CurPage !== 0)
    {
        MaxW = this.WPages[this.CurPage].GetMax();
    }
    else
    {
        var MaxWOFirst = this.WPages[this.CurPage].GetMax(),
            FirstW     = this.WPages[this.CurPage].GetFirst();

        var MathSettings = Get_WordDocumentDefaultMathSettings(),
            WrapState = this.GetCurrentWrapState();

        var wrapIndent = MathSettings.Get_WrapIndent(WrapState);

        MaxW = FirstW > wrapIndent + MaxWOFirst ? FirstW: MaxWOFirst + wrapIndent;
    }

    return MaxW;
};
CMathPageInfo.prototype.GetMaxW = function(_Page) // without first page
{
    var Page = _Page - this.StartPage;

    return this.WPages[Page].GetMax();
};
CMathPageInfo.prototype.GetFirstLineOnPage = function(_Page)
{
    var FirstLine = null;
    var Page = _Page - this.StartPage;

    if(Page >= 0 && Page < this.WPages.length)
    {
        var FirstLineOnPage = this.WPages[Page].FirstLineOnPage;
        FirstLine = this.StartLine + FirstLineOnPage;
    }

    return FirstLine;
};
CMathPageInfo.prototype.IsResetNextPage = function(_Page)
{
    var bReset = true;

    if(this.CurPage == -1)
    {
        bReset = false;
    }
    else
    {
        var Page = _Page - this.StartPage;
        bReset = this.CurPage < Page;

    }

    return bReset;
};
CMathPageInfo.prototype.IsFirstLineOnPage = function(_Line, _Page)
{
    var bFirstLine = true;

    if(this.StartPage >= 0) // если нет, то только начали расчет формулы
    {
        var Page = _Page - this.StartPage;

        if(Page < this.WPages.length) // если нет, то только начали расчет страницы
        {
            var FirstLine = this.GetFirstLineOnPage(_Page);

            bFirstLine = _Line == FirstLine;
        }
    }

    return bFirstLine;
};


/**
 *
 * @constructor
 * @extends {CParagraphContentWithContentBase}
 */
function ParaMath()
{
    ParaMath.superclass.constructor.call(this);

    this.Id                 = g_oIdCounter.Get_NewId();
    this.Type               = para_Math;

    this.Jc                 = undefined;

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

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

    this.FirstPage          = -1;
    this.PageInfo           = new CMathPageInfo();

    this.ParaMathRPI        = new CMathRecalculateInfo();

    this.bSelectionUse      = false;
    this.Paragraph          = null;
    this.bFastRecalculate   = true;

    this.AbsolutePage       = 0;

    this.NearPosArray       = [];

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

    this.DispositionOpers   = [];

    this.DefaultTextPr     = new CTextPr();

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

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
	g_oTableId.Add( this, this.Id );
}
Asc.extendClass(ParaMath, CParagraphContentWithContentBase);
ParaMath.prototype.Get_Type = function()
{
    return this.Type;
};

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

ParaMath.prototype.Copy = function(Selected)
{
    var NewMath = new ParaMath();
    NewMath.Root.bRoot = true;

    if(Selected)
    {
        var result = this.GetSelectContent();
        result.Content.CopyTo(NewMath.Root, Selected);
    }
    else
    {
        this.Root.CopyTo(NewMath.Root, Selected);
    }

    NewMath.Root.Correct_Content(true);

    return NewMath;
};
ParaMath.prototype.CopyContent = function(Selected)
{
    return [this.Copy(Selected)];
};
ParaMath.prototype.Set_Paragraph = function(Paragraph)
{
    this.Paragraph = Paragraph;
    this.Root.Set_Paragraph(Paragraph);
    this.Root.Set_ParaMath(this, null);
};

ParaMath.prototype.Get_Text = function(Text)
{
    Text.Text = null;
};

ParaMath.prototype.Is_Empty = function()
{
    if (this.Root.Content.length <= 0)
        return true;

    if (1 === this.Root.Content.length)
        return this.Root.Content[0].Is_Empty({SkipPlcHldr : true});

    return false;
};

ParaMath.prototype.Is_CheckingNearestPos = function()
{
    return this.Root.Is_CheckingNearestPos();
};

ParaMath.prototype.Is_StartFromNewLine = function()
{
    return false;
};

ParaMath.prototype.Get_TextPr = function(_ContentPos, Depth)
{
    var TextPr = new CTextPr();

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

    return TextPr;
};
ParaMath.prototype.Get_CompiledTextPr = function(Copy)
{
    var oContent = this.GetSelectContent();
    var mTextPr = oContent.Content.Get_CompiledTextPr(Copy);

    return mTextPr;
};

ParaMath.prototype.Add = function(Item)
{
    var Type = Item.Type;
    var oSelectedContent = this.GetSelectContent();

    var oContent = oSelectedContent.Content;

    var StartPos = oSelectedContent.Start;
    var Run = oContent.Content[StartPos];

    // Мы вставляем только в Run
    if (para_Math_Run !== Run.Type)
        return;

    var NewElement = null;
    if (para_Text === Type)
    {
        // заглушка для текстовых настроек плейсхолдера

        if(oContent.bRoot == false && Run.IsPlaceholder())
        {
            var CtrRunPr = oContent.Get_ParentCtrRunPr(false); // ctrPrp (не копия)
            Run.Apply_TextPr(CtrRunPr, undefined, true);
        }

        if(Item.Value == 38)
        {
            NewElement = new CMathAmp();
            Run.Add(NewElement, true);
        }
        else
        {
            NewElement = new CMathText(false);
            NewElement.add(Item.Value);
            Run.Add(NewElement, true);
        }
    }
    else if (para_Space === Type)
    {
        NewElement = new CMathText(false);
        NewElement.add(32);
        Run.Add(NewElement, true);
    }
    else if (para_Math === Type)
    {
        var ContentPos = new CParagraphContentPos();

        if(this.bSelectionUse == true)
            this.Get_ParaContentPos(true, true, ContentPos);
        else
            this.Get_ParaContentPos(false, false, ContentPos);

        var TextPr = this.Root.GetMathTextPrForMenu(ContentPos, 0);

        // Нам нужно разделить данный Run на 2 части
        var RightRun = Run.Split2(Run.State.ContentPos);

        oContent.Internal_Content_Add(StartPos + 1, RightRun, false);
        // Выставляем позицию в начало этого рана
        oContent.CurPos = StartPos + 1;
        RightRun.Cursor_MoveToStartPos();

        var lng = oContent.Content.length;
        oContent.Load_FromMenu(Item.Menu, this.Paragraph);

        var lng2 = oContent.Content.length;
        var Pos_ApplyTextPr =
        {
            StartPos:   StartPos + 1,
            EndPos:     StartPos + lng2 - lng
        };

        TextPr.RFonts.Set_All("Cambria Math", -1);
        oContent.Apply_TextPr(TextPr, undefined, false, Pos_ApplyTextPr);
        //oContent.Set_MathTextPr2(MathTxtPr.TextPr, MathTxtPr.MathPr, false, StartPos + 1, lng2 - lng);
    }

    if ((para_Text === Type || para_Space === Type) && null !== NewElement)
    {
        this.bFastRecalculate = oContent.bOneLine == false; // многострочный контент => можно осуществлять быстрый пересчет

        // Пробуем произвести автозамену
        oContent.Process_AutoCorrect(NewElement);
    }

    // Корректируем данный контент
    oContent.Correct_Content(true);
};

ParaMath.prototype.Get_AlignToLine = function(_CurLine, _CurRange, _Page, _X, _XLimit)
{
    // отступ первой строки не учитывается для неинлайновых формул
    var X = _X;

    var MathSettings = Get_WordDocumentDefaultMathSettings();

    var AbsolutePage = this.Paragraph == null ? 0 : this.Paragraph.Get_StartPage_Absolute();
    var Page = AbsolutePage + _Page;

    var WrapState = this.PageInfo.GetWrapStateOnPage(Page);
    var bFirstLine = this.Root.IsStartLine(_CurLine);

    // выставим сначала Position до пересчета выравнивания для формулы
    // для расчета смещений относительно операторов

    var PosInfo = new CMathPosInfo();

    PosInfo.CurLine  = _CurLine;
    PosInfo.CurRange = _CurRange;

    if(true == this.NeedDispOperators(_CurLine))
    {
        this.DispositionOpers.length = 0;
        PosInfo.DispositionOpers = this.DispositionOpers;
    }

    var pos   = new CMathPosition();
    this.Root.setPosition(pos, PosInfo);

    var XStart, XEnd;

    if(this.ParaMathRPI.bInline == false)
    {
        XStart = this.ParaMathRPI.XStart;
        XEnd   = this.ParaMathRPI.XEnd;
    }
    else
    {
        XStart = _X;
        XEnd   = _XLimit;
    }

    XStart += MathSettings.Get_LeftMargin(WrapState);
    XEnd   -= MathSettings.Get_RightMargin(WrapState);

    var Jc = this.Get_Align();

    var W = this.PageInfo.GetMaxW(Page);

    var alignBrk = this.Root.GetAlignBrk(_CurLine, _CurRange);
    var DispLng = this.DispositionOpers.length;

    var bAlignAt = WrapState === ALIGN_MARGIN_WRAP && DispLng > 0 && bFirstLine === false && alignBrk > 0;

    if(bFirstLine == true || bAlignAt == true) // первая строка первой страницы, если строка разбивается на несколько отрезков, то это уже будет inline-формула => ф-ия Get_AlignToLine не будет вызвана
    {                                          // bAlignAt == true - учтем выравниевание первой строки + прибавим смещение для alnAt
        var StartLineWidth = this.PageInfo.GetStartLinetWidth(); // если страница не первая, то ширину первой строки формулы не учитываем

        switch(Jc)
        {
            case align_Left:    X = XStart; break;
            case align_Right:   X = Math.max(XEnd - StartLineWidth, XStart); break;
            case align_Center:  X = Math.max(XStart + (XEnd - XStart - StartLineWidth)/2, XStart); break;
            case align_Justify:
            {
                X = Math.max(XStart + (XEnd - XStart - W)/2, XStart);
                break;
            }
        }

        if(bAlignAt == true)
        {
            var PosAln  = alignBrk < DispLng ?  alignBrk -1 : DispLng - 1;
            X += this.DispositionOpers[PosAln];
        }
    }
    else
    {
        var wrap = 0;
        var wrapIndent = MathSettings.Get_WrapIndent(WrapState);

        if(true == MathSettings.IsWrap(WrapState))
        {
            wrap = this.Root.Get_WrapToLine(_CurLine, _CurRange, wrapIndent);
        }

        if(Jc == align_Justify)
        {
            X = XEnd - XStart > W ? XStart + (XEnd - XStart - W)/2 + wrap : XStart;
        }
        else
        {
            X = XEnd - XStart > W ? XStart + wrap : XStart;
        }
    }


    return X;
};

ParaMath.prototype.Remove = function(Direction, bOnAddText)
{
    var TrackRevisions = null;
    if (this.Paragraph && this.Paragraph.LogicDocument)
        TrackRevisions = this.Paragraph.LogicDocument.Is_TrackRevisions();

    var oSelectedContent = this.GetSelectContent();

    var nStartPos = oSelectedContent.Start;
    var nEndPos = oSelectedContent.End;
    var oContent = oSelectedContent.Content;

    if (nStartPos === nEndPos)
    {
        var oElement = oContent.getElem(nStartPos);
        var ElementReviewType = oElement.Get_ReviewType();

        // Если данный элемент - ран, удаляем внутри рана, если нет, тогда удаляем целиком элемент
        if (para_Math_Run === oElement.Type)
        {
            if ((true === oElement.IsPlaceholder()) || (false === oElement.Remove(Direction) && true !== this.bSelectionUse))
            {
                if ((Direction > 0 && oContent.Content.length - 1 === nStartPos) || (Direction < 0 && 0 === nStartPos))
                {
                    // Проверяем находимся ли мы на верхнем уровне
                    if (oContent.bRoot)
                        return false;

                    // Значит мы в каком-то элементе, тогда надо выделить данный элемент
                    oContent.ParentElement.Select_WholeElement();

                    return true;
                }

                if (Direction > 0)
                {
                    var oNextElement = oContent.getElem(nStartPos + 1);
                    if (para_Math_Run === oNextElement.Type)
                    {
                        // Здесь мы не проверяем результат Remove, потому что ран не должен быть пустым после
                        // Correct_Content
                        oNextElement.Cursor_MoveToStartPos();
                        oNextElement.Remove(1);

                        if (oNextElement.Is_Empty())
                        {
                            oContent.Correct_Content();
                            oContent.Correct_ContentPos(1);
                        }

                        this.Selection_Remove();
                    }
                    else
                    {
                        oContent.Select_ElementByPos(nStartPos + 1, true);
                    }
                }
                else //if (Direction < 0)
                {
                    var oPrevElement = oContent.getElem(nStartPos - 1);
                    if (para_Math_Run === oPrevElement.Type)
                    {
                        // Здесь мы не проверяем результат Remove, потому что ран не должен быть пустым после
                        // Correct_Content
                        oPrevElement.Cursor_MoveToEndPos();
                        oPrevElement.Remove(-1);

                        if (oPrevElement.Is_Empty())
                        {
                            oContent.Correct_Content();
                            oContent.Correct_ContentPos(-1);
                        }

                        this.Selection_Remove();
                    }
                    else
                    {
                        oContent.Select_ElementByPos(nStartPos - 1, true);
                    }
                }
            }
            else
            {
                if (oElement.Is_Empty())
                {
                    oContent.CurPos = nStartPos;
                    oContent.Correct_Content();
                    oContent.Correct_ContentPos(-1); // -1, потому что нам надо встать перед элементом, а не после
                }

                this.Selection_Remove();
            }

            return true;
        }
        else
        {
            this.Selection_Remove();
            if (true === TrackRevisions)
            {
                if (reviewtype_Common === ElementReviewType)
                {
                    oElement.Set_ReviewType(reviewtype_Remove);
                }
                else if (reviewtype_Add === ElementReviewType)
                {
                    oContent.Remove_FromContent(nStartPos, 1);
                    if (para_Math_Run === oContent.Content[nStartPos].Type)
                        oContent.Content[nStartPos].Cursor_MoveToStartPos();
                }
            }
            else
            {
                oContent.Remove_FromContent(nStartPos, 1);
                if (para_Math_Run === oContent.Content[nStartPos].Type)
                    oContent.Content[nStartPos].Cursor_MoveToStartPos();
            }
            oContent.CurPos = nStartPos;
            oContent.Correct_Content();
            oContent.Correct_ContentPos(-1); // -1, потому что нам надо встать перед элементом, а не после
        }
    }
    else
    {
        if (nStartPos > nEndPos)
        {
            var nTemp = nEndPos;
            nEndPos = nStartPos;
            nStartPos = nTemp;
        }

        // Проверяем начальный и конечный элементы
        var oStartElement = oContent.getElem(nStartPos);
        var oEndElement = oContent.getElem(nEndPos);

        this.Selection_Remove();
        if (true === TrackRevisions)
        {
            for (var CurPos = nEndPos; CurPos >= nStartPos; --CurPos)
            {
                var Element = oContent.getElem(CurPos);
                var ElementReviewType = Element.Get_ReviewType();

                if (para_Math_Run === Element.Type && (CurPos === nEndPos || CurPos === nStartPos))
                {
                    // Удаление разруливается внутри рана
                    Element.Remove(Direction);
                }
                else
                {
                    if (reviewtype_Common === ElementReviewType)
                    {
                        Element.Set_ReviewType(reviewtype_Remove);
                    }
                    else if (reviewtype_Add === ElementReviewType)
                    {
                        oContent.Remove_FromContent(CurPos, 1);
                        nEndPos--;
                    }
                }
            }

            if (Direction < 0)
            {
                oContent.CurPos = nStartPos;
            }
            else
            {
                oContent.CurPos = nEndPos;
                if (para_Math_Run === oContent.Content[nEndPos].Type)
                    oContent.Content[nEndPos].Cursor_MoveToStartPos();
            }
        }
        else
        {
            // Если последний элемент - ран, удаляем внутри, если нет, тогда удаляем целиком элемент
            if (para_Math_Run === oEndElement.Type)
                oEndElement.Remove(Direction);
            else
                oContent.Remove_FromContent(nEndPos, 1);

            // Удаляем все промежуточные элементы
            oContent.Remove_FromContent(nStartPos + 1, nEndPos - nStartPos - 1);

            // Если первый элемент - ран, удаляем внутри рана, если нет, тогда удаляем целиком элемент
            if (para_Math_Run === oStartElement.Type)
                oStartElement.Remove(Direction);
            else
                oContent.Remove_FromContent(nStartPos, 1);

            oContent.CurPos = nStartPos;
        }
        oContent.Correct_Content();
        oContent.Correct_ContentPos(Direction);
    }
};

ParaMath.prototype.GetSelectContent = function()
{
    return this.Root.GetSelectContent();
};

ParaMath.prototype.Get_CurrentParaPos = function()
{
    return this.Root.Get_CurrentParaPos();
};

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

        var NewTextPr = new CTextPr();
        var bSetInRoot = false;


        if(IncFontSize == undefined)
        {
            if(TextPr.Underline !== undefined)
            {

                NewTextPr.Underline   = TextPr.Underline;
                bSetInRoot            = true;
            }

            if(TextPr.FontSize !== undefined && content.IsNormalTextInRuns() == false)
            {
                NewTextPr.FontSize    = TextPr.FontSize;
                bSetInRoot            = true;

            }

            content.Apply_TextPr(TextPr, IncFontSize, ApplyToAll);

            if(bSetInRoot)
                this.Root.Apply_TextPr(NewTextPr, IncFontSize, true);
        }
        else
        {

            if(content.IsNormalTextInRuns() == false)
                this.Root.Apply_TextPr(TextPr, IncFontSize, true);
            else
                content.Apply_TextPr(TextPr, IncFontSize, ApplyToAll);
        }
    }
};

ParaMath.prototype.Clear_TextPr = function()
{

};

ParaMath.prototype.Check_NearestPos = function(ParaNearPos, Depth)
{
    this.Root.Check_NearestPos(ParaNearPos, Depth);
};

ParaMath.prototype.Get_DrawingObjectRun = function(Id)
{
    return null;
};

ParaMath.prototype.Get_DrawingObjectContentPos = function(Id, ContentPos, Depth)
{
    return false;
};

ParaMath.prototype.Get_Layout = function(DrawingLayout, UseContentPos, ContentPos, Depth)
{
    if (true === UseContentPos)
        DrawingLayout.Layout = true;
    else
        DrawingLayout.X += this.Width;
};

ParaMath.prototype.Get_NextRunElements = function(RunElements, UseContentPos, Depth)
{
};

ParaMath.prototype.Get_PrevRunElements = function(RunElements, UseContentPos, Depth)
{
};

ParaMath.prototype.Collect_DocumentStatistics = function(ParaStats)
{
    // TODO: ParaMath.Collect_DocumentStatistics
};

ParaMath.prototype.Create_FontMap = function(Map)
{
    // Styles.js
    // Document_CreateFontMap

    this.Root.Create_FontMap(Map);
};

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

    this.Root.Get_AllFontNames(AllFonts);
};

ParaMath.prototype.Get_SelectedElementsInfo = function(Info)
{
    Info.Set_Math(this);
};

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

        return "";
    }

    return "";
};

ParaMath.prototype.Get_SelectionDirection = function()
{
    return this.Root.Get_SelectionDirection();
};

ParaMath.prototype.Clear_TextFormatting = function( DefHyper )
{
};

ParaMath.prototype.Can_AddDropCap = function()
{
    return false;
};

ParaMath.prototype.Get_TextForDropCap = function(DropCapText, UseContentPos, ContentPos, Depth)
{
    if ( true === DropCapText.Check )
        DropCapText.Mixed = true;
};

ParaMath.prototype.Get_StartTabsCount = function(TabsCounter)
{
    return false;
};

ParaMath.prototype.Remove_StartTabs = function(TabsCounter)
{
    return false;
};

ParaMath.prototype.Add_ToContent = function(Pos, Item, UpdatePosition)
{

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

ParaMath.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    // Paragraph_Recalculate.js
    // private_RecalculateFastRange

    // Document.js
    // Recalculate
    // SimpleChanges

    // Paragraph.js
    // CRunRecalculateObject.Compare

    if(PRS.bFastRecalculate == true && this.bFastRecalculate == false)
        return;

    if( this.Paragraph !== PRS.Paragraph )
    {
        this.Paragraph = PRS.Paragraph;
        this.protected_UpdateSpellChecking();
    }

    this.AbsolutePage = this.Paragraph == null ? 0 : this.Paragraph.Get_StartPage_Absolute();

    var Para      = PRS.Paragraph;
    var ParaLine  = PRS.Line;
    var ParaRange = PRS.Range;
    var Page      = this.AbsolutePage + PRS.Page;

    var bStartRange    = this.Root.IsStartRange(ParaLine, ParaRange);


    // первый пересчет
    var PrevLineObject = PRS.RestartPageRecalcInfo.Object;
    var bCurrentObj = PrevLineObject == null || PrevLineObject == this;
    var PrevObject = bCurrentObj ? null : PrevLineObject;

    var bStartRecalculate = PrevLineObject == null && true == bStartRange && PRS.bFastRecalculate == false;
    var bContinueRecalc = this.ParaMathRPI.bInline == false && PRS.bContinueRecalc === true;

    var LDRecalcInfo  = this.Paragraph.Parent.RecalcInfo;

    if(bStartRecalculate == true && bContinueRecalc == false) // первый пересчет
    {
        // информация о пересчете
        var RPI = new CRPI();
        RPI.MergeMathInfo(this.ParaMathRPI);
        var ArgSize = new CMathArgSize();

        this.Root.PreRecalc(null, this, ArgSize, RPI);

        this.PageInfo.Reset();
        this.PageInfo.SetStartPos(Page, ParaLine);

        this.ParaMathRPI.Reset(PRS, ParaPr);
    }
    else
    {
        // true == this.PageInfo.IsResetNextPage(Page)
        /// при переходе на следующую страницу выставляем стартовые параметры для отрезка, в к-ом пересчитываем
        // может произойти в одной из 2-х ситуаций:
        // 1. первый раз пересчитываем формулу => для PageInfo ширины и др . параметры еще не рассчитали
        // 2. произошли изменения на пред страницах, их пересчитали, перешли к следующей => для PageInfo нужно выставить дефолтные настройки для параметров и обнулить массив ширин
        // параметры для ParaMathRPI выставляем дефолтные в любом из этих двух случаев

        // false == this.PageInfo.IsResetNextPage(Page) && true == this.PageInfo.IsFirstLineOnPage(Line, Page)
        // т.е. рассчитываем текущую страницу с первой строки
        // может произойти, если вновь стали (PrevLineObject !== null) пересчитывать формулу на данной странице (из-за того что изменилась макс ширина и нужно заново пересчитать формулу на странице и т.п.)
        // или же произошли какие-то изменения на странице и вызвался пересчет для этой страницы (PrevLineObject == null) и отсутствует быстрый пересчет (PRS.bFastRecalculate == false)

        var bResetNextPage = true == this.PageInfo.IsResetNextPage(Page);
        var bResetPageInfo = PrevLineObject == null && bContinueRecalc == false && PRS.bFastRecalculate == false && true == this.PageInfo.IsFirstLineOnPage(ParaLine, Page);

        if(bResetNextPage == true || bResetPageInfo == true)
        {
            this.ParaMathRPI.Reset(PRS, ParaPr);
            this.PageInfo.Reset_Page(Page);
        }
    }

    PRS.MathNotInline = this.ParaMathRPI.bInline  == false; // если неинлайновая формула, то рассчитываем Ranges по максимальному измерению

    if(this.ParaMathRPI.bInline == false)
    {
        PRS.RestartPageRecalcInfo.Object = this; // т.к. this.ParaMathRPI.bInline == false
        // и чтобы на проверке bResetPageInfo не перебить параметры
    }


    // такая сиуация возможна, если разместили формулу под картинкой и нужно заново пересчитать формулу
    // ддля этого меняем PRS.Y и ждем пока не произойдет private_RecalculateLineCheckRangeY
    // т.к. в противном случае мы можем изменить Ranges на те, что находятся PRS.Y, который был до того как его изменили в данном блоке (возникает из-за того, что ф-ия private_RecalculateLineCheckRanges нах-ся выше ф-ии private_RecalculateLineCheckRangeY)
    if(this.ParaMathRPI.ShiftY - PRS.Y > 0 || PRS.bMathRangeY == true)
    {
        // выполняем перенос здесь для того, чтобы перенести под нужную картинку
        // к примеру, у нас есть нескоолько картинок с выравниванием по контору и картинка с выравниванием top_bottom(она расположена ниже всех остальных картинок) =>
        // нужно сделать перенос под картинку top_bottom и пересчитывать заново формулу
        //
        //this.Set_EmptyRange(PRS);
        PRS.bMathRangeY = true;
        PRS.ForceNewPage = true;
        this.private_UpdateRangeY(PRS, this.ParaMathRPI.ShiftY);
    }
    else
    {
        // такая ситуация возможна  когда пришел пересчет заново и кол-во отрезков выравнивания 0 (либо меньше, чем нужно)
        // при этом если это первый Range данной формулы, то пришел еще Reset, то есть пересчитать придется, при этом не меняем max ширину, т.к. если мы уже пересчитали с учетом Range, она не должна поменяться
        this.Root.Set_Paragraph(Para);
        this.Root.Set_ParaMath(this, null);

        this.PageInfo.UpdateCurrentPage(Page, ParaLine);

        var bRecalcNormal = true;

        if(bCurrentObj == true && this.ParaMathRPI.bInline == false &&  PRS.bFastRecalculate == false) // меняем отрезки обтекания только для случая, когда пересчитываем текущий объект (а не вновь возвращаемся к последнему пересчету)
        {
            var UpdWrap = this.private_UpdateWrapSettings(PRS, ParaPr);

            if(UpdWrap == MATH_UPDWRAP_NEWRANGE)
            {
                // Уберем из массива информацию о рассчитанных ширинах, чтобы не учлась рассчитанная ранее максимальная ширина (в связи с тем, что отрезок, в к-ом нужно расположить, изменился по ширине)
                // выставляем EmptyLine = false, т.к. нужно сделать заново пересчет в новом отрезке (а не перенести формулу под картинку)
                // т.к. инициируем пересчет заново, то в проверку на ParaNewLine : if (true === NotInlineMath && true !== PRS.EmptyLine) не зайдем, т.к. NewRange = true
                this.PageInfo.Reset_Page(Page);
                this.ParaMathRPI.bInternalRanges = true;
                // не выставляем EmtyLine = false, т.к. так и так выйдем из пересчета данной строки при расчете Ranges, до пересчета картинок не дойдем, поэтому PRS.EmptyLine = false  выставлять не нужно
                //PRS.EmptyLine = false;
                this.private_SetRestartRecalcInfo(PRS);
            }
            else if(UpdWrap == MATH_UPDWRAP_UNDERFLOW)
            {
                // пересчитаем PRS.Y на след пересчете при this.ParaMathRPI.ShiftY - PRS.Y > 0
                // в блоке if(this.ParaMathRPI.ShiftY - PRS.Y > 0)
            }

            bRecalcNormal = UpdWrap == MATH_UPDWRAP_NOCHANGES; // пересчитываем всю строку заново, т.к. может получиться так, что добавилась еще одна картинка (+ к уже существующим) и нужно заново выбрать Range, в котором необходимо разместить формулу
        }

        if(bRecalcNormal == true) // пересчет в штатном режиме
        {
            var MathSettings = Get_WordDocumentDefaultMathSettings();

            var DispDef = MathSettings.Get_DispDef(),
                bInline = this.Is_Inline(); // учитываем, если формула внутристроковая или же разбивается плавающим объектом (в этом случае тоже нужно рассчитывать как инлайновую)

            //здесь обновляем WrapState, исходя из этого параметра будем считать WrapIndent
            this.PageInfo.UpdateCurrentWrap(DispDef, bInline);


            // формулы не инлайновая, есть Ranges пересчитываем формулу в макс Range => private_RecalculateRangeInsideInterval
            if(this.ParaMathRPI.IntervalState !== MATH_INTERVAL_EMPTY && this.ParaMathRPI.bInternalRanges == true/*this.ParaMathRPI.bStartRanges == true*/) // картинки в другом параграфе и формула пересчитывается с учетом Ranges
            {
                // X и XEnd не перебиваем выше, т.к. они понадобятся для учета попадания в Range в ф-ии  private_RecalculateRangeInsideInterval
                this.private_RecalculateRangeInsideInterval(PRS, ParaPr, Depth);
            }
            else
            {
                this.private_RecalculateRangeWrap(PRS, ParaPr, Depth);
            }

            this.ParaMathRPI.ClearRecalculate();
        }
    }

    // обновляем LDRecalcInfo здесь, т.к. формула - многострочный мат объект, нельзя каждый раз изменять LDRecalcInfo => иначе для четных/нечетных сток будет чередование ParaMath = this/null
    if (PRS.RecalcResult == recalcresult_PrevLine && (true === LDRecalcInfo.Can_RecalcObject() || true === LDRecalcInfo.Check_ParaMath(this)))
    {
        LDRecalcInfo.Set_ParaMath(this);
    }
    else if(true === LDRecalcInfo.Check_ParaMath(this))
    {
        LDRecalcInfo.Reset();
    }
    else
    {

    }

    if(bCurrentObj == true)
    {
        // этот параметр необходим для пересчета нескольких неинлайновых (и инлайновых формул) внутри одного параграфа,
        // чтобы не перетирать параметры внутри пересчитанных формул (и соответственно избежать зацикливания)
        PRS.bContinueRecalc = true;

        if(PRS.NewRange == false)
        {
            // на случай когда у нас несколько неинлайновых формул в одном параграфе
            PRS.RestartPageRecalcInfo.Object = null;
        }
    }
    else
    {
        PRS.RestartPageRecalcInfo.Object = PrevObject; // возвращаем формулу, которая инициировала пересчет (если это была текущая формула, то null)
    }

};
ParaMath.prototype.private_UpdateWrapSettings = function(PRS)
{
    // запомним PRS.Ranges.Y для смещения, чтобы выставить потом смещение, т.к. возможен случай, что картинка, под которой нужно расположить формулу, будет не первой, которая встретиться, пр первом пересчете, или же будет отсутствовать в текущем пересчете
    // (т.к. надо расположить под картинков), отсюда проще запомнить смещение, чем гонять пересчет до конкретной строки, чтобы private_RecalculateLineCheckRangeY вернула нужное значение

    /// значение this.ParaMathRPI.bInternalRanges может изменить значение после того как будет вызвана данная функция

    var UpdateWrap = MATH_UPDWRAP_NOCHANGES;

    var LngR       = PRS.Ranges.length,
        Ranges     = PRS.Ranges;


    if(LngR > 0)
    {
        this.ParaMathRPI.IntervalState = MATH_INTERVAL_ON_SIDE;

        var  RY_NotWrap   = null;

        for(var Pos = 0; Pos < LngR; Pos++)
        {
            var WrapType = Ranges[Pos].typeLeft;

            if(WrapType !== WRAPPING_TYPE_SQUARE && WrapType !== WRAPPING_TYPE_THROUGH && WrapType !== WRAPPING_TYPE_TIGHT)
            {
                // выберем картинку с max RangeY c учетом данного условия, под которой попробуем расположить формулу
                if(RY_NotWrap == null || RY_NotWrap < Ranges[Pos].Y1)
                {
                    RY_NotWrap = Ranges[Pos].Y1;
                }

                this.ParaMathRPI.IntervalState = MATH_INTERVAL_EMPTY;
            }
        }

        if(this.ParaMathRPI.IntervalState == MATH_INTERVAL_ON_SIDE) // WrapType == WRAPPING_TYPE_SQUARE || WrapType == WRAPPING_TYPE_THROUGH || WrapType == WRAPPING_TYPE_TIGHT
        {
            // вычтем здесь Ind.Left для корректного сравнения (т.к.стартовый отрезок = граница Range + Ind.Left ), а также если XStart окажется левой границей (прибаится лишний Ind.Left)
            var XRange = this.ParaMathRPI.XRange - this.ParaMathRPI.IndLeft,
                XLimit = this.ParaMathRPI.XLimit;

            // рассчитываем XStart, XEnd
            var XStart = XRange,
                XEnd   = Ranges[0].X0;

            for(var Pos = 0; Pos < LngR - 1; Pos++)
            {
                if(XEnd - XStart < Ranges[Pos+1].X0 - Ranges[Pos].X1)
                {
                    XStart = Ranges[Pos].X1;
                    XEnd   = Ranges[Pos+1].X0;
                }
            }

            if(XEnd - XStart < XLimit - Ranges[LngR - 1].X1)
            {
                XStart = Ranges[LngR - 1].X1;
                XEnd   = XLimit;
            }

            // учтем Ind.Left
            // если впоследствии Ind.Left в word не будет учитываться, то нужно пересмотреть схему => в каких случаях и с какими параметрами рассчитыывать в Range

            XStart += this.ParaMathRPI.IndLeft;


            // в конце сравним с текущим отрезком, т.к. может произойти например след ситуация :
            // 2 плавающих объекта находятся в различных строках +> PRS.Ranges.length <=1
            // при этом формула должна расположится в макс по ширине из отрезков, образованными обоими плавающими мат объектами

            // учтем предыдущие отрезки:
            if(this.ParaMathRPI.XStart > XStart)
            {
                XStart = this.ParaMathRPI.XStart;
            }

            if(this.ParaMathRPI.XEnd < XEnd)
            {
                XEnd = this.ParaMathRPI.XEnd;
            }

            // рассчитываем RangeY

            var RangeY = Ranges[0].Y1;

            for(var Pos = 1; Pos < Ranges.length; Pos++)
            {
                if(Ranges[Pos].Y1 < RangeY)
                    RangeY = Ranges[Pos].Y1;
            }

            if(this.ParaMathRPI.RangeY == null || RangeY < this.ParaMathRPI.RangeY)
            {
                this.ParaMathRPI.RangeY = RangeY;
            }


            var DiffXStart = Math.abs(this.ParaMathRPI.XStart - XStart),
                DiffXEnd   = Math.abs(this.ParaMathRPI.XEnd - XEnd);

            if(DiffXStart > 0.001 || DiffXEnd > 0.001)
            {
                this.ParaMathRPI.XStart     = XStart;
                this.ParaMathRPI.XEnd       = XEnd;

                UpdateWrap = MATH_UPDWRAP_NEWRANGE;
            }
        }
        else
        {
            // если появился плавающий объект, относительно которого нельзя разместить формулу (в одном из Range, образованным плавающими объектами), то, соответсвенно, формула должна располагаться под плавающим объектом

            this.private_SetShiftY(PRS, RY_NotWrap);
            UpdateWrap = MATH_UPDWRAP_UNDERFLOW;
        }

    }

    return UpdateWrap;
};
ParaMath.prototype.private_RecalculateRangeInsideInterval = function(PRS, ParaPr, Depth)
{
    // var bInsideRange = PRS.X - 0.001 < this.ParaMathRPI.XStart && this.ParaMathRPI.XEnd < PRS.XEnd + 0.001;
    // наложим менее строгие условия попадания в отрезок
    var bNotInsideRange = this.ParaMathRPI.XStart > PRS.XEnd || this.ParaMathRPI.XEnd < PRS.X;
    var bNextRangeSide   = this.ParaMathRPI.IntervalState == MATH_INTERVAL_ON_SIDE && bNotInsideRange == true; // пересчитываем только в том отрезке, в котором находится формула

    // Номер  Range не влияет на UpdateWrapSettings, т.к. картинки могут располагаться одна под другой, и в одной ситуации это будет 0-ой Range,  в другой 1-ый

    if(bNextRangeSide) // при пересчете формулы между картинками/сбоку от картинки рассчитываем формулу в самом большом Range, остальные делаем пустыми
    {
        // переход к следующему Range
        this.Set_EmptyRange(PRS);
    }
    else
    {
        PRS.X = this.ParaMathRPI.XStart;
        PRS.XEnd = this.ParaMathRPI.XEnd;

        this.private_UpdateXLimits(PRS);

        this.private_RecalculateRoot(PRS, ParaPr, Depth);


        if(PRS.bMathWordLarge == true)
        {
            this.private_SetShiftY(PRS, this.ParaMathRPI.RangeY);
        }
        else if(PRS.NewRange == false && PRS.EmptyLine == true) // формула пересчиталась корректно, располагаем в данной строке => не разбивается на слова, выставим EmptyLine = false, чтобы не перенесли под картинку
        {
            PRS.EmptyLine = false;
        }

        PRS.RestartPageRecalcInfo.Object = this;

        if(PRS.NewRange == true && PRS.RecalcResult !== recalcresult_PrevLine)
            PRS.ForceNewLine = true;
    }
};
ParaMath.prototype.private_RecalculateRangeWrap = function(PRS, ParaPr, Depth)
{
    // попадем сюда только, когда  либо нет плавающих объектов, привязанных к другому параграфу, нежели формула
    // либо когда не получилось расположить формулу в Range и формула пересчитывается обычным образом

    var PrevLineObject = PRS.RestartPageRecalcInfo.Object;

    if(PrevLineObject == null ||  PrevLineObject == this)
    {
        PRS.RecalcResult = recalcresult_NextLine;
        //PRS.Reset_RestartPageRecalcInfo();
        // не вызываем функцию Reset_RestartPageRecalcInfo, т.к. в данной функции учитывается флаг, что начали пересчитывать заново
        PRS.RestartPageRecalcInfo.Line   = 0;
        // выставляем только для инлайновых формул => может случится так, что в одном параграфе окажутся несколько формул и для того, чтобы при первом пересчете пересчитались настройки нужно возвращать null
        // при последующих пересчетах PRS.RestartPageRecalcInfo.Object будет выставлен null на Reset_RestartPageRecalcInfo в ф-ии private_RecalculatePage

        PRS.RestartPageRecalcInfo.Object = this.ParaMathRPI.bInline ? null : this;
    }

    if(this.ParaMathRPI.bInline == false)  // здесь перебивается для неинлайновых формул и отступ первой строки и тот случай, когда формула не пересекает область расположения картинки (FlowBounds), но тем неменее пришли
    {
        PRS.X = this.ParaMathRPI.XStart;
        PRS.XEnd = this.ParaMathRPI.XEnd;
    }

    this.private_UpdateXLimits(PRS);

    var bStartRange    = this.Root.IsStartRange(PRS.Line, PRS.Range);
    var bNotBrPosInLWord = this.ParaMathRPI.bInline == true && bStartRange == true && PRS.Ranges.length > 0 && PRS.Word == true;
    PRS.bBreakPosInLWord = bNotBrPosInLWord == false;  //не обновляем для инлайновой формулы, когда WordLarge (слово вышло за границы Range), перед формулой есть еще текст, чтобы не перебить LineBreakPos и выставить разбиение по тем меткам, которые были до пересчета формулы

    var bEmptyLine = PRS.EmptyLine;

    this.private_RecalculateRoot(PRS, ParaPr, Depth);

    var WrapState = this.PageInfo.GetCurrentWrapState();
    var bWordLarge =  PRS.bMathWordLarge == true && WrapState == ALIGN_EMPTY;
    this.PageInfo.SetStateWordLarge(PRS.Line, bWordLarge);

    if(PRS.bMathWordLarge == true)
    {
        if(WrapState !== ALIGN_EMPTY)
        {
            this.private_SetRestartRecalcInfo(PRS);
            this.PageInfo.SetNextWrapState();
        }
        else if(this.ParaMathRPI.bInline == true && PRS.Ranges.length > 0)
        {
            if(PRS.bBreakPosInLWord == true) // когда для инлайновой формулы WordLarge (слово вышло за границы Range), перед формулой есть еще текст, чтобы не перебить LineBreakPos и выставить разбиение по тем меткам, которые были до пересчета формулы
            {
                PRS.EmptyLine = bEmptyLine; // вернем пред знач-е
                this.Root.Math_Set_EmptyRange(PRS.Line, PRS.Range);
                PRS.bMathWordLarge = false;
                PRS.NewRange = true;
                PRS.MoveToLBP = false;
            }
            else
            {
                //не обновляем для инлайновой формулы, когда WordLarge, перед формулой есть еще текст, чтобы не перебить LineBreakPos и выставить по тем меткам, которые были до формулы разбиение
                PRS.MoveToLBP = true;
            }
        }
    }
};
ParaMath.prototype.private_RecalculateRoot = function(PRS, ParaPr, Depth)
{
    var Para      = PRS.Paragraph;
    var ParaLine  = PRS.Line;
    var ParaRange = PRS.Range;

    // заглушка для пересчета Gaps элементов в текущей строке
    // если быстрый пересчет проверим нужно ли пересчитывать gaps у элементов текущей строки
    if(PRS.bFastRecalculate == true)
    {
        this.Root.Math_UpdateGaps(ParaLine, ParaRange);
    }

    this.Root.Recalculate_Range(PRS, ParaPr, Depth);

    if(PRS.NewRange == false)
    {
        // обнуляем GapRight для операторов
        PRS.OperGapRight       = 0;

        var WidthLine = PRS.X - PRS.XRange + PRS.SpaceLen + PRS.WordLen;

        var bFirstItem =  PRS.FirstItemOnLine == true && true === Para.Internal_Check_Ranges(ParaLine, ParaRange);
        if(bFirstItem && PRS.X + PRS.SpaceLen + PRS.WordLen > PRS.XEnd)
        {
            PRS.bMathWordLarge = true;
        }

        this.UpdateWidthLine(PRS, WidthLine);
    }
};
ParaMath.prototype.private_SetRestartRecalcInfo = function(PRS)
{
    var Page = this.AbsolutePage + PRS.Page;
    var Line = this.PageInfo.GetFirstLineOnPage(Page);
    PRS.Set_RestartPageRecalcInfo(Line, this);
    PRS.RecalcResult = recalcresult_PrevLine;
    PRS.NewRange = true;
};
ParaMath.prototype.Set_EmptyRange = function(PRS)
{
    // не выставляем PRS.EmptyLine = false, чтобы корректно не произошел перенос на след строку для ParaNewLine (PRS.EmptyLine == false && bInline == false)

    this.Root.Math_Set_EmptyRange(PRS.Line, PRS.Range);

    PRS.RecalcResult = recalcresult_NextLine;
    PRS.RestartPageRecalcInfo.Object = this;

    PRS.NewRange = true;
};
ParaMath.prototype.private_UpdateRangeY = function(PRS, RY)
{
    if (Math.abs(RY - PRS.Y) < 0.001)
        PRS.Y = RY + 1; // смещаемся по 1мм
    else
        PRS.Y = RY + 0.001; // Добавляем 0.001, чтобы избавиться от погрешности


    PRS.NewRange = true;
};
ParaMath.prototype.private_SetShiftY = function(PRS, RY)
{
    this.PageInfo.SetNeedUpdateWrap();
    this.ParaMathRPI.UpdateShiftY(RY);
    this.ParaMathRPI.Reset_WrapSettings();
    this.private_SetRestartRecalcInfo(PRS);
};
ParaMath.prototype.private_UpdateXLimits = function(PRS)
{
    var MathSettings = Get_WordDocumentDefaultMathSettings();

    var WrapState = this.PageInfo.GetCurrentWrapState();

    PRS.X    += MathSettings.Get_LeftMargin(WrapState);
    PRS.XEnd -= MathSettings.Get_RightMargin(WrapState);


    PRS.WrapIndent = MathSettings.Get_WrapIndent(WrapState);
    PRS.bPriorityOper = this.ParaMathRPI.bInline == false;

    var bFirstLine = this.Root.IsStartLine(PRS.Line);
    PRS.bFirstLine = bFirstLine;

    if(bFirstLine == false && true == MathSettings.IsWrap(WrapState))
    {
        PRS.X += this.Root.Get_WrapToLine(PRS.Line, PRS.Range, PRS.WrapIndent);
    }

    PRS.XRange = PRS.X;
};
ParaMath.prototype.Save_MathInfo = function(Copy)
{
    var RecalculateObject = new CMathRecalculateObject();

    var StructRecalc =
    {
        bFastRecalculate:   this.bFastRecalculate,
        PageInfo:           this.PageInfo,
        bInline:            this.ParaMathRPI.bInline,
        Align:              this.Get_Align(),
        bEmptyFirstRange:   this.Root.Is_EmptyRange(this.Root.StartLine, this.Root.StartRange)
    };

    RecalculateObject.Fill(StructRecalc);

    return RecalculateObject;
};
ParaMath.prototype.Load_MathInfo = function(RecalculateObject)
{
    RecalculateObject.Load_MathInfo(this.PageInfo);
};
ParaMath.prototype.CompareMathInfo = function(RecalculateObject)
{
    return RecalculateObject.Compare(this.PageInfo);
};
ParaMath.prototype.Recalculate_Reset = function(CurRange, CurLine, RecalcResult)
{
    this.Root.Recalculate_Reset(CurRange, CurLine); // обновим StartLine и StartRange только для Root (в CParagraphContentWithContentBase), для внутренних элементов обновится на Recalculate_Range
};
ParaMath.prototype.Recalculate_Set_RangeEndPos = function(PRS, PRP, Depth)
{
    this.Root.Recalculate_Set_RangeEndPos(PRS, PRP, Depth);
};
ParaMath.prototype.Recalculate_LineMetrics = function(PRS, ParaPr, _CurLine, _CurRange)
{
    var ContentMetrics = new CMathBoundsMeasures();

    // обновляем LineAscent и LineDescent для пересчета инлайновой формулы с картинкой
    // если в формуле находится картинка, то может так получится, что в отрезках обтекания не будет ни одного элемента => PRS.Ascent и PRS.Descent равны 0
    // далее при вычилении отрезков (PRS.Ranges) для следующей строки  учитываются PRS.Ascent и PRS.Descent предыдщей строки, а они будут равны 0 , соответственно получим те же самые отрезки обтекания, что и в предыдущей строке
    // произойдет зацикливание

    this.Root.Recalculate_LineMetrics(PRS, ParaPr, _CurLine, _CurRange, ContentMetrics);

    var RootAscent  = this.Root.GetAscent(_CurLine, _CurRange),
        RootDescent = this.Root.GetDescent(_CurLine, _CurRange);


    if(PRS.LineAscent < RootAscent)
        PRS.LineAscent = RootAscent;

    if(PRS.LineDescent < RootDescent)
        PRS.LineDescent = RootDescent;

};
ParaMath.prototype.Recalculate_Range_Width = function(PRSC, _CurLine, _CurRange)
{
    var SpaceLen   = PRSC.SpaceLen;

    var bBrkBefore = this.Is_BrkBinBefore();

    var bGapLeft  = bBrkBefore == true,
        bGapRight = bBrkBefore == false;

    this.Root.UpdateOperators(_CurLine, _CurRange, bGapLeft, bGapRight);

    this.Root.Recalculate_Range_Width(PRSC, _CurLine, _CurRange);

    PRSC.Range.W        += PRSC.SpaceLen - SpaceLen;
    PRSC.Range.SpaceLen = SpaceLen;

    PRSC.Words++;
};
ParaMath.prototype.UpdateWidthLine = function(PRS, Width)
{
    var PrevRecalcObject = PRS.RestartPageRecalcInfo.Object;

    if(PrevRecalcObject == null || PrevRecalcObject == this)
    {
        var MathSettings = Get_WordDocumentDefaultMathSettings(),
            Page = this.AbsolutePage + PRS.Page;

        var WrapState = this.PageInfo.GetWrapStateOnPage(Page), // если впоследствии State будет изменен, то пересчитаем с первой строки текущей страницы
            WrapIndent = MathSettings.Get_WrapIndent(WrapState);

        var wrap = PRS.Page == 0 ? this.Root.Get_WrapToLine(PRS.Line, PRS.Range, WrapIndent) : 0;
        var W = Width - PRS.OperGapRight - PRS.OperGapLeft + wrap;

        var bChangeMaxW = this.PageInfo.UpdateCurrentWidth(PRS.Line, W);

        if(bChangeMaxW == true && this.Is_Inline() == false && align_Justify == this.Get_Align())
        {
            var Line = this.PageInfo.GetFirstLineOnPage(Page);
            PRS.Set_RestartPageRecalcInfo(Line, this);
            PRS.RecalcResult = recalcresult_PrevLine;
            PRS.NewRange = true;
        }
    }
};
ParaMath.prototype.Recalculate_Range_Spaces = function(PRSA, _CurLine, _CurRange, _CurPage)
{
    // до пересчета Bounds для текущей строки ранее должны быть вызваны Recalculate_Range_Width (для ширины), Recalculate_LineMetrics(для высоты и аскента)

    //var Page = 0;
    //if ( this.Paragraph !== null)
        //Page = this.Paragraph.Get_StartPage_Absolute();

    // для инлайновой формулы не вызывается ф-ия setPosition, поэтому необходимо вызвать здесь
    // для неилайновой setPosition вызывается на Get_AlignToLine

    var PosInfo = new CMathPosInfo();

    PosInfo.CurLine  = _CurLine;
    PosInfo.CurRange = _CurRange;

    var pos   = new CMathPosition();
    this.Root.setPosition(pos, PosInfo);

    // страиницу для смещния параграфа относительно документа добавим на Get_Bounds, т.к. если формула находится в автофигуре, то для нее не прийдет Recalculate_Range_Spaces при перемещении автофигуры а другую страницу

    this.Root.UpdateBoundsPosInfo(PRSA, _CurLine, _CurRange, _CurPage);

    this.Root.Recalculate_Range_Spaces(PRSA, _CurLine, _CurRange, _CurPage);
};
ParaMath.prototype.Recalculate_PageEndInfo = function(PRSI, _CurLine, _CurRange)
{

};
ParaMath.prototype.Save_RecalculateObject = function(Copy)
{
    var RecalcObj = this.Root.Save_RecalculateObject(Copy);
    RecalcObj.Save_MathInfo(this, Copy);

    return RecalcObj;
};
ParaMath.prototype.Load_RecalculateObject = function(RecalcObj)
{
    RecalcObj.Load_MathInfo(this);
    this.Root.Load_RecalculateObject(RecalcObj);
};
ParaMath.prototype.Prepare_RecalculateObject = function()
{
    this.Root.Prepare_RecalculateObject();
};
ParaMath.prototype.Is_EmptyRange = function(_CurLine, _CurRange)
{
    return this.Root.Is_EmptyRange(_CurLine, _CurRange);
};
ParaMath.prototype.Check_Range_OnlyMath = function(Checker, CurRange, CurLine)
{
    if (null !== Checker.Math)
    {
        Checker.Math   = null;
        Checker.Result = false;
    }
    else
        Checker.Math = this;
};

ParaMath.prototype.Check_MathPara = function(Checker)
{
    Checker.Found  = true;
    Checker.Result = false;
};

ParaMath.prototype.Check_PageBreak = function()
{
    return false;
};

ParaMath.prototype.Check_BreakPageEnd = function(PBChecker)
{
    return false;
};
ParaMath.prototype.Get_ParaPosByContentPos = function(ContentPos, Depth)
{
    return this.Root.Get_ParaPosByContentPos(ContentPos, Depth);
};

ParaMath.prototype.Recalculate_CurPos = function(_X, Y, CurrentRun, _CurRange, _CurLine, _CurPage, UpdateCurPos, UpdateTarget, ReturnTarget)
{
    return this.Root.Recalculate_CurPos(_X, Y, CurrentRun, _CurRange, _CurLine, _CurPage, UpdateCurPos, UpdateTarget, ReturnTarget);
};

ParaMath.prototype.Refresh_RecalcData = function(Data)
{
    this.Paragraph.Refresh_RecalcData2(0);
};

ParaMath.prototype.Refresh_RecalcData2 = function(Data)
{
    this.Paragraph.Refresh_RecalcData2(0);
};

ParaMath.prototype.Recalculate_MinMaxContentWidth = function(MinMax)
{
    var RPI = new CRPI();
    RPI.MergeMathInfo(this.ParaMathRPI);
    var ArgSize = new CMathArgSize();

    this.Root.PreRecalc(null, this, ArgSize, RPI);
    this.Root.Recalculate_MinMaxContentWidth(MinMax);
};

ParaMath.prototype.Get_Range_VisibleWidth = function(RangeW, _CurLine, _CurRange)
{
    this.Root.Get_Range_VisibleWidth(RangeW, _CurLine, _CurRange);
};
ParaMath.prototype.Is_BrkBinBefore = function()
{
    var MathSettings = Get_WordDocumentDefaultMathSettings();

    return this.Is_Inline() ? false : MathSettings.Get_BrkBin() == BREAK_BEFORE;
};
ParaMath.prototype.Shift_Range = function(Dx, Dy, _CurLine, _CurRange)
{
    this.Root.Shift_Range(Dx, Dy, _CurLine, _CurRange);
    var CurrentAbsolutePage = this.Paragraph.Get_StartPage_Absolute();

    if(this.Paragraph !== null && this.AbsolutePage !== CurrentAbsolutePage)
    {
        this.Root.ShiftPage(CurrentAbsolutePage - this.AbsolutePage);
        this.AbsolutePage = CurrentAbsolutePage;
    }
};
//-----------------------------------------------------------------------------------
// Функция для работы с формулой
// в тч с  дефолтными текстовыми настройками и argSize
//-----------------------------------------------------------------------------------
ParaMath.prototype.Set_Inline = function(value)
{
    if(value !== this.ParaMathRPI.bInline)
    {
        this.ParaMathRPI.bChangeInline = true;
        this.ParaMathRPI.bInline = value;
        this.bFastRecalculate = false;          // после смены инлайновости, требуется полностью пересчитать формулу
    }
};
ParaMath.prototype.Get_Inline = function()
{
    return this.ParaMathRPI.bInline;
};
ParaMath.prototype.Is_Inline = function()
{
    return this.ParaMathRPI.bInline == true /*|| (this.ParaMathRPI.bInternalRanges == true && this.ParaMathRPI.bStartRanges == false)*/;
};
ParaMath.prototype.NeedDispOperators = function(Line)
{
    return false === this.Is_Inline() &&  true == this.Root.IsStartLine(Line);
};
ParaMath.prototype.Get_Align = function()
{
    var Jc;
    if(this.ParaMathRPI.bInline)
    {
        var ParaPr = this.Paragraph.Get_CompiledPr2(false).ParaPr;
        Jc = ParaPr.Jc;
    }
    else if (undefined !== this.Jc)
    {
        Jc = this.Jc;
    }
    else
    {
        var MathSettings = Get_WordDocumentDefaultMathSettings();

        Jc = MathSettings.Get_DefJc();
    }

    return Jc;
};
ParaMath.prototype.Set_Align = function(Align)
{
    if (this.Jc !== Align)
    {
        History.Add(this, new CChangesMathParaJc(Align, this.Jc));
        this.raw_SetAlign(Align);
    }
};
ParaMath.prototype.raw_SetAlign = function(Align)
{
    this.Jc = Align;
};
ParaMath.prototype.SetRecalcCtrPrp = function(Class)
{
    if(this.Root.Content.length > 0 && this.ParaMathRPI.bRecalcCtrPrp == false)
    {
        this.ParaMathRPI.bRecalcCtrPrp = this.Root.Content[0] == Class;
    }
};
ParaMath.prototype.MathToImageConverter = function(bCopy, _canvasInput, _widthPx, _heightPx, raster_koef)
{
    var bTurnOnId = false;
    if (false === g_oTableId.m_bTurnOff)
    {
        g_oTableId.m_bTurnOff = true;
        bTurnOnId = true;
    }

	History.TurnOff();

    var oldDefTabStop = Default_Tab_Stop;
    Default_Tab_Stop = 1;

    var hdr = new CHeaderFooter(editor.WordControl.m_oLogicDocument.HdrFtr, editor.WordControl.m_oLogicDocument, editor.WordControl.m_oDrawingDocument, hdrftr_Header);
    var _dc = hdr.Content;

    var par = new Paragraph(editor.WordControl.m_oDrawingDocument, _dc, 0, 0, 0, 0, false);

    if (bCopy)
        par.Internal_Content_Add(0, this.Copy(false), false);
    else
        par.Internal_Content_Add(0, this, false);

    _dc.Internal_Content_Add(0, par, false);

    par.Set_Align(align_Left);
    par.Set_Tabs(new CParaTabs());

    var _ind = new CParaInd();
    _ind.FirstLine = 0;
    _ind.Left = 0;
    _ind.Right = 0;
    par.Set_Ind(_ind, false);

    var _sp = new CParaSpacing();
    _sp.Line              = 1;
    _sp.LineRule          = linerule_Auto;
    _sp.Before            = 0;
    _sp.BeforeAutoSpacing = false;
    _sp.After             = 0;
    _sp.AfterAutoSpacing  = false;
    par.Set_Spacing(_sp, false);

    _dc.Reset(0, 0, 10000, 10000);
    _dc.Recalculate_Page(0, true);

    _dc.Reset(0, 0, par.Lines[0].Ranges[0].W + 0.001, 10000);
    _dc.Recalculate_Page(0, true);

    Default_Tab_Stop = oldDefTabStop;

    if (true === bTurnOnId)
        g_oTableId.m_bTurnOff = false;

    History.TurnOn();

    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;

    if (undefined !== raster_koef)
    {
        w_px *= raster_koef;
        h_px *= raster_koef;

        if (undefined !== _widthPx)
            _widthPx *= raster_koef;
        if (undefined !== _heightPx)
            _heightPx *= raster_koef;
    }

    var _canvas = (_canvasInput === undefined) ? document.createElement('canvas') : _canvasInput;

    _canvas.width   = (undefined == _widthPx) ? w_px : _widthPx;
    _canvas.height  = (undefined == _heightPx) ? h_px : _heightPx;

    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;

    if (_widthPx !== undefined && _heightPx !== undefined)
    {
        g.m_oCoordTransform.tx = (_widthPx - w_px) / 2;
        g.m_oCoordTransform.ty = (_heightPx - h_px) / 2;
    }

    g.transform(1,0,0,1,0,0);

    par.Draw(0, g);

    window.IsShapeToImageConverter = false;

    if (undefined === _canvasInput)
    {
        var _ret = { ImageNative: _canvas, ImageUrl: "" };
        try
        {
            _ret.ImageUrl = _canvas.toDataURL("image/png");
        }
        catch (err)
        {
            _ret.ImageUrl = "";
        }
        return _ret;
    }
    return null;
};
ParaMath.prototype.Get_FirstTextPr = function()
{
    return this.Root.Get_FirstTextPr();
};
ParaMath.prototype.GetFirstRPrp = function()
{
    return this.Root.getFirstRPrp();
};
ParaMath.prototype.GetShiftCenter = function(oMeasure, font)
{
    oMeasure.SetFont(font);
    var metrics = oMeasure.Measure2Code(0x2217); // "+"

    return 0.6*metrics.Height;
};
ParaMath.prototype.GetPlh = function(oMeasure, font)
{
    oMeasure.SetFont(font);

    return oMeasure.Measure2Code(0x2B1A).Height;
};
ParaMath.prototype.GetA = function(oMeasure, font)
{
    oMeasure.SetFont(font);

    return oMeasure.Measure2Code(0x61).Height;
};

ParaMath.prototype.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

};

ParaMath.prototype.GetMathPr = function()
{
    return this.MathPr;
};

ParaMath.prototype.Get_Default_TPrp = function()
{
    return this.DefaultTextPr;
};
//-----------------------------------------------------------------------------------
// Функции отрисовки
//-----------------------------------------------------------------------------------
ParaMath.prototype.Draw_HighLights = function(PDSH)
{
    if(false == this.Root.IsEmptyRange(PDSH.Line, PDSH.Range))
    {
        var X  = PDSH.X;
        var Y0 = PDSH.Y0;
        var Y1 = PDSH.Y1;

        var Comm = PDSH.Save_Comm();
        var Coll = PDSH.Save_Coll();

        this.Root.Draw_HighLights(PDSH, false);

        var CommFirst = PDSH.Comm.Get_Next();
        var CollFirst = PDSH.Coll.Get_Next();

        PDSH.Load_Comm(Comm);
        PDSH.Load_Coll(Coll);

        if (null !== CommFirst)
        {
            var CommentsCount = PDSH.Comments.length;
            var CommentId     = ( CommentsCount > 0 ? PDSH.Comments[CommentsCount - 1] : null );
            var CommentsFlag  = PDSH.CommentsFlag;

            var Bounds = this.Root.Get_LineBound(PDSH.Line, PDSH.Range);
            Comm.Add(Bounds.Y, Bounds.Y + Bounds.H, Bounds.X, Bounds.X + Bounds.W, 0, 0, 0, 0, { Active : CommentsFlag === comments_ActiveComment ? true : false, CommentId : CommentId } );
        }

        if (null !== CollFirst)
        {
            var Bounds = this.Root.Get_LineBound(PDSH.Line, PDSH.Range);
            Coll.Add(Bounds.Y, Bounds.Y + Bounds.H, Bounds.X, Bounds.X + Bounds.W, 0, CollFirst.r, CollFirst.g, CollFirst.b);
        }

        PDSH.Y0 = Y0;
        PDSH.Y1 = Y1;
    }
};
ParaMath.prototype.Draw_Elements = function(PDSE)
{
    /*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);*/

    var X = PDSE.X;

    this.Root.Draw_Elements(PDSE);

    PDSE.X = X + this.Root.GetWidth(PDSE.Line, PDSE.Range);

    /*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);*/
};
ParaMath.prototype.GetLinePosition = function(Line, Range)
{
    return this.Root.GetPos(Line, Range);
};
ParaMath.prototype.Draw_Lines = function(PDSL)
{
    if(false == this.Root.IsEmptyRange(PDSL.Line, PDSL.Range))
    {
        // Underline всей формулы
        var FirstRPrp = this.GetFirstRPrp();

        var Para = PDSL.Paragraph;

        var aUnderline  = PDSL.Underline;

        var X          = PDSL.X;
        var Y          = PDSL.Baseline;
        var UndOff     = PDSL.UnderlineOffset;
        var UnderlineY = Y + UndOff;
        var LineW      = (FirstRPrp.FontSize / 18) * g_dKoef_pt_to_mm;


        var BgColor = PDSL.BgColor;
        if ( undefined !== FirstRPrp.Shd && shd_Nil !== FirstRPrp.Shd.Value )
            BgColor = FirstRPrp.Shd.Get_Color( Para );
        var AutoColor = ( undefined != BgColor && false === BgColor.Check_BlackAutoColor() ? new CDocumentColor( 255, 255, 255, false ) : new CDocumentColor( 0, 0, 0, false ) );
        var CurColor, RGBA, Theme = this.Paragraph.Get_Theme(), ColorMap = this.Paragraph.Get_ColorMap();

        // Выставляем цвет обводки
        if ( true === PDSL.VisitedHyperlink && ( undefined === FirstRPrp.Color && undefined === FirstRPrp.Unifill ) )
            CurColor = new CDocumentColor( 128, 0, 151 );
        else if ( true === FirstRPrp.Color.Auto && !FirstRPrp.Unifill)
            CurColor = new CDocumentColor( AutoColor.r, AutoColor.g, AutoColor.b );
        else
        {
            if(FirstRPrp.Unifill)
            {
                FirstRPrp.Unifill.check(Theme, ColorMap);
                RGBA = FirstRPrp.Unifill.getRGBAColor();
                CurColor = new CDocumentColor( RGBA.R, RGBA.G, RGBA.B );
            }
            else
            {
                CurColor = new CDocumentColor( FirstRPrp.Color.r, FirstRPrp.Color.g, FirstRPrp.Color.b );
            }
        }

        var Bound = this.Root.Get_LineBound(PDSL.Line, PDSL.Range),
            Width = Bound.W;

        if ( true === FirstRPrp.Underline )
            aUnderline.Add( UnderlineY, UnderlineY, X, X + Width, LineW, CurColor.r, CurColor.g, CurColor.b );


        this.Root.Draw_Lines(PDSL);

        PDSL.X = Bound.X + Width;
    }
};

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

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

    return this.Root.Cursor_Is_Start();
};

ParaMath.prototype.Cursor_Is_NeededCorrectPos = function()
{
    return false;
};

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

    return this.Root.Cursor_Is_End();
};

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

    this.Root.Cursor_MoveToStartPos();
};

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

    this.Root.Cursor_MoveToEndPos(SelectFromEnd);
};

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

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

    if(SearchPos.InText)
        SearchPos.DiffX  = 0.001; // чтобы всегда встать в формулу, если попали в текст

    return Result;
};

ParaMath.prototype.Get_ParaContentPos = function(bSelection, bStart, ContentPos) // получить текущую логическую позицию
{
    this.Root.Get_ParaContentPos(bSelection, bStart, ContentPos);
};

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

ParaMath.prototype.Get_PosByElement = function(Class, ContentPos, Depth, UseRange, Range, Line)
{
    if ( this === Class )
        return true;

    return this.Root.Get_PosByElement(Class, ContentPos, Depth, UseRange, Range, Line);
};

ParaMath.prototype.Get_ElementByPos = function(ContentPos, Depth)
{
    return this.Root.Get_ElementByPos(ContentPos, Depth);
};

ParaMath.prototype.Get_ClassesByPos = function(Classes, ContentPos, Depth)
{
    Classes.push(this);

    this.Root.Get_ClassesByPos(Classes, ContentPos, Depth);
};

ParaMath.prototype.Get_PosByDrawing = function(Id, ContentPos, Depth)
{
    return false;
};

ParaMath.prototype.Get_RunElementByPos = function(ContentPos, Depth)
{
    return null;
};

ParaMath.prototype.Get_LastRunInRange = function(_CurLine, _CurRange)
{
    return this.Root.Get_LastRunInRange(_CurLine, _CurRange);
};

ParaMath.prototype.Get_LeftPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
    return this.Root.Get_LeftPos(SearchPos, ContentPos, Depth, UseContentPos, false);
};

ParaMath.prototype.Get_RightPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
    return this.Root.Get_RightPos(SearchPos, ContentPos, Depth, UseContentPos, StepEnd, false);
};

ParaMath.prototype.Get_WordStartPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
    this.Root.Get_WordStartPos(SearchPos, ContentPos, Depth, UseContentPos, false);
};

ParaMath.prototype.Get_WordEndPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
    this.Root.Get_WordEndPos(SearchPos, ContentPos, Depth, UseContentPos, StepEnd, false);
};
ParaMath.prototype.Get_EndRangePos = function(_CurLine, _CurRange, SearchPos, Depth)
{
    return this.Root.Get_EndRangePos(_CurLine, _CurRange, SearchPos, Depth);
};
ParaMath.prototype.Get_StartRangePos = function(_CurLine, _CurRange, SearchPos, Depth)
{
    return this.Root.Get_StartRangePos(_CurLine, _CurRange, SearchPos, Depth);
};
ParaMath.prototype.Get_StartRangePos2 = function(_CurLine, _CurRange, ContentPos, Depth)
{
    return this.Root.Get_StartRangePos2(_CurLine, _CurRange, ContentPos, Depth);
};

ParaMath.prototype.Get_StartPos = function(ContentPos, Depth)
{
    this.Root.Get_StartPos(ContentPos, Depth);
};

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

ParaMath.prototype.Selection_IsUse = function()
{
    return this.bSelectionUse;
};

ParaMath.prototype.Selection_Stop = function()
{
};

ParaMath.prototype.Selection_Remove = function()
{
    this.bSelectionUse = false;
    this.Root.Selection_Remove();
};

ParaMath.prototype.Select_All = function(Direction)
{
    this.bSelectionUse = true;
    this.Root.Select_All();
};

ParaMath.prototype.Selection_DrawRange = function(_CurLine, _CurRange, SelectionDraw)
{
    this.Root.Selection_DrawRange(_CurLine, _CurRange, SelectionDraw);
};
ParaMath.prototype.Selection_IsEmpty = function(CheckEnd)
{
    return this.Root.Selection_IsEmpty();
};

ParaMath.prototype.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;
};

ParaMath.prototype.Selection_CheckParaEnd = function()
{
    return false;
};

ParaMath.prototype.Selection_CheckParaContentPos = function(ContentPos, Depth, bStart, bEnd)
{
    return this.Root.Selection_CheckParaContentPos(ContentPos, Depth, bStart, bEnd);
};

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

ParaMath.prototype.Selection_CorrectLeftPos = function(Direction)
{
    return false;
};
//----------------------------------------------------------------------------------------------------------------------
// Функции совместного редактирования
//----------------------------------------------------------------------------------------------------------------------
ParaMath.prototype.Undo = function(Data)
{
    Data.Undo(this);
};

ParaMath.prototype.Redo = function(Data)
{
    Data.Redo(this);
};

ParaMath.prototype.Save_Changes = function(Data, Writer)
{
    WriteChanges_ToBinary(Data, Writer);
};

ParaMath.prototype.Load_Changes = function(Reader)
{
    ReadChanges_FromBinary(Reader, this);
};

ParaMath.prototype.Write_ToBinary2 = function(Writer)
{
    Writer.WriteLong( historyitem_type_Math );

    // String : this.Id
    // Long   : this.Type
    // String : Root.Id

    Writer.WriteString2(this.Id);
    Writer.WriteLong(this.Type);
    Writer.WriteString2(this.Root.Id);
};

ParaMath.prototype.Read_FromBinary2 = function(Reader)
{
    // String : this.Id
    // Long   : this.Type
    // String : Root.Id

    this.Id   = Reader.GetString2();
    this.Type = Reader.GetLong();
    this.Root = g_oTableId.Get_ById(Reader.GetString2());
    this.Root.bRoot = true;
    this.Root.ParentElement = this;
};

ParaMath.prototype.Get_ContentSelection = function()
{
    var Bounds = null;
    var oContent = this.GetSelectContent().Content;

    if (oContent.bRoot == false)
    {
        if(oContent.bOneLine)
        {
            Bounds = oContent.Get_Bounds();
        }
        else
        {
            Bounds = this.private_GetBounds(oContent);
        }
    }

    return Bounds;
};

ParaMath.prototype.Recalc_RunsCompiledPr = function()
{
    this.Root.Recalc_RunsCompiledPr();
};

/**
 * Проверяем находимся ли мы во внутреннем (не самом верхнем) контенте формулы.
 */
ParaMath.prototype.Is_InInnerContent = function()
{
    var oContent = this.GetSelectContent().Content;

    if (oContent.bRoot)
        return false;

    return true;
};

/**
 * Обработка нажатия Enter внутри формулы
 */
ParaMath.prototype.Handle_AddNewLine = function()
{
    var ContentPos = new CParagraphContentPos();

    var CurrContent = this.GetSelectContent().Content;

    if (true === CurrContent.bRoot)
        return false;

    CurrContent.Get_ParaContentPos(this.bSelectionUse, true, ContentPos);

    var NeedRecalculate = false;

    if(MATH_EQ_ARRAY === CurrContent.ParentElement.kind)
    {
        var NewContent = CurrContent.Parent.addRow();
        CurrContent.SplitContent(NewContent, ContentPos, 0);
        NewContent.Correct_Content(true);
        CurrContent.Correct_Content(true);

        NewContent.Cursor_MoveToStartPos();

        NeedRecalculate = true;
    }
    else if(MATH_MATRIX !== CurrContent.ParentElement.kind)
    {
        var ctrPrp = CurrContent.Parent.CtrPrp.Copy();
        var props = {row: 2, ctrPrp: ctrPrp};
        var EqArray = new CEqArray(props);

        var FirstContent  = EqArray.getElementMathContent(0);
        var SecondContent = EqArray.getElementMathContent(1);

        CurrContent.SplitContent(SecondContent, ContentPos, 0);
        CurrContent.CopyTo(FirstContent, false);

        // вставим пустой Run в Content, чтобы не упала ф-ия Remove_FromContent
        // первый элемент всегда Run
        var Run = CurrContent.getElem(0);
        Run.Remove_FromContent(0, Run.Content.length, true);

        CurrContent.Remove_FromContent(1, CurrContent.Content.length);
        CurrContent.Add_ToContent(1, EqArray);
        CurrContent.Correct_Content(true);

        var CurrentContent = new CParagraphContentPos();
        this.Get_ParaContentPos(false, false, CurrentContent);

        var RightContentPos = new CParagraphSearchPos();
        this.Get_RightPos(RightContentPos, CurrentContent, 0, true);
        this.Set_ParaContentPos(RightContentPos.Pos, 0);

        EqArray.CurPos = 1;
        SecondContent.Cursor_MoveToStartPos();

        NeedRecalculate = true;
    }


    return NeedRecalculate;
};

/**
 * Разделение формулы на 2 части в заданной позиции. В текущем объекте остается левая часть формулы.
 * @param ContentPos Позиция
 * @param Depth
 * @returns Возвращается правая часть формулы.
 */
ParaMath.prototype.Split = function (ContentPos, Depth)
{
    var NewParaMath = new ParaMath();
    NewParaMath.Jc = this.Jc;

    this.Root.SplitContent(NewParaMath.Root, ContentPos, Depth);

    return NewParaMath;
};

/**
 * Пытаемся выполнить автозамену в формуле.
 * @returns {boolean} Выполнилась ли автозамена.
 */
ParaMath.prototype.Make_AutoCorrect = function()
{
    return false;
};

/**
 * Получаем рект формулы
 * @constructor
 */
ParaMath.prototype.Get_Bounds = function()
{
    if (undefined === this.Paragraph || null === this.Paragraph)
    {
        return [{X : 0, Y : 0, W : 0, H : 0, Page : 0}];
    }
    else
    {
        return this.private_GetBounds(this.Root);
    }
};
ParaMath.prototype.private_GetBounds = function(Content)
{
    var Bounds = [];
    var StartParaPage = this.Paragraph.Get_StartPage_Absolute();

    var ContentBounds = Content.Get_Bounds();

    for(var Line = 0; Line < ContentBounds.length; Line++)
    {
        Bounds[Line] = [];
        var CurLine = Line + Content.StartLine;
        var HLine = this.Paragraph.Lines[CurLine].Bottom - this.Paragraph.Lines[CurLine].Top;
        var Height = HLine;
        var Y;

        for(var Range = 0; Range < ContentBounds[Line].length; Range++)
        {
            var oBound   = ContentBounds[Line][Range],
                ParaPage = oBound.Page,
                YLine    = this.Paragraph.Pages[ParaPage].Y + this.Paragraph.Lines[CurLine].Top;

            Y = YLine;

            if(Content.bRoot == false)
            {
                if(HLine < oBound.H)
                {
                    Height = HLine;
                    Y = YLine;
                }
                else
                {
                    Height = oBound.H;
                    Y  = oBound.Y;
                }
            }

            Bounds[Line][Range] =
            {
                X:      oBound.X,
                Y:      Y,
                W:      oBound.W,
                H:      Height,
                Page:   oBound.Page + StartParaPage
            };
        }
    }

    return Bounds;
};

ParaMath.prototype.getPropsForWrite = function()
{
    return {Jc : this.Jc};
};

/**
 * Обновляем состояние интерфейса.
 */
ParaMath.prototype.Document_UpdateInterfaceState = function()
{
    var SelectedContent = this.GetSelectContent();
    var MathContent = SelectedContent.Content;

    var MathProps = new CMathProp();

    if (MathContent.bRoot)
    {
        MathProps.Type = c_oAscMathInterfaceType.Common;
        MathProps.Pr   = null;
    }
    else if (undefined !== MathContent.ParentElement && null !== MathContent.ParentElement)
    {
        MathContent.ParentElement.Document_UpdateInterfaceState(MathProps);
    }

    editor.sync_MathPropCallback(MathProps);
};

/**
 * Проверяем используется ли заданный MathContent на текущем уровне формулы
 * @param MathContent
 */
ParaMath.prototype.Is_ContentUse  = function(MathContent)
{
    if (this.Root === MathContent)
        return true;

    return false;
};

/*
 * Выполняем коректировку формулы после конвертирования ее из старой формулы (Equation 2-3).
 */
ParaMath.prototype.Correct_AfterConvertFromEquation = function()
{
    this.ParaMathRPI.bCorrect_FontSize = true;
    //this.Root.Correct_AfterConvertFromEquation();
};

ParaMath.prototype.Check_RevisionsChanges = function(Checker, ContentPos, Depth)
{
    return this.Root.Check_RevisionsChanges(Checker, ContentPos, Depth);
};
ParaMath.prototype.Accept_RevisionChanges = function(Type, bAll)
{
    return this.Root.Accept_RevisionChanges(Type, bAll);
};
ParaMath.prototype.Reject_RevisionChanges = function(Type, bAll)
{
    return this.Root.Reject_RevisionChanges(Type, bAll);
};
ParaMath.prototype.Set_ReviewType = function(ReviewType, RemovePrChange)
{
    return this.Root.Set_ReviewType(ReviewType, RemovePrChange);
};

//----------------------------------------------------------------------------------------------------------------------
// Классы с изменениями
//----------------------------------------------------------------------------------------------------------------------
var historyitem_Math_AddItem                   =  1; // Добавляем элемент
var historyitem_Math_RemoveItem                =  2; // Удаляем элемент
var historyitem_Math_CtrPrpFSize               =  3; // CtrPrp
var historyitem_Math_ParaJc                    =  4; // ParaMath.Jc
var historyitem_Math_CtrPrpShd                 =  5;
var historyitem_Math_AddItems_ToMathBase       =  6;
var historyitem_Math_EqArrayPr                 =  7; // Изменение настроек у CEqArray
var historyitem_Math_CtrPrpColor               =  8;
var historyitem_Math_CtrPrpUnifill             =  9;
var historyitem_Math_CtrPrpUnderline           =  10;
var historyitem_Math_CtrPrpStrikeout           =  11;
var historyitem_Math_CtrPrpDoubleStrikeout     =  12;
var historyitem_Math_CtrPrpItalic              =  13;
var historyitem_Math_CtrPrpBold                =  14;
var historyitem_Math_RFontsAscii               =  15;
var historyitem_Math_RFontsHAnsi               =  16;
var historyitem_Math_RFontsCS                  =  17;
var historyitem_Math_RFontsEastAsia            =  18;
var historyitem_Math_RFontsHint                =  19;
var historyitem_Math_CtrPrpHighLight           =  20;
var historyitem_Math_ArgSize                   =  21;
var historyitem_Math_ReviewType                =  22;


function ReadChanges_FromBinary(Reader, Class)
{
    var Type = Reader.GetLong();
    var Changes = null;

    switch(Type)
    {
        case historyitem_Math_CtrPrpFSize           : Changes = new CChangesMathFontSize(); break;
        case historyitem_Math_ParaJc                : Changes = new CChangesMathParaJc(); break;
        case historyitem_Math_CtrPrpShd             : Changes = new CChangesMathShd(); break;
        case historyitem_Math_AddItems_ToMathBase   : Changes = new CChangesMathAddItems(); break;
        case historyitem_Math_CtrPrpColor           : Changes = new CChangesMathColor(); break;
        case historyitem_Math_CtrPrpUnifill         : Changes = new CChangesMathUnifill(); break;
        case historyitem_Math_CtrPrpUnderline       : Changes = new CChangesMathUnderline(); break;
        case historyitem_Math_CtrPrpStrikeout       : Changes = new CChangesMathStrikeout(); break;
        case historyitem_Math_CtrPrpDoubleStrikeout : Changes = new CChangesMath_DoubleStrikeout(); break;
        case historyitem_Math_CtrPrpItalic          : Changes = new CChangesMathItalic(); break;
        case historyitem_Math_CtrPrpBold            : Changes = new CChangesMathBold(); break;
        case historyitem_Math_RFontsAscii           : Changes = new CChangesMath_RFontsAscii(); break;
        case historyitem_Math_RFontsHAnsi           : Changes = new CChangesMath_RFontsHAnsi(); break;
        case historyitem_Math_RFontsCS              : Changes = new CChangesMath_RFontsCS(); break;
        case historyitem_Math_RFontsEastAsia        : Changes = new CChangesMath_RFontsEastAsia(); break;
        case historyitem_Math_RFontsHint            : Changes = new CChangesMath_RFontsHint(); break;
        case historyitem_Math_CtrPrpHighLight       : Changes = new CChangesMathHighLight(); break;
    }

    if (null !== Changes)
        Changes.Load_Changes(Reader, Class);
}

function WriteChanges_ToBinary(Changes, Writer)
{
    Writer.WriteLong(Changes.Type);
    Changes.Save_Changes(Writer);
}

//----------------------------------------------------------------------------------------------------------------------
// Классы с изменениями
//----------------------------------------------------------------------------------------------------------------------
function CChangesMathFontSize(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}

CChangesMathFontSize.prototype.Type = historyitem_Math_CtrPrpFSize;

CChangesMathFontSize.prototype.Undo = function(Class)
{
    Class.raw_SetFontSize(this.Old);
};
CChangesMathFontSize.prototype.Redo = function(Class)
{
    Class.raw_SetFontSize(this.New);
};
CChangesMathFontSize.prototype.Save_Changes = function(Writer)
{
    // Bool : IsUndefined
    // Long : New
    if (undefined === this.New)
        Writer.WriteBool(true);
    else
    {
        Writer.WriteBool(false);
        Writer.WriteLong(this.New);
    }
};
CChangesMathFontSize.prototype.Load_Changes = function(Reader, Class)
{
    // Bool : IsUndefined
    // Long : New

    if (true === Reader.GetBool())
        this.New = undefined;
    else
        this.New = Reader.GetLong();

    this.Redo(Class);
};

function CChangesMathShd(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMathShd.prototype.Type = historyitem_Math_CtrPrpShd;
CChangesMathShd.prototype.Undo = function(Class)
{
    Class.raw_SetShd(this.Old);
};
CChangesMathShd.prototype.Redo = function(Class)
{
    Class.raw_SetShd(this.New);
};
CChangesMathShd.prototype.Save_Changes = function(Writer)
{
    // Bool : IsUndefined

    if ( undefined !== this.New )
    {
        Writer.WriteBool(false);
        this.New.Write_ToBinary(Writer);
    }
    else
        Writer.WriteBool(true);

};
CChangesMathShd.prototype.Load_Changes = function(Reader, Class)
{
    // Bool : IsUndefined

    if ( Reader.GetBool() == false)
    {
        this.New = new CDocumentShd();
        this.New.Read_FromBinary( Reader );
    }
    else
    {
        this.New = undefined;
    }

    this.Redo(Class);
};

function CChangesMathHighLight(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMathHighLight.prototype.Type = historyitem_Math_CtrPrpHighLight;
CChangesMathHighLight.prototype.Undo = function(Class)
{
    Class.raw_SetHighLight(this.Old);
};
CChangesMathHighLight.prototype.Redo = function(Class)
{
    Class.raw_SetHighLight(this.New);
};
CChangesMathHighLight.prototype.Save_Changes = function(Writer)
{
    if ( undefined != this.New )
    {
        Writer.WriteBool(false);
        if ( highlight_None != this.New )
        {
            Writer.WriteBool( false );
            this.New.Write_ToBinary( Writer );
        }
        else
            Writer.WriteBool( true );
    }
    else
        Writer.WriteBool(true);
};
CChangesMathHighLight.prototype.Load_Changes = function(Reader, Class)
{
    if ( Reader.GetBool() == false )
    {
        if ( Reader.GetBool() == false )
        {
            this.New = new CDocumentColor(0,0,0);
            this.New.Read_FromBinary(Reader);
        }
        else
            this.New = highlight_None;
    }
    else
        this.New = undefined;

    this.Redo(Class);
};

function CChangesMathColor(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMathColor.prototype.Type = historyitem_Math_CtrPrpColor;
CChangesMathColor.prototype.Undo = function(Class)
{
    Class.raw_SetColor(this.Old);
};
CChangesMathColor.prototype.Redo = function(Class)
{
    Class.raw_SetColor(this.New);
};
CChangesMathColor.prototype.Save_Changes = function(Writer)
{
    // Bool : IsUndefined

    if ( undefined !== this.New )
    {
        Writer.WriteBool(false);
        this.New.Write_ToBinary(Writer);
    }
    else
    {
        Writer.WriteBool(true);
    }
};
CChangesMathColor.prototype.Load_Changes = function(Reader, Class)
{
    // Bool : IsUndefined

    if ( Reader.GetBool() == false)
    {
        this.New = new CDocumentColor(0, 0, 0, false);
        this.New.Read_FromBinary(Reader);
    }
    else
    {
        this.New = undefined;
    }

    this.Redo(Class);
};

function CChangesMathUnifill(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMathUnifill.prototype.Type = historyitem_Math_CtrPrpUnifill;
CChangesMathUnifill.prototype.Undo = function(Class)
{
    Class.raw_SetUnifill(this.Old);
};
CChangesMathUnifill.prototype.Redo = function(Class)
{
    Class.raw_SetUnifill(this.New);
};
CChangesMathUnifill.prototype.Save_Changes = function(Writer)
{
    // Bool : IsUndefined

    if ( undefined !== this.New )
    {
        Writer.WriteBool(false);
        this.New.Write_ToBinary(Writer);
    }
    else
    {
        Writer.WriteBool(true);
    }
};
CChangesMathUnifill.prototype.Load_Changes = function(Reader, Class)
{
    // Bool : IsUndefined

    if ( Reader.GetBool() == false)
    {
        this.New = new CUniFill();
        this.New.Read_FromBinary(Reader);
    }
    else
    {
        this.New = undefined;
    }

    this.Redo(Class);
};

function CChangesMathUnderline(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMathUnderline.prototype.Type = historyitem_Math_CtrPrpUnderline;
CChangesMathUnderline.prototype.Undo = function(Class)
{
    Class.raw_SetUnderline(this.Old);
};
CChangesMathUnderline.prototype.Redo = function(Class)
{
    Class.raw_SetUnderline(this.New);
};
CChangesMathUnderline.prototype.Save_Changes = function(Writer)
{
    // Bool : IsUndefined
    // Bool : IsUnderline

    if (undefined === this.New)
        Writer.WriteBool(true);
    else
    {
        Writer.WriteBool(false);
        Writer.WriteBool(this.New);
    }

};
CChangesMathUnderline.prototype.Load_Changes = function(Reader, Class)
{
    // Bool : IsUndefined
    // Bool : IsUnderline

    if(true === Reader.GetBool())
        this.New = undefined;
    else
        this.New = Reader.GetBool();

    this.Redo(Class);
}

function CChangesMathStrikeout(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMathStrikeout.prototype.Type = historyitem_Math_CtrPrpStrikeout;
CChangesMathStrikeout.prototype.Undo = function(Class)
{
    Class.raw_SetStrikeout(this.Old);
};
CChangesMathStrikeout.prototype.Redo = function(Class)
{
    Class.raw_SetStrikeout(this.New);
};
CChangesMathStrikeout.prototype.Save_Changes = function(Writer)
{
    // Bool : IsUndefined
    // Bool : IsStrikeOut

    if (undefined === this.New)
        Writer.WriteBool(true);
    else
    {
        Writer.WriteBool(false);
        Writer.WriteBool(this.New);
    }
};
CChangesMathStrikeout.prototype.Load_Changes = function(Reader, Class)
{
    // Bool : IsUndefined
    // Bool : IsStrikeOut

    if(true === Reader.GetBool())
        this.New = undefined;
    else
        this.New = Reader.GetBool();

    this.Redo(Class);
};

function CChangesMath_DoubleStrikeout(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMath_DoubleStrikeout.prototype.Type = historyitem_Math_CtrPrpDoubleStrikeout;
CChangesMath_DoubleStrikeout.prototype.Undo = function(Class)
{
    Class.raw_Set_DoubleStrikeout(this.Old);
};
CChangesMath_DoubleStrikeout.prototype.Redo = function(Class)
{
    Class.raw_Set_DoubleStrikeout(this.New);
};
CChangesMath_DoubleStrikeout.prototype.Save_Changes = function(Writer)
{
    // Bool : IsUndefined
    // Bool : IsDoubleStrikeOut

    if (undefined === this.New)
        Writer.WriteBool(true);
    else
    {
        Writer.WriteBool(false);
        Writer.WriteBool(this.New);
    }
};
CChangesMath_DoubleStrikeout.prototype.Load_Changes = function(Reader, Class)
{
    // Bool : IsUndefined
    // Bool : IsDoubleStrikeOut

    if(true === Reader.GetBool())
        this.New = undefined;
    else
        this.New = Reader.GetBool();

    this.Redo(Class);
};

function CChangesMathItalic(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMathItalic.prototype.Type = historyitem_Math_CtrPrpItalic;
CChangesMathItalic.prototype.Undo = function(Class)
{
    Class.raw_SetItalic(this.Old);
};
CChangesMathItalic.prototype.Redo = function(Class)
{
    Class.raw_SetItalic(this.New);
};
CChangesMathItalic.prototype.Save_Changes = function(Writer)
{
    // Bool : IsUndefined
    // Bool : IsItalic

    if (undefined === this.New)
        Writer.WriteBool(true);
    else
    {
        Writer.WriteBool(false);
        Writer.WriteBool(this.New);
    }

};
CChangesMathItalic.prototype.Load_Changes = function(Reader, Class)
{
    // Bool : IsUndefined
    // Bool : IsItalic

    if(true === Reader.GetBool())
        this.New = undefined;
    else
        this.New = Reader.GetBool();

    this.Redo(Class);

};

function CChangesMathBold(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMathBold.prototype.Type = historyitem_Math_CtrPrpBold;
CChangesMathBold.prototype.Undo = function(Class)
{
    Class.raw_SetBold(this.Old);
};
CChangesMathBold.prototype.Redo = function(Class)
{
    Class.raw_SetBold(this.New);
};
CChangesMathBold.prototype.Save_Changes = function(Writer)
{
    // Bool : IsUndefined
    // Bool : IsBold

    if (undefined === this.New)
        Writer.WriteBool(true);
    else
    {
        Writer.WriteBool(false);
        Writer.WriteBool(this.New);
    }

};
CChangesMathBold.prototype.Load_Changes = function(Reader, Class)
{
    // Bool : IsUndefined
    // Bool : IsBold

    if(true === Reader.GetBool())
        this.New = undefined;
    else
        this.New = Reader.GetBool();

    this.Redo(Class);

};


function CChangesMath_RFontsAscii(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMath_RFontsAscii.prototype.Type = historyitem_Math_RFontsAscii;
CChangesMath_RFontsAscii.prototype.Undo = function(Class)
{
    Class.raw_SetRFontsAscii(this.Old);
};
CChangesMath_RFontsAscii.prototype.Redo = function(Class)
{
    Class.raw_SetRFontsAscii(this.New);
};
CChangesMath_RFontsAscii.prototype.Save_Changes = function(Writer)
{
    // Bool   : IsUndefined
    // String : Font

    if (undefined === this.New)
    {
        Writer.WriteBool(true);
    }
    else
    {
        Writer.WriteBool(false);
        Writer.WriteString2(this.New.Name);
    }
};
CChangesMath_RFontsAscii.prototype.Load_Changes = function(Reader, Class)
{
    // Bool   : IsUndefined
    // String : Font

    if(true === Reader.GetBool())
        this.New = undefined;
    else
    {
        this.New =
        {
            Name  : Reader.GetString2(),
            Index : -1
        };
    }

    this.Redo(Class);
};

function CChangesMath_RFontsHAnsi(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMath_RFontsHAnsi.prototype.Type = historyitem_Math_RFontsHAnsi;
CChangesMath_RFontsHAnsi.prototype.Undo = function(Class)
{
    Class.raw_SetRFontsHAnsi(this.Old);
};
CChangesMath_RFontsHAnsi.prototype.Redo = function(Class)
{
    Class.raw_SetRFontsHAnsi(this.New);
};
CChangesMath_RFontsHAnsi.prototype.Save_Changes = function(Writer)
{
    // Bool   : IsUndefined
    // String : Font

    if (undefined === this.New)
    {
        Writer.WriteBool(true);
    }
    else
    {
        Writer.WriteBool(false);
        Writer.WriteString2(this.New.Name);
    }
};
CChangesMath_RFontsHAnsi.prototype.Load_Changes = function(Reader, Class)
{
    // Bool   : IsUndefined
    // String : Font

    if(true === Reader.GetBool())
        this.New = undefined;
    else
    {
        this.New =
        {
            Name  : Reader.GetString2(),
            Index : -1
        };
    }

    this.Redo(Class);
};


function CChangesMath_RFontsCS(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMath_RFontsCS.prototype.Type = historyitem_Math_RFontsCS;
CChangesMath_RFontsCS.prototype.Undo = function(Class)
{
    Class.raw_SetRFontsCS(this.Old);
};
CChangesMath_RFontsCS.prototype.Redo = function(Class)
{
    Class.raw_SetRFontsCS(this.New);
};
CChangesMath_RFontsCS.prototype.Save_Changes = function(Writer)
{
    // Bool   : IsUndefined
    // String : Font

    if (undefined === this.New)
    {
        Writer.WriteBool(true);
    }
    else
    {
        Writer.WriteBool(false);
        Writer.WriteString2(this.New.Name);
    }
};
CChangesMath_RFontsCS.prototype.Load_Changes = function(Reader, Class)
{
    // Bool   : IsUndefined
    // String : Font

    if(true === Reader.GetBool())
        this.New = undefined;
    else
    {
        this.New =
        {
            Name  : Reader.GetString2(),
            Index : -1
        };
    }

    this.Redo(Class);
};

function CChangesMath_RFontsEastAsia(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMath_RFontsEastAsia.prototype.Type = historyitem_Math_RFontsEastAsia;
CChangesMath_RFontsEastAsia.prototype.Undo = function(Class)
{
    Class.raw_SetRFontsEastAsia(this.Old);
};
CChangesMath_RFontsEastAsia.prototype.Redo = function(Class)
{
    Class.raw_SetRFontsEastAsia(this.New);
};
CChangesMath_RFontsEastAsia.prototype.Save_Changes = function(Writer)
{
    // Bool   : IsUndefined
    // String : Font

    if (undefined === this.New)
    {
        Writer.WriteBool(true);
    }
    else
    {
        Writer.WriteBool(false);
        Writer.WriteString2(this.New.Name);
    }


};
CChangesMath_RFontsEastAsia.prototype.Load_Changes = function(Reader, Class)
{
    // Bool   : IsUndefined
    // String : Font

    if(true === Reader.GetBool())
        this.New = undefined;
    else
    {
        this.New =
        {
            Name  : Reader.GetString2(),
            Index : -1
        };
    }

    this.Redo(Class);
};

function CChangesMath_RFontsHint(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMath_RFontsHint.prototype.Type = historyitem_Math_RFontsHint;
CChangesMath_RFontsHint.prototype.Undo = function(Class)
{
    Class.raw_SetRFontsHint(this.Old);
};
CChangesMath_RFontsHint.prototype.Redo = function(Class)
{
    Class.raw_SetRFontsHint(this.New);
};
CChangesMath_RFontsHint.prototype.Save_Changes = function(Writer)
{
    // Bool   : IsUndefined
    // String : Font

    if (undefined === this.New)
    {
        Writer.WriteBool(true);
    }
    else
    {
        Writer.WriteBool(false);
        Writer.WriteLong(this.New);
    }
};
CChangesMath_RFontsHint.prototype.Load_Changes = function(Reader, Class)
{
    // Bool   : IsUndefined
    // String : Font

    if(true === Reader.GetBool())
        this.New = undefined;
    else
        this.New = Reader.GetLong();

    this.Redo(Class);
};


function CChangesMathAddItems(Pos, Items)
{
    this.Pos   = Pos;
    this.Items = Items;
}
CChangesMathAddItems.prototype.Type = historyitem_Math_AddItems_ToMathBase;
CChangesMathAddItems.prototype.Undo = function(Class)
{
    Class.raw_RemoveFromContent(this.Pos, this.Items.length);
};
CChangesMathAddItems.prototype.Redo = function(Class)
{
    Class.raw_AddToContent(this.Pos, this.Items, false);
};
CChangesMathAddItems.prototype.Save_Changes = function(Writer)
{
    // Long : Count
    // Long : Pos
    // Array of String : Id

    var Count = this.Items.length;
    Writer.WriteLong(Count);
    Writer.WriteLong(this.Pos);

    for(var Index = 0; Index < Count; Index++)
    {
        Writer.WriteString2(this.Items[Index].Get_Id());
    }
};
CChangesMathAddItems.prototype.Load_Changes = function(Reader, Class)
{
    // Long : Count
    // Long : Pos
    // Array of String : Id

    var Count = Reader.GetLong();
    this.Pos  = Reader.GetLong();

    this.Items = [];
    for(var Index = 0; Index < Count; Index++)
    {
        var Element = g_oTableId.Get_ById(Reader.GetString2());

        if (null !== Element)
            this.Items.push(Element);
    }

    this.Redo(Class);
};

function CChangesMathParaJc(NewValue, OldValue)
{
    this.New = NewValue;
    this.Old = OldValue;
}
CChangesMathParaJc.prototype.Type = historyitem_Math_ParaJc;
CChangesMathParaJc.prototype.Undo = function(Class)
{
    Class.raw_SetAlign(this.Old);
};
CChangesMathParaJc.prototype.Redo = function(Class)
{
    Class.raw_SetAlign(this.New);
};
CChangesMathParaJc.prototype.Save_Changes = function(Writer)
{
    // Bool : undefined?
    // Long : value
    if (undefined === this.New)
        Writer.WriteBool(true);
    else
    {
        Writer.WriteBool(false);
        Writer.WriteLong(this.New);
    }
};
CChangesMathParaJc.prototype.Load_Changes = function(Reader, Class)
{
    if (true === Reader.GetBool())
        this.New = undefined;
    else
        this.New = Reader.GetLong();

    this.Redo(Class);
};

function CChangesMathEqArrayPr(NewPr, OldPr)
{
    this.New = NewPr;
    this.Old = OldPr;
}
CChangesMathEqArrayPr.prototype.Type = historyitem_Math_EqArrayPr;
CChangesMathEqArrayPr.prototype.Undo = function(Class)
{
    Class.raw_SetPr(this.Old);
};
CChangesMathEqArrayPr.prototype.Redo = function(Class)
{
    Class.raw_SetPr(this.New);
};
CChangesMathEqArrayPr.prototype.Save_Changes = function(Writer)
{
    // Bool : undefined?
    // Long : value
    if (undefined === this.New)
        Writer.WriteBool(true);
    else
    {
        Writer.WriteBool(false);
        this.New.Write_ToBinary(Writer);
    }
};
CChangesMathEqArrayPr.prototype.Load_Changes = function(Reader, Class)
{
    if (true === Reader.GetBool())
        this.New = undefined;
    else
    {
        this.New = new CMathEqArrPr();
        this.New.Read_FromBinary(Reader);
    }

    this.Redo(Class);
};


function CChangesMathBaseReviewType(NewType, NewInfo, OldType, OldInfo)
{
    this.NewType = NewType;
    this.NewInfo = NewInfo ? NewInfo.Copy() : undefined;
    this.OldType = OldType;
    this.OldInfo = OldInfo ? OldInfo.Copy() : undefined;
}
CChangesMathBaseReviewType.prototype.Type = historyitem_Math_ReviewType;
CChangesMathBaseReviewType.prototype.Undo = function(Class)
{
    Class.raw_SetReviewType(this.OldType, this.OldInfo);
};
CChangesMathBaseReviewType.prototype.Redo = function(Class)
{
    Class.raw_SetReviewType(this.NewType, this.NewInfo);
};
CChangesMathBaseReviewType.prototype.Save_Changes = function(Writer)
{
    // Long        : ReviewType
    // Bool        : ReviewInfo undefined ?
    //   false     : ReviewInfo

    Writer.WriteLong(this.NewType);

    if (undefined === this.NewInfo)
    {
        Writer.WriteBool(true);
    }
    else
    {
        Writer.WriteBool(false);
        this.NewInfo.Write_ToBinary(Writer);
    }
};
CChangesMathBaseReviewType.prototype.Load_Changes = function(Reader, Class)
{
    // Long        : ReviewType
    // CReviewInfo : ReviewInfo

    this.NewType = Reader.GetLong();

    if (true === Reader.GetBool())
    {
        this.NewInfo = undefined;
    }
    else
    {
        this.NewInfo = new CReviewInfo();
        this.NewInfo.Read_FromBinary(Reader);
    }

    this.Redo(Class);
};

function MatGetKoeffArgSize(FontSize, ArgSize)
{
    var FontKoef = 1;

    if(ArgSize == -1)
    {
        FontKoef = g_dMathArgSizeKoeff_1;
    }
    else if(ArgSize == -2)
    {
        FontKoef = g_dMathArgSizeKoeff_2;
    }

    if (1 !== FontKoef )
    {
        FontKoef = (((FontSize * FontKoef * 2 + 0.5) | 0) / 2) / FontSize;
    }

    return FontKoef;
}

function CMathRecalculateInfo()
{
    this.bInline                = false;
    this.bChangeInline          = true;
    this.bRecalcCtrPrp          = false; // необходимо для пересчета CtrPrp (когда изменились текстовые настройки у первого элемнента, ctrPrp нужно пересчитать заново для всей формулы)
    this.bCorrect_FontSize      = false;

    this.IntervalState          = MATH_INTERVAL_EMPTY;
    this.XStart                 = 0;
    this.XEnd                   = 0;
    this.XRange                 = 0;
    this.XLimit                 = 0;
    this.IndLeft                = 0;
    this.bInternalRanges        = false;

    this.RangeY                 = null; // max среди нижних границ плавающих объектов
    this.ShiftY                 = 0;
}
CMathRecalculateInfo.prototype.Reset = function(PRS, ParaPr)
{
    this.XRange                 = PRS.XStart + ParaPr.Ind.Left;
    this.XLimit                 = PRS.XLimit;
    this.IndLeft                = ParaPr.Ind.Left;
    this.ShiftY                 = 0;

    this.Reset_WrapSettings();
};
CMathRecalculateInfo.prototype.Reset_WrapSettings = function()
{
    this.RangeY                 = null;

    this.bInternalRanges        = false;
    this.IntervalState          = MATH_INTERVAL_EMPTY;

    this.XStart                 = this.XRange;
    this.XEnd                   = this.XLimit;
};
CMathRecalculateInfo.prototype.UpdateShiftY = function(RY)
{
    this.ShiftY = RY;
};
CMathRecalculateInfo.prototype.ClearRecalculate = function()
{
    this.bChangeInline     = false;
    this.bRecalcCtrPrp     = false;
    this.bCorrect_FontSize = false;
};

function CMathRecalculateObject()
{
    this.WrapState        = ALIGN_EMPTY;
    this.MaxW             = 0;              // для рассчета выравнивания формулы нужно учитывать изменилась ли максимальная ширина или нет
    this.bWordLarge       = false;          // если формула выходит за границы докумена, то не нужно учитывать выравнивание, а значит можно сделать быстрый пересчет
    this.bFastRecalculate = true;           /*если добавляем буквы во внутренний контент, который не бьется на строки, то отменяем быстрый пересчет,
                                            т.к. высота контента может поменяться (она рассчитывается точно исходя из размеров внутр элементов)*/

    this.bInline          = false;
    this.Align            = align_Justify;
    this.bEmptyFirstRange = false;
}
CMathRecalculateObject.prototype.Fill = function(StructRecalc)
{
    this.bFastRecalculate = StructRecalc.bFastRecalculate;
    this.bInline          = StructRecalc.bInline;
    this.Align            = StructRecalc.Align;

    var PageInfo          = StructRecalc.PageInfo;

    this.WrapState        = PageInfo.GetCurrentWrapState();
    this.MaxW             = PageInfo.GetCurrentMaxWidthAllLines();
    this.bWordLarge       = PageInfo.GetCurrentStateWordLarge();

    this.bEmptyFirstRange = StructRecalc.bEmptyFirstRange;
};
CMathRecalculateObject.prototype.Load_MathInfo = function(PageInfo)
{
    PageInfo.SetCurrentWrapState(this.WrapState);

    // текущая MaxW и MaxW в PageInfo это не одно и то же
    //PageInfo.SetCurrentMaxWidth(this.MaxW);
};
CMathRecalculateObject.prototype.Compare = function(PageInfo)
{
    var result = true;

    if(this.bFastRecalculate == false)
        result = false;

    if(this.WrapState !== PageInfo.GetCurrentWrapState())
        result = false;

    if(this.bEmptyFirstRange !== PageInfo.bEmptyFirstRange)
        result = false;

    var DiffMaxW = this.MaxW - PageInfo.GetCurrentMaxWidthAllLines();

    if(DiffMaxW < 0)
        DiffMaxW = -DiffMaxW;

    var LargeComposition = this.bWordLarge == true && true == PageInfo.GetCurrentStateWordLarge();

    if(LargeComposition == false && this.bInline == false && this.Align == align_Justify && DiffMaxW > 0.001)
        result = false;

    return result;
};