/*
 * (c) Copyright Ascensio System SIA 2010-2017
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

"use strict";

// TODO: При расчете таблиц есть один баг, который надо будет поправить в будущем:
//       при разбиении строки на страницы возможен вариант, когда у каких-то ячеек
//       убирается содержимое на первой странице, а у каких-то - нет. В данном случае
//       надо для всех ячеек содержимое переносить на новую страницу(как в Word).

// TODO: Несовсем правильно(всмысле не как в Word) обрабатывается верхнее поле ячеек:
//       особенно это проявляется в таблицах с ненулевым расстоянием между ячейками.

    
// TODO: Оказалось, что параметр "не отрывать от следующего" влияет и на таблицы, если 
//       после параграфа с таким параметром идет таблица. (см. MSFT_FY11Q3_10Q.docx стр. 3)
    
// TODO: Поскольку, расстояния до/после параграфа для первого и последнего параграфов 
//       в ячейке зависит от следующей и предыдущей ячеек, надо включать их в пересчет

// Import
var align_Left = AscCommon.align_Left;
var CMouseMoveData = AscCommon.CMouseMoveData;
var g_oTableId = AscCommon.g_oTableId;
var History = AscCommon.History;

var linerule_AtLeast = Asc.linerule_AtLeast;
var c_oAscError = Asc.c_oAscError;
var c_oAscHAnchor = Asc.c_oAscHAnchor;
var c_oAscXAlign = Asc.c_oAscXAlign;
var c_oAscYAlign = Asc.c_oAscYAlign;
var c_oAscVAnchor = Asc.c_oAscVAnchor;
var c_oAscCellTextDirection = Asc.c_oAscCellTextDirection;
    

var table_Selection_Cell = 0x00; // Селектим целыми ячейками
var table_Selection_Text = 0x01; // Селектим текст внутри текущей ячейки

var table_Selection_Common            = 0x00;
var table_Selection_Border            = 0x01;
var table_Selection_Border_InnerTable = 0x02;

var type_Table = 0x0002;


/**
 * Класс CTable
 * @constructor
 * @extends {CDocumentContentElementBase}
 */
function CTable(DrawingDocument, Parent, Inline, Rows, Cols, TableGrid, bPresentation)
{
	CDocumentContentElementBase.call(this, Parent);

    this.Markup = new AscCommon.CTableMarkup(this);

    this.Inline = Inline;

    this.Lock = new AscCommon.CLock();
    // TODO: Когда у g_oIdCounter будет тоже проверка на TurnOff заменить здесь
    if (false === AscCommon.g_oIdCounter.m_bLoad && true === History.Is_On())
    {
        this.Lock.Set_Type(AscCommon.locktype_Mine, false);
        if (AscCommon.CollaborativeEditing)
            AscCommon.CollaborativeEditing.Add_Unlock2(this);
    }
    
    this.DrawingDocument = null;
    this.LogicDocument   = null;
    
    if ( undefined !== DrawingDocument && null !== DrawingDocument )
    {
        this.DrawingDocument = DrawingDocument;
        this.LogicDocument   = this.DrawingDocument.m_oLogicDocument;
    }
    
    this.CompiledPr =
    {
        Pr         : null,  // Скомпилированный (окончательный стиль)
        NeedRecalc : true   // Нужно ли пересчитать скомпилированный стиль
    };

    this.Pr = new CTablePr();
    this.Pr.TableW = new CTableMeasurement(tblwidth_Auto, 0);

    this.TableGridNeedRecalc = true;
    this.bPresentation = bPresentation === true;

    // TODO: TableLook и TableStyle нужно перемесить в TablePr
    this.TableStyle = (undefined !== this.DrawingDocument && null !== this.DrawingDocument && this.DrawingDocument.m_oLogicDocument && this.DrawingDocument.m_oLogicDocument.Styles ? this.DrawingDocument.m_oLogicDocument.Styles.Get_Default_TableGrid() : null);
    this.TableLook  = new CTableLook(true, true, false, false, true, false);

    this.TableSumGrid  = []; // данный массив будет заполнен после private_RecalculateGrid
    this.TableGrid     = TableGrid ? TableGrid : [];
    this.TableGridCalc = this.private_CopyTableGrid();

    this.RecalcInfo = new CTableRecalcInfo();

    this.Rows = Rows;
    this.Cols = Cols;

    // Массив строк
    this.Content = [];
    for ( var Index = 0; Index < Rows; Index++ )
    {
        this.Content[Index] = new CTableRow( this, Cols, TableGrid );
    }

    this.Internal_ReIndexing(0);

    // Информация о строках (расположение, высота и остальные метрики)
    this.RowsInfo = [];
    this.TableRowsBottom = [];
    this.HeaderInfo =
    {
        Count     : 0, // Количество строк, входящих в заголовок
        H         : 0, // Суммарная высота, занимаемая заголовком
        PageIndex : 0, // Страница, на которой лежит исходный заголовок (либо 0, либо 1)
        Pages     : []
    };

    this.Selection =
    {
        Start    : false,
        Use      : false,
        StartPos :
        {
            Pos        : { Row : 0, Cell : 0 },
            X          : 0,
            Y          : 0,
            PageIndex  : 0,
            MouseEvent : { ClickCount : 1, Type : AscCommon.g_mouse_event_type_down, CtrlKey : false }
        },
        EndPos   :
        {
            Pos        : { Row : 0, Cell : 0 },
            X          : 0,
            Y          : 0,
            PageIndex  : 0,
            MouseEvent : { ClickCount : 1, Type : AscCommon.g_mouse_event_type_down, CtrlKey : false }
        },
        Type     : table_Selection_Text,
        Data     : null,
        Type2    : table_Selection_Common,
        Data2    : null,
        CurRow   : 0  // Специальный параметр, используемый для стрелок вправо/влево
    };

    // this.X_origin - точка, которую нам задали как начальную для рисования таблицы
    // this.X        - фактическая начальная точка для рисования и обсчета таблицы
    this.X_origin = 0;

    this.AllowOverlap = true;

    // Позиция по горизонтали
    this.PositionH =
    {
        RelativeFrom : c_oAscHAnchor.Page, // Относительно чего вычисляем координаты
        Align        : true,               // true : В поле Value лежит тип прилегания, false - в поле Value лежит точное значени
        Value        : c_oAscXAlign.Center //
    };

    this.PositionH_Old = undefined;

    // Позиция по горизонтали
    this.PositionV =
    {
        RelativeFrom : c_oAscVAnchor.Page, // Относительно чего вычисляем координаты
        Align        : true,               // true : В поле Value лежит тип прилегания, false - в поле Value лежит точное значени
        Value        : c_oAscYAlign.Center //
    };

    this.PositionV_Old = undefined;

    // Расстояние до окружающего текста
    this.Distance =
    {
        T : 0,
        B : 0,
        L : 0,
        R : 0
    };

    this.AnchorPosition = new CTableAnchorPosition();
    
    this.Pages    = [];
    this.Pages[0] = new CTablePage(0, 0, 0, 0, 0, 0);

    this.MaxTopBorder = [];
    this.MaxBotBorder = [];
    this.MaxBotMargin = [];

    // Выставляем текущую ячейку
    if ( this.Content.length > 0 )
        this.CurCell = this.Content[0].Get_Cell( 0 );
    else
        this.CurCell = null;

    this.TurnOffRecalc = false;

    this.ApplyToAll = false; // Специальный параметр, используемый в ячейках таблицы.
                             // True, если ячейка попадает в выделение по ячейкам.

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

CTable.prototype = Object.create(CDocumentContentElementBase.prototype);
CTable.prototype.constructor = CTable;

CTable.prototype.GetType = function()
{
	return type_Table;
};
//----------------------------------------------------------------------------------------------------------------------
// Общие функции
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.Get_Theme = function()
{
	return this.Parent.Get_Theme();
};
CTable.prototype.Get_ColorMap = function()
{
	return this.Parent.Get_ColorMap();
};
CTable.prototype.Get_Props = function()
{
	var TablePr = this.Get_CompiledPr(false).TablePr;

	var Pr = {};

	if (tblwidth_Auto === TablePr.TableW.Type)
		Pr.TableWidth = null;
	else if (tblwidth_Mm === TablePr.TableW.Type)
		Pr.TableWidth = TablePr.TableW.W;
	else// if (tblwidth_Pct === TablePr.TableW.Type)
		Pr.TableWidth = -TablePr.TableW.W;

	Pr.AllowOverlap = this.AllowOverlap;

	// Пока у нас во всей таблицы одинаковый Spacing
	Pr.TableSpacing = this.Content[0].Get_CellSpacing();

	Pr.TableDefaultMargins = {
		Left   : TablePr.TableCellMar.Left.W,
		Right  : TablePr.TableCellMar.Right.W,
		Top    : TablePr.TableCellMar.Top.W,
		Bottom : TablePr.TableCellMar.Bottom.W
	};

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		Pr.CellSelect = true;

		var CellMargins    = null;
		var CellMarginFlag = false;

		var Border_left    = null;
		var Border_right   = null;
		var Border_top     = null;
		var Border_bottom  = null;
		var Border_insideH = null;
		var Border_insideV = null;

		var CellShd        = null;
		var CellWidth      = undefined;
		var CellWidthStart = undefined;

		var Prev_row  = -1;
		var bFirstRow = true;

		var VAlign        = null;
		var TextDirection = null;
		var NoWrap        = null;

		for (var Index = 0; Index < this.Selection.Data.length; Index++)
		{
			var Pos          = this.Selection.Data[Index];
			var Row          = this.Content[Pos.Row];
			var Cell         = Row.Get_Cell(Pos.Cell);
			var Cell_borders = Cell.Get_Borders();
			var Cell_margins = Cell.Get_Margins();
			var Cell_shd     = Cell.Get_Shd();
			var Cell_w       = Cell.Get_W();

			if (0 === Index)
			{
				VAlign        = Cell.Get_VAlign();
				TextDirection = Cell.Get_TextDirection();
				NoWrap        = Cell.Get_NoWrap();
			}
			else
			{
				if (VAlign !== Cell.Get_VAlign())
					VAlign = null;

				if (TextDirection !== Cell.Get_TextDirection())
					TextDirection = null;

				if (NoWrap !== Cell.Get_NoWrap())
					NoWrap = null;
			}

			if (0 === Index)
			{
				CellShd = Cell_shd;
			}
			else
			{
				if (null != CellShd && ( CellShd.Value != Cell_shd.Value || CellShd.Color.r != Cell_shd.Color.r || CellShd.Color.g != Cell_shd.Color.g || CellShd.Color.b != Cell_shd.Color.b ))
					CellShd = null;
			}

			if (0 === Index)
			{
				if (tblwidth_Auto === Cell_w.Type)
					CellWidth = null;
				else if (tblwidth_Mm === Cell_w.Type)
					CellWidth = Cell_w.W;
				else// if (tblwidth_Pct === Cell_w.Type)
					CellWidth = -Cell_w.W;

				CellWidthStart = CellWidth;
			}
			else
			{
				var _CellWidth;
				if (tblwidth_Auto === Cell_w.Type)
					_CellWidth = null;
				else if (tblwidth_Mm === Cell_w.Type)
					_CellWidth = Cell_w.W;
				else// if (tblwidth_Pct === Cell_w.Type)
					_CellWidth = -Cell_w.W;

				if ((tblwidth_Auto === Cell_w.Type && null !== CellWidth)
					|| (undefined === CellWidth
					|| null === CellWidth
					|| Math.abs(CellWidth - _CellWidth) > 0.001))
					CellWidth = undefined;
			}

			// Крайняя левая ли данная ячейка в выделении?
			if (0 === Index || this.Selection.Data[Index - 1].Row != Pos.Row)
			{
				if (null === Border_left)
					Border_left = Cell_borders.Left;
				else
					Border_left = this.Internal_CompareBorders2(Border_left, Cell_borders.Left);
			}
			else
			{
				if (null === Border_insideV)
					Border_insideV = Cell_borders.Left;
				else
					Border_insideV = this.Internal_CompareBorders2(Border_insideV, Cell_borders.Left);
			}

			// Крайняя правая ли данная ячейка в выделении?
			if (this.Selection.Data.length - 1 === Index || this.Selection.Data[Index + 1].Row != Pos.Row)
			{
				if (null === Border_right)
					Border_right = Cell_borders.Right;
				else
					Border_right = this.Internal_CompareBorders2(Border_right, Cell_borders.Right);
			}
			else
			{
				if (null === Border_insideV)
					Border_insideV = Cell_borders.Right;
				else
					Border_insideV = this.Internal_CompareBorders2(Border_insideV, Cell_borders.Right);
			}

			if (Prev_row != Pos.Row)
			{
				if (-1 != Prev_row)
					bFirstRow = false;

				if (false === bFirstRow)
				{
					if (null === Border_insideH)
					{
						Border_insideH = Border_bottom;
						Border_insideH = this.Internal_CompareBorders2(Border_insideH, Cell_borders.Top);
					}
					else
					{
						Border_insideH = this.Internal_CompareBorders2(Border_insideH, Border_bottom);
						Border_insideH = this.Internal_CompareBorders2(Border_insideH, Cell_borders.Top);
					}
				}
				else
				{
					if (null === Border_top)
						Border_top = Cell_borders.Top;
				}

				Border_bottom = Cell_borders.Bottom;
				Prev_row      = Pos.Row;
			}
			else
			{
				if (false === bFirstRow)
				{
					if (null === Border_insideH)
						Border_insideH = Cell_borders.Top;
					else
						Border_insideH = this.Internal_CompareBorders2(Border_insideH, Cell_borders.Top);
				}
				else
				{
					if (null === Border_top)
						Border_top = Cell_borders.Top;
					else
						Border_top = this.Internal_CompareBorders2(Border_top, Cell_borders.Top);
				}

				Border_bottom = this.Internal_CompareBorders2(Border_bottom, Cell_borders.Bottom);
			}

			if (true != Cell.Is_TableMargins())
			{
				if (null === CellMargins)
				{
					CellMargins = Common_CopyObj(Cell_margins);
				}
				else
				{
					if (CellMargins.Left.W != Cell_margins.Left.W)
						CellMargins.Left.W = null;

					if (CellMargins.Right.W != Cell_margins.Right.W)
						CellMargins.Right.W = null;

					if (CellMargins.Top.W != Cell_margins.Top.W)
						CellMargins.Top.W = null;

					if (CellMargins.Bottom.W != Cell_margins.Bottom.W)
						CellMargins.Bottom.W = null;
				}
			}
			else
			{
				CellMarginFlag = true;
			}
		}

		Pr.CellsVAlign        = VAlign;
		Pr.CellsTextDirection = TextDirection;
		Pr.CellsNoWrap        = NoWrap;

		if (undefined === CellWidth)
		{
			Pr.CellsWidth         = CellWidthStart;
			Pr.CellsWidthNotEqual = true;
		}
		else
		{
			Pr.CellsWidth         = CellWidthStart;
			Pr.CellsWidthNotEqual = false;
		}


		Pr.CellBorders = {
			Left    : Border_left.Copy(),
			Right   : Border_right.Copy(),
			Top     : Border_top.Copy(),
			Bottom  : Border_bottom.Copy(),
			InsideH : null === Border_insideH ? null : Border_insideH.Copy(),
			InsideV : null === Border_insideV ? null : Border_insideV.Copy()
		};

		if (null === CellShd)
			Pr.CellsBackground = null;
		else
			Pr.CellsBackground = CellShd.Copy();

		if (null === CellMargins)
		{
			Pr.CellMargins = {
				Flag : 0
			};
		}
		else
		{
			var Flag = 2;
			if (true === CellMarginFlag)
				Flag = 1;

			Pr.CellMargins = {
				Left   : CellMargins.Left.W,
				Right  : CellMargins.Right.W,
				Top    : CellMargins.Top.W,
				Bottom : CellMargins.Bottom.W,
				Flag   : Flag
			};
		}
	}
	else
	{
		Pr.CellSelect = false;

		var Cell        = this.CurCell;
		var CellMargins = Cell.Get_Margins();
		var CellBorders = Cell.Get_Borders();
		var CellShd     = Cell.Get_Shd();
		var CellW       = Cell.Get_W();

		if (true === Cell.Is_TableMargins())
		{
			Pr.CellMargins = {
				Flag : 0
			};
		}
		else
		{
			Pr.CellMargins = {
				Left   : CellMargins.Left.W,
				Right  : CellMargins.Right.W,
				Top    : CellMargins.Top.W,
				Bottom : CellMargins.Bottom.W,
				Flag   : 2
			};
		}

		Pr.CellsVAlign        = Cell.Get_VAlign();
		Pr.CellsTextDirection = Cell.Get_TextDirection();
		Pr.CellsNoWrap        = Cell.Get_NoWrap();

		Pr.CellsBackground = CellShd.Copy();

		if (tblwidth_Auto === CellW.Type)
			Pr.CellsWidth = null;
		else if (tblwidth_Mm === CellW.Type)
			Pr.CellsWidth = CellW.W;
		else// if (tblwidth_Pct === CellW.Type)
			Pr.CellsWidth = -CellW.W;

		Pr.CellsWidthNotEqual = false;

		var Spacing = this.Content[0].Get_CellSpacing();

		var Border_left    = null;
		var Border_right   = null;
		var Border_top     = null;
		var Border_bottom  = null;
		var Border_insideH = null;
		var Border_insideV = null;

		var CellShd = null;

		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			var Row         = this.Content[CurRow];
			var Cells_Count = Row.Get_CellsCount();

			for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
			{
				var Cell         = Row.Get_Cell(CurCell);
				var Cell_borders = Cell.Get_Borders();
				var Cell_shd     = Cell.Get_Shd();

				if (0 === CurCell && Cells_Count)
				{
					CellShd = Cell_shd;
				}
				else
				{
					if (null != CellShd && ( CellShd.Value != Cell_shd.Value || CellShd.Color.r != Cell_shd.Color.r || CellShd.Color.g != Cell_shd.Color.g || CellShd.Color.b != Cell_shd.Color.b ))
						CellShd = null;
				}

				// Крайняя левая ли данная ячейка в выделении?
				if (0 === CurCell)
				{
					if (null === Border_left)
						Border_left = Cell_borders.Left;
					else
						Border_left = this.Internal_CompareBorders2(Border_left, Cell_borders.Left);
				}
				else
				{
					if (null === Border_insideV)
						Border_insideV = Cell_borders.Left;
					else
						Border_insideV = this.Internal_CompareBorders2(Border_insideV, Cell_borders.Left);
				}

				// Крайняя правая ли данная ячейка в выделении?
				if (Cells_Count - 1 === CurCell)
				{
					if (null === Border_right)
						Border_right = Cell_borders.Right;
					else
						Border_right = this.Internal_CompareBorders2(Border_right, Cell_borders.Right);
				}
				else
				{
					if (null === Border_insideV)
						Border_insideV = Cell_borders.Right;
					else
						Border_insideV = this.Internal_CompareBorders2(Border_insideV, Cell_borders.Right);
				}

				if (0 === CurCell)
				{
					if (0 != CurRow)
					{
						if (null === Border_insideH)
						{
							Border_insideH = Border_bottom;
							Border_insideH = this.Internal_CompareBorders2(Border_insideH, Cell_borders.Top);
						}
						else
						{
							Border_insideH = this.Internal_CompareBorders2(Border_insideH, Border_bottom);
							Border_insideH = this.Internal_CompareBorders2(Border_insideH, Cell_borders.Top);
						}
					}
					else
					{
						if (null === Border_top)
							Border_top = Cell_borders.Top;
					}

					Border_bottom = Cell_borders.Bottom;
				}
				else
				{
					if (0 != CurRow)
					{
						if (null === Border_insideH)
							Border_insideH = Cell_borders.Top;
						else
							Border_insideH = this.Internal_CompareBorders2(Border_insideH, Cell_borders.Top);
					}
					else
					{
						if (null === Border_top)
							Border_top = Cell_borders.Top;
						else
							Border_top = this.Internal_CompareBorders2(Border_top, Cell_borders.Top);
					}

					Border_bottom = this.Internal_CompareBorders2(Border_bottom, Cell_borders.Bottom);
				}
			}
		}

		Pr.CellBorders = {
			Left    : Border_left.Copy(),
			Right   : Border_right.Copy(),
			Top     : Border_top.Copy(),
			Bottom  : Border_bottom.Copy(),
			InsideH : null === Border_insideH ? null : Border_insideH.Copy(),
			InsideV : null === Border_insideV ? null : Border_insideV.Copy()
		};
	}

	switch (Pr.CellsVAlign)
	{
		case vertalignjc_Top    :
			Pr.CellsVAlign = c_oAscVertAlignJc.Top;
			break;
		case vertalignjc_Bottom :
			Pr.CellsVAlign = c_oAscVertAlignJc.Bottom;
			break;
		case vertalignjc_Center :
			Pr.CellsVAlign = c_oAscVertAlignJc.Center;
			break;
		default                 :
			Pr.CellsVAlign = null;
			break;
	}

	switch (Pr.CellsTextDirection)
	{
		case textdirection_LRTB  :
			Pr.CellsTextDirection = c_oAscCellTextDirection.LRTB;
			break;
		case textdirection_TBRL  :
			Pr.CellsTextDirection = c_oAscCellTextDirection.TBRL;
			break;
		case textdirection_BTLR  :
			Pr.CellsTextDirection = c_oAscCellTextDirection.BTLR;
			break;
		default                  :
			Pr.CellsTextDirection = null;
			break;
	}

	Pr.RowsInHeader = 0;
	for (var Index = 0; Index < this.Content.length; Index++)
	{
		if (true === this.Content[Index].Is_Header())
			Pr.RowsInHeader++;
	}

	if (true === this.Is_Inline())
	{
		Pr.TableAlignment     = ( align_Left === TablePr.Jc ? 0 : ( AscCommon.align_Center === TablePr.Jc ? 1 : 2 ) );
		Pr.TableIndent        = TablePr.TableInd;
		Pr.TableWrappingStyle = AscCommon.c_oAscWrapStyle.Inline;

		Pr.Position = {
			X : this.X,
			Y : this.Y
		};

		Pr.TablePaddings = {
			Top    : 0,
			Bottom : 0,
			Left   : 3.2,
			Right  : 3.2
		};
	}
	else
	{
		var LD_PageFields = this.LogicDocument.Get_PageFields(this.Get_StartPage_Absolute());

		Pr.TableAlignment     = 0; // align_Left
		Pr.TableIndent        = this.X_origin - LD_PageFields.X;
		Pr.TableWrappingStyle = AscCommon.c_oAscWrapStyle.Flow;

		Pr.PositionH              = {};
		Pr.PositionH.RelativeFrom = this.PositionH.RelativeFrom;
		Pr.PositionH.UseAlign     = this.PositionH.Align;
		Pr.PositionH.Align        = ( true === Pr.PositionH.UseAlign ? this.PositionH.Value : undefined );
		Pr.PositionH.Value        = ( true === Pr.PositionH.UseAlign ? 0 : this.PositionH.Value );

		Pr.PositionV              = {};
		Pr.PositionV.RelativeFrom = this.PositionV.RelativeFrom;
		Pr.PositionV.UseAlign     = this.PositionV.Align;
		Pr.PositionV.Align        = ( true === Pr.PositionV.UseAlign ? this.PositionV.Value : undefined );
		Pr.PositionV.Value        = ( true === Pr.PositionV.UseAlign ? 0 : this.PositionV.Value );

		Pr.Position = {
			X : this.Parent.X,
			Y : this.Parent.Y
		};

		Pr.TablePaddings = {
			Left   : this.Distance.L,
			Right  : this.Distance.R,
			Top    : this.Distance.T,
			Bottom : this.Distance.B
		};
	}

	Pr.Internal_Position = this.AnchorPosition;

	Pr.TableBorders = Common_CopyObj(TablePr.TableBorders);

	Pr.TableBackground = TablePr.Shd.Copy();

	Pr.TableStyle = this.TableStyle;
	Pr.TableLook  = this.TableLook;

	if (true === this.Parent.Is_DrawingShape())
		Pr.CanBeFlow = false;
	else
		Pr.CanBeFlow = true;

	Pr.Locked = this.Lock.Is_Locked();

	if (true === this.Parent.Is_InTable())
		Pr.TableLayout = undefined;
	else
		Pr.TableLayout = (TablePr.TableLayout === tbllayout_AutoFit ? c_oAscTableLayout.AutoFit : c_oAscTableLayout.Fixed );

	if (!this.bPresentation)
	{
		this.DrawingDocument.CheckTableStyles(new Asc.CTablePropLook(this.TableLook));
	}

	Pr.PercentFullWidth = this.private_RecalculatePercentWidth();
	Pr.TableDescription = this.Get_TableDescription();
	Pr.TableCaption     = this.Get_TableCaption();

	return Pr;
};
CTable.prototype.Set_Props = function(Props)
{
	var TablePr            = this.Get_CompiledPr(false).TablePr;
	var bApplyToInnerTable = false;

	if (true != this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
	{
		bApplyToInnerTable = this.CurCell.Content.SetTableProps(Props);
	}

	if (true === bApplyToInnerTable)
		return true;

	var bRecalc_All = false;
	var bRedraw     = false;

	// TableStyle (стиль таблицы)
	if (undefined !== Props.TableStyle)
	{
		this.Set_TableStyle(Props.TableStyle);
		bRecalc_All = true;
	}

	// TableLook
	if ("undefined" != typeof(Props.TableLook))
	{
		var NewLook = new CTableLook(Props.TableLook.FirstCol, Props.TableLook.FirstRow, Props.TableLook.LastCol, Props.TableLook.LastRow, Props.TableLook.BandHor, Props.TableLook.BandVer);
		this.Set_TableLook(NewLook);
		bRecalc_All = true;
	}

	// AllowOverlap
	if (undefined != Props.AllowOverlap)
	{
		this.Set_AllowOverlap(Props.AllowOverlap);
		bRecalc_All = true;
	}

	// RowsInHeader
	if (undefined != Props.RowsInHeader)
	{
		var RowsInHeader = Props.RowsInHeader
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			if (Index < RowsInHeader && true != this.Content[Index].Is_Header())
				this.Content[Index].Set_Header(true);
			else if (Index >= RowsInHeader && true === this.Content[Index].Is_Header())
				this.Content[Index].Set_Header(false);
		}
	}

	// TableSpacing (расстояние между ячейками)
	if ("undefined" != typeof(Props.TableSpacing))
	{
		var NeedChange = false;
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			if (Props.TableSpacing != this.Content[Index].Get_CellSpacing())
			{
				NeedChange = true;
				break;
			}
		}

		if (true === NeedChange)
		{
			var OldSpacing = this.Content[0].Get_CellSpacing();
			var Diff       = Props.TableSpacing - ( null === OldSpacing ? 0 : OldSpacing );

			for (var Index = 0; Index < this.Content.length; Index++)
				this.Content[Index].Set_CellSpacing(Props.TableSpacing);

			bRecalc_All = true;

			// При изменении Spacing мы должны изменить сетку таблицы
			var GridKoeff = [];
			var ColsCount = this.TableGridCalc.length;
			for (var Index = 0; Index < ColsCount; Index++)
				GridKoeff.push(1);

			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row        = this.Content[CurRow];
				var GridBefore = Row.Get_Before().GridBefore;
				var GridAfter  = Row.Get_After().GridAfter;

				GridKoeff[Math.min(GridBefore, GridKoeff.length - 1)]    = 1.5;
				GridKoeff[Math.max(GridKoeff.length - 1 - GridAfter, 0)] = 1.5;
			}

			var arrNewGrid = [];
			for (var Index = 0; Index < ColsCount; Index++)
			{
				arrNewGrid[Index] = this.TableGridCalc[Index] + GridKoeff[Index] * Diff;
			}
			this.SetTableGrid(arrNewGrid);
		}
	}

	// Определим, есть ли у таблицы Spacing, уже с учетом новых настроек
	var bSpacing = null === this.Content[0].Get_CellSpacing() ? false : true;

	// TableDefaultMargins (отступы в ячейках по умолчанию)
	if ("undefined" != typeof(Props.TableDefaultMargins))
	{
		var UsingDefaultMar = false;
		for (var Index = 0; Index < this.Content.length; Index++)
		{
			var Row        = this.Content[Index];
			var CellsCount = Row.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell = Row.Get_Cell(CurCell);
				if (null === Cell.Pr.TableCellMar)
				{
					UsingDefaultMar = true;
					break;
				}
			}
		}

		var NeedChange = false;

		var TDM        = Props.TableDefaultMargins;
		var Left_new   = ( "undefined" != typeof(TDM.Left) ? ( null != TDM.Left ? TDM.Left : TablePr.TableCellMar.Left.W   ) : TablePr.TableCellMar.Left.W   );
		var Right_new  = ( "undefined" != typeof(TDM.Right) ? ( null != TDM.Right ? TDM.Right : TablePr.TableCellMar.Right.W  ) : TablePr.TableCellMar.Right.W  );
		var Top_new    = ( "undefined" != typeof(TDM.Top) ? ( null != TDM.Top ? TDM.Top : TablePr.TableCellMar.Top.W    ) : TablePr.TableCellMar.Top.W    );
		var Bottom_new = ( "undefined" != typeof(TDM.Bottom) ? ( null != TDM.Bottom ? TDM.Bottom : TablePr.TableCellMar.Bottom.W ) : TablePr.TableCellMar.Bottom.W );

		if (Left_new != TablePr.TableCellMar.Left.W || Right_new != TablePr.TableCellMar.Right.W || Top_new != TablePr.TableCellMar.Top.W || Bottom_new != TablePr.TableCellMar.Bottom.W)
			NeedChange = true;

		if (true === NeedChange)
		{
			this.Set_TableCellMar(Left_new, Top_new, Right_new, Bottom_new);

			if (true === UsingDefaultMar)
			{
				bRecalc_All = true;
			}
		}
	}

	// CellMargins (отступы в ячейках)
	if ("undefined" != typeof(Props.CellMargins) && null != Props.CellMargins)
	{
		var NeedChange = false;

		switch (Props.CellMargins.Flag)
		{
			case 0:
			{
				if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
				{
					for (var Index = 0; Index < this.Selection.Data.length; Index++)
					{
						var Pos  = this.Selection.Data[Index];
						var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);

						if (null != Cell.Pr.TableCellMar)
						{
							Cell.Set_Margins(null);
							NeedChange = true;
						}
					}
				}
				else
				{
					var Cell = this.CurCell;

					if (null != Cell.Pr.TableCellMar)
					{
						Cell.Set_Margins(null);
						NeedChange = true;
					}
				}

				break;
			}
			case 1:
			{
				if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
				{
					for (var Index = 0; Index < this.Selection.Data.length; Index++)
					{
						var Pos  = this.Selection.Data[Index];
						var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);

						// Ячейки, у которых маргины дефелтовые, мы не трогаем
						if (true != Cell.Is_TableMargins())
						{
							if (null != Props.CellMargins.Left)
								Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);

							if (null != Props.CellMargins.Right)
								Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);

							if (null != Props.CellMargins.Top)
								Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);

							if (null != Props.CellMargins.Bottom)
								Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);

							NeedChange = true;
						}
					}
				}
				else
				{
					// Сюда вообще не должны заходить, но на всякий случай реализуем.
					var Cell = this.CurCell;
					if (true != Cell.Is_TableMargins())
					{
						if (null != Props.CellMargins.Left)
							Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);

						if (null != Props.CellMargins.Right)
							Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);

						if (null != Props.CellMargins.Top)
							Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);

						if (null != Props.CellMargins.Bottom)
							Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);
					}
					else
					{
						if (null != Props.CellMargins.Left)
							Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Left.W, Type : tblwidth_Mm}, 3);

						if (null != Props.CellMargins.Right)
							Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Right.W, Type : tblwidth_Mm}, 1);

						if (null != Props.CellMargins.Top)
							Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Top.W, Type : tblwidth_Mm}, 0);

						if (null != Props.CellMargins.Bottom)
							Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Bottom.W, Type : tblwidth_Mm}, 2);
					}

					NeedChange = true;
				}

				break;
			}
			case 2:
			{
				NeedChange = true;

				if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
				{
					for (var Index = 0; Index < this.Selection.Data.length; Index++)
					{
						var Pos  = this.Selection.Data[Index];
						var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);

						// Ячейки, у которых маргины дефелтовые, мы не трогаем
						if (true != Cell.Is_TableMargins())
						{
							if (null != Props.CellMargins.Left)
								Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);

							if (null != Props.CellMargins.Right)
								Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);

							if (null != Props.CellMargins.Top)
								Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);

							if (null != Props.CellMargins.Bottom)
								Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);
						}
						else
						{
							if (null != Props.CellMargins.Left)
								Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);
							else
								Cell.Set_Margins({W : TablePr.TableCellMar.Left.W, Type : tblwidth_Mm}, 3);

							if (null != Props.CellMargins.Right)
								Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);
							else
								Cell.Set_Margins({W : TablePr.TableCellMar.Right.W, Type : tblwidth_Mm}, 1);

							if (null != Props.CellMargins.Top)
								Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);
							else
								Cell.Set_Margins({W : TablePr.TableCellMar.Top.W, Type : tblwidth_Mm}, 0);

							if (null != Props.CellMargins.Bottom)
								Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);
							else
								Cell.Set_Margins({W : TablePr.TableCellMar.Bottom.W, Type : tblwidth_Mm}, 2);
						}
					}
				}
				else
				{
					var Cell = this.CurCell;
					if (true != Cell.Is_TableMargins())
					{
						if (null != Props.CellMargins.Left)
							Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);

						if (null != Props.CellMargins.Right)
							Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);

						if (null != Props.CellMargins.Top)
							Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);

						if (null != Props.CellMargins.Bottom)
							Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);
					}
					else
					{
						if (null != Props.CellMargins.Left)
							Cell.Set_Margins({W : Props.CellMargins.Left, Type : tblwidth_Mm}, 3);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Left.W, Type : tblwidth_Mm}, 3);

						if (null != Props.CellMargins.Right)
							Cell.Set_Margins({W : Props.CellMargins.Right, Type : tblwidth_Mm}, 1);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Right.W, Type : tblwidth_Mm}, 1);

						if (null != Props.CellMargins.Top)
							Cell.Set_Margins({W : Props.CellMargins.Top, Type : tblwidth_Mm}, 0);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Top.W, Type : tblwidth_Mm}, 0);

						if (null != Props.CellMargins.Bottom)
							Cell.Set_Margins({W : Props.CellMargins.Bottom, Type : tblwidth_Mm}, 2);
						else
							Cell.Set_Margins({W : TablePr.TableCellMar.Bottom.W, Type : tblwidth_Mm}, 2);
					}

					NeedChange = true;
				}

				break;
			}
		}

		if (true === NeedChange)
			bRecalc_All = true;
	}

	// TableWidth (ширина таблицы)
	if (undefined !== Props.TableWidth)
	{
		if (null === Props.TableWidth)
		{
			if (tblwidth_Auto != TablePr.TableW.Type)
			{
				this.Set_TableW(tblwidth_Auto, 0);
				bRecalc_All = true;
			}
		}
		else if (Props.TableWidth > -0.001)
		{
			this.Set_TableW(tblwidth_Mm, Props.TableWidth);
			bRecalc_All = true;
		}
		else
		{
			this.Set_TableW(tblwidth_Pct, Math.abs(Props.TableWidth));
			bRecalc_All = true;
		}
	}

	// TableLayout
	if (undefined != Props.TableLayout)
	{
		this.Set_TableLayout(( Props.TableLayout === c_oAscTableLayout.AutoFit ? tbllayout_AutoFit : tbllayout_Fixed ));
		bRecalc_All = true;
	}

	// TableWrappingStyle
	if (undefined != Props.TableWrappingStyle)
	{
		// При изменении flow на inline или наоборот, пересчет таблицы будет запущен позже
		if (0 === Props.TableWrappingStyle && true != this.Inline)
		{
			this.Set_Inline(true);
			bRecalc_All = true;
		}
		else if (1 === Props.TableWrappingStyle && false != this.Inline)
		{
			this.Set_Inline(false);

			if (undefined === Props.PositionH)
				this.Set_PositionH(c_oAscHAnchor.Page, false, this.AnchorPosition.Calculate_X_Value(c_oAscHAnchor.Page));

			if (undefined === Props.PositionV)
				this.Set_PositionV(c_oAscVAnchor.Page, false, this.AnchorPosition.Calculate_Y_Value(c_oAscVAnchor.Page));

			if (undefined === Props.TablePaddings)
				this.Set_Distance(3.2, 0, 3.2, 0);

			bRecalc_All = true;
		}
	}

	var _Jc = TablePr.Jc; // Запоминаем, чтобы не пересчитывать стиль
	// TableAlignment (прилегание таблицы)
	if ("undefined" != typeof(Props.TableAlignment) && true === this.Is_Inline())
	{
		var NewJc = ( 0 === Props.TableAlignment ? align_Left : ( 1 === Props.TableAlignment ? AscCommon.align_Center : AscCommon.align_Right ) );
		if (TablePr.Jc != NewJc)
		{
			_Jc = NewJc;
			this.Set_TableAlign(NewJc);
			bRecalc_All = true;
		}
	}

	// TableIndent (отступ слева)
	if ("undefined" != typeof(Props.TableIndent) && true === this.Is_Inline() && align_Left === _Jc)
	{
		if (Props.TableIndent != TablePr.TableInd)
		{
			this.Set_TableInd(Props.TableIndent);
			bRecalc_All = true;
		}
	}

	// Position
	if (undefined != Props.Position)
	{
		this.PositionH.RelativeFrom = c_oAscHAnchor.Page;
		this.PositionH.Align        = true;
		this.PositionV.RelativeFrom = c_oAscVAnchor.Page;
		this.PositionH.Align        = true;

		this.PositionH.Value = c_oAscXAlign.Center;
		this.PositionV.Value = c_oAscYAlign.Center;

		//this.PositionH.Value        = ( "undefined" != typeof(Props.Position.X) ? ( null != Props.Position.X ?
		// Props.Position.X : this.X ) : this.X ); this.PositionV.Value        = ( "undefined" !=
		// typeof(Props.Position.Y) ? ( null != Props.Position.Y ? Props.Position.Y : this.Y ) : this.Y );

		bRecalc_All = true;
	}

	if (undefined != Props.PositionH)
	{
		this.Set_PositionH(Props.PositionH.RelativeFrom, Props.PositionH.UseAlign, (true === Props.PositionH.UseAlign) ? Props.PositionH.Align : Props.PositionH.Value);
	}

	if (undefined != Props.PositionV)
	{
		this.Set_PositionV(Props.PositionV.RelativeFrom, Props.PositionV.UseAlign, (true === Props.PositionV.UseAlign) ? Props.PositionV.Align : Props.PositionV.Value);
	}

	// TablePaddings
	if (undefined != Props.TablePaddings)
	{
		var TP          = Props.TablePaddings;
		var CurPaddings = this.Distance;

		var NewPaggings_left   = ( undefined != TP.Left ? ( null != TP.Left ? TP.Left : CurPaddings.L ) : CurPaddings.L );
		var NewPaggings_right  = ( undefined != TP.Right ? ( null != TP.Right ? TP.Right : CurPaddings.R ) : CurPaddings.R );
		var NewPaggings_top    = ( undefined != TP.Top ? ( null != TP.Top ? TP.Top : CurPaddings.T ) : CurPaddings.T );
		var NewPaggings_bottom = ( undefined != TP.Bottom ? ( null != TP.Bottom ? TP.Bottom : CurPaddings.B ) : CurPaddings.B );

		if (Math.abs(CurPaddings.L - NewPaggings_left) > 0.001 || Math.abs(CurPaddings.R - NewPaggings_right) > 0.001 || Math.abs(CurPaddings.T - NewPaggings_top) > 0.001 || Math.abs(CurPaddings.B - NewPaggings_bottom) > 0.001)
		{
			this.Set_Distance(NewPaggings_left, NewPaggings_top, NewPaggings_right, NewPaggings_bottom);
			bRecalc_All = true;
		}
	}

	// TableBorders(границы таблицы)
	if ("undefined" != typeof(Props.TableBorders) && null != Props.TableBorders)
	{
		if (false === this.Internal_CheckNullBorder(Props.TableBorders.Top) && false === this.Internal_CompareBorders3(Props.TableBorders.Top, TablePr.TableBorders.Top))
		{
			this.Set_TableBorder_Top(Props.TableBorders.Top);
			bRecalc_All = true;

			if (true != bSpacing)
			{
				var Row = this.Content[0];
				for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
				{
					var Cell = Row.Get_Cell(CurCell);
					Cell.Set_Border(null, 0);
				}
			}
		}

		if (false === this.Internal_CheckNullBorder(Props.TableBorders.Bottom) && false === this.Internal_CompareBorders3(Props.TableBorders.Bottom, TablePr.TableBorders.Bottom))
		{
			this.Set_TableBorder_Bottom(Props.TableBorders.Bottom);
			bRecalc_All = true;

			if (true != bSpacing)
			{
				var Row = this.Content[this.Content.length - 1];
				for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
				{
					var Cell = Row.Get_Cell(CurCell);
					Cell.Set_Border(null, 2);
				}
			}
		}

		if (false === this.Internal_CheckNullBorder(Props.TableBorders.Left) && false === this.Internal_CompareBorders3(Props.TableBorders.Left, TablePr.TableBorders.Left))
		{
			this.Set_TableBorder_Left(Props.TableBorders.Left);
			bRecalc_All = true;

			if (true != bSpacing)
			{
				for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
				{
					var Cell = this.Content[CurRow].Get_Cell(0);
					Cell.Set_Border(null, 3);
				}
			}
		}

		if (false === this.Internal_CheckNullBorder(Props.TableBorders.Right) && false === this.Internal_CompareBorders3(Props.TableBorders.Right, TablePr.TableBorders.Right))
		{
			this.Set_TableBorder_Right(Props.TableBorders.Right);
			bRecalc_All = true;

			if (true != bSpacing)
			{
				for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
				{
					var Cell = this.Content[CurRow].Get_Cell(this.Content[CurRow].Get_CellsCount() - 1);
					Cell.Set_Border(null, 1);
				}
			}
		}

		if (false === this.Internal_CheckNullBorder(Props.TableBorders.InsideH) && false === this.Internal_CompareBorders3(Props.TableBorders.InsideH, TablePr.TableBorders.InsideH))
		{
			this.Set_TableBorder_InsideH(Props.TableBorders.InsideH);
			bRecalc_All = true;

			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row         = this.Content[CurRow];
				var Cells_Count = Row.Get_CellsCount();

				for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
				{
					var Cell = Row.Get_Cell(CurCell);

					if ((0 === CurRow && true === bSpacing) || 0 != CurRow)
						Cell.Set_Border(null, 0);

					if (( this.Content.length - 1 === CurRow && true === bSpacing ) || this.Content.length - 1 != CurRow)
						Cell.Set_Border(null, 2);

				}
			}
		}

		if (false === this.Internal_CheckNullBorder(Props.TableBorders.InsideV) && false === this.Internal_CompareBorders3(Props.TableBorders.InsideV, TablePr.TableBorders.InsideV))
		{
			this.Set_TableBorder_InsideV(Props.TableBorders.InsideV);
			bRecalc_All = true;

			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row         = this.Content[CurRow];
				var Cells_Count = Row.Get_CellsCount();

				for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
				{
					var Cell = Row.Get_Cell(CurCell);

					if ((0 === CurCell && true === bSpacing) || 0 != CurCell)
						Cell.Set_Border(null, 3);

					if (( Cells_Count - 1 === CurCell && true === bSpacing ) || Cells_Count - 1 != CurCell)
						Cell.Set_Border(null, 1);
				}
			}
		}
	}

	// CellBorders (границы ячеек)
	if ("undefined" != typeof(Props.CellBorders) && null != Props.CellBorders)
	{
		var Cells_array = null;

		// Переделаем идеальный вариант, на новый
		if (true === bSpacing)
		{
			if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
			{
				Cells_array = [];
				for (var Index = 0, Count = this.Selection.Data.length; Index < Count; Index++)
				{
					var RowIndex  = this.Selection.Data[Index].Row;
					var CellIndex = this.Selection.Data[Index].Cell;

					var StartGridCol    = this.Content[RowIndex].Get_CellInfo(CellIndex).StartGridCol;
					var GridSpan        = this.Content[RowIndex].Get_Cell(CellIndex).Get_GridSpan();
					var TempCells_array = this.private_GetCellsPosArrayByCellsArray(this.private_GetMergedCells(RowIndex, StartGridCol, GridSpan));
					Cells_array         = Cells_array.concat(TempCells_array);
				}
			}
			else if (false === Props.CellSelect)
			{
				Cells_array = [];
				for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
				{
					var Row         = this.Content[CurRow];
					var Cells_count = Row.Get_CellsCount();
					for (var CurCell = 0; CurCell < Cells_count; CurCell++)
					{
						var Cell = Row.Get_Cell(CurCell);
						if (vmerge_Continue === Cell.Get_VMerge())
							continue;

						var StartGridCol    = this.Content[CurRow].Get_CellInfo(CurCell).StartGridCol;
						var GridSpan        = this.Content[CurRow].Get_Cell(CurCell).Get_GridSpan();
						var TempCells_array = this.private_GetCellsPosArrayByCellsArray(this.private_GetMergedCells(CurRow, StartGridCol, GridSpan));

						Cells_array = Cells_array.concat(TempCells_array);
					}
				}
			}
			else
			{
				var RowIndex     = this.CurCell.Row.Index;
				var CellIndex    = this.CurCell.Index;
				var StartGridCol = this.Content[RowIndex].Get_CellInfo(CellIndex).StartGridCol;
				var GridSpan     = this.Content[RowIndex].Get_Cell(CellIndex).Get_GridSpan();
				Cells_array      = this.private_GetCellsPosArrayByCellsArray(this.private_GetMergedCells(RowIndex, StartGridCol, GridSpan));
			}
		}
		else
		{
			if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
			{
				Cells_array = [];
				for (var Index = 0, Count = this.Selection.Data.length; Index < Count; Index++)
				{
					var RowIndex  = this.Selection.Data[Index].Row;
					var CellIndex = this.Selection.Data[Index].Cell;

					var StartGridCol    = this.Content[RowIndex].Get_CellInfo(CellIndex).StartGridCol;
					var GridSpan        = this.Content[RowIndex].Get_Cell(CellIndex).Get_GridSpan();
					var TempCells_array = this.private_GetCellsPosArrayByCellsArray(this.private_GetMergedCells(RowIndex, StartGridCol, GridSpan));
					Cells_array         = Cells_array.concat(TempCells_array);
				}
			}
			else
			{
				var RowIndex     = this.CurCell.Row.Index;
				var CellIndex    = this.CurCell.Index;
				var StartGridCol = this.Content[RowIndex].Get_CellInfo(CellIndex).StartGridCol;
				var GridSpan     = this.Content[RowIndex].Get_Cell(CellIndex).Get_GridSpan();
				Cells_array      = this.private_GetCellsPosArrayByCellsArray(this.private_GetMergedCells(RowIndex, StartGridCol, GridSpan));
			}
		}

		//if ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type )
		//    Cells_array = this.Selection.Data;
		//else
		//{
		//    // TODO: Если данная ячейка имеет вертикальное объединение, тогда нам надо добавить
		//    //       все ячейки в него попадающие
		//    Cells_array = [ { Row : this.CurCell.Row.Index, Cell : this.CurCell.Index } ];
		//}

		var Pos_first = Cells_array[0];
		var Pos_last  = Cells_array[Cells_array.length - 1];
		var Row_first = Pos_first.Row;
		var Row_last  = Pos_last.Row;

		var bBorder_top     = ( false === this.Internal_CheckNullBorder(Props.CellBorders.Top) ? true : false );
		var bBorder_bottom  = ( false === this.Internal_CheckNullBorder(Props.CellBorders.Bottom) ? true : false );
		var bBorder_left    = ( false === this.Internal_CheckNullBorder(Props.CellBorders.Left) ? true : false );
		var bBorder_right   = ( false === this.Internal_CheckNullBorder(Props.CellBorders.Right) ? true : false );
		var bBorder_insideh = ( false === this.Internal_CheckNullBorder(Props.CellBorders.InsideH) ? true : false );
		var bBorder_insidev = ( false === this.Internal_CheckNullBorder(Props.CellBorders.InsideV) ? true : false );

		if (true != bSpacing)
		{
			// Узначем GridCol начала и конца первой и последней строк
			var Grid_row_first_start = 0, Grid_row_first_end = 0, Grid_row_last_start = 0, Grid_row_last_end = 0;
			var Pos                  = {Row : 0, Cell : 0};

			var CurRow           = Row_first;
			var Index            = 0;
			Grid_row_first_start = this.Content[Pos_first.Row].Get_CellInfo(Pos_first.Cell).StartGridCol;
			while (Index < Cells_array.length)
			{
				Pos = Cells_array[Index];
				if (Pos.Row != Row_first)
					break;

				var Row  = this.Content[Pos.Row];
				var Cell = Row.Get_Cell(Pos.Cell);

				Grid_row_first_end = Row.Get_CellInfo(Pos.Cell).StartGridCol + Cell.Get_GridSpan() - 1;
				Index++;
			}

			Index = 0;
			while (Index < Cells_array.length)
			{
				Pos = Cells_array[Index];
				if (Pos.Row === Row_last)
					break;

				Index++;
			}

			Grid_row_last_start = this.Content[Pos.Row].Get_CellInfo(Pos.Cell).StartGridCol;
			Grid_row_last_end   = this.Content[Pos_last.Row].Get_CellInfo(Pos_last.Cell).StartGridCol + this.Content[Pos_last.Row].Get_Cell(Pos_last.Cell).Get_GridSpan() - 1;

			if (Row_first > 0 && true === bBorder_top)
			{
				var Cell_start = 0, Cell_end = 0;
				var bStart     = false;
				var bEnd       = false;

				var Row = this.Content[Row_first - 1];
				for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
				{
					var StartGridCol = Row.Get_CellInfo(CurCell).StartGridCol;
					var EndGridCol   = StartGridCol + Row.Get_Cell(CurCell).Get_GridSpan() - 1;

					if (false === bStart)
					{
						if (StartGridCol < Grid_row_first_start)
							continue;
						else if (StartGridCol > Grid_row_first_start)
							break;
						else //if ( StartGridCol === Grid_row_first_start )
						{
							Cell_start = CurCell;
							bStart     = true;

							if (EndGridCol < Grid_row_first_end)
								continue;
							else if (EndGridCol > Grid_row_first_end)
								break;
							else
							{
								Cell_end = CurCell;
								bEnd     = true;
								break;
							}
						}
					}

					if (false === bEnd)
					{
						if (EndGridCol < Grid_row_first_end)
							continue;
						else if (EndGridCol > Grid_row_first_end)
							break;
						else //if ( EndGridCol === Grid_row_first_end )
						{
							Cell_end = CurCell;
							bEnd     = true;
							break;
						}
					}
				}

				if (true === bStart && true === bEnd)
				{
					for (var CurCell = Cell_start; CurCell <= Cell_end; CurCell++)
					{
						var Cell = Row.Get_Cell(CurCell);
						Cell.Set_Border(Props.CellBorders.Top, 2);
					}
					bRecalc_All = true;
				}
			}

			if (Row_last < this.Content.length - 1 && true === bBorder_bottom)
			{
				var Cell_start = 0, Cell_end = 0;
				var bStart     = false;
				var bEnd       = false;

				var Row = this.Content[Row_last + 1];
				for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
				{
					var StartGridCol = Row.Get_CellInfo(CurCell).StartGridCol;
					var EndGridCol   = StartGridCol + Row.Get_Cell(CurCell).Get_GridSpan() - 1;

					if (false === bStart)
					{
						if (StartGridCol < Grid_row_last_start)
							continue;
						else if (StartGridCol > Grid_row_last_start)
							break;
						else //if ( StartGridCol === Grid_row_last_start )
						{
							Cell_start = CurCell;
							bStart     = true;

							if (EndGridCol < Grid_row_last_end)
								continue;
							else if (EndGridCol > Grid_row_last_end)
								break;
							else
							{
								Cell_end = CurCell;
								bEnd     = true;
								break;
							}
						}
					}

					if (false === bEnd)
					{
						if (EndGridCol < Grid_row_last_end)
							continue;
						else if (EndGridCol > Grid_row_last_end)
							break;
						else //if ( EndGridCol === Grid_row_last_end )
						{
							Cell_end = CurCell;
							bEnd     = true;
							break;
						}
					}
				}

				if (true === bStart && true === bEnd)
				{
					for (var CurCell = Cell_start; CurCell <= Cell_end; CurCell++)
					{
						var Cell = Row.Get_Cell(CurCell);
						Cell.Set_Border(Props.CellBorders.Bottom, 0);
					}
					bRecalc_All = true;
				}
			}
		}

		var PrevRow    = Row_first;
		var Cell_start = Pos_first.Cell, Cell_end = Pos_first.Cell;
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos = Cells_array[Index];
			Row     = this.Content[Pos.Row];
			Cell    = Row.Get_Cell(Pos.Cell);

			if (PrevRow != Pos.Row)
			{
				var Row_temp = this.Content[PrevRow];

				if (true != bSpacing && Cell_start > 0 && true === bBorder_left)
				{
					Row_temp.Get_Cell(Cell_start - 1).Set_Border(Props.CellBorders.Left, 1);
					bRecalc_All = true;
				}

				if (true != bSpacing && Cell_end < Row_temp.Get_CellsCount() - 1 && true === bBorder_right)
				{
					Row_temp.Get_Cell(Cell_end + 1).Set_Border(Props.CellBorders.Right, 3);
					bRecalc_All = true;
				}

				for (var CurCell = Cell_start; CurCell <= Cell_end; CurCell++)
				{
					var Cell_temp = Row_temp.Get_Cell(CurCell);

					if (Row_first === PrevRow && true === bBorder_top)
					{
						Cell_temp.Set_Border(Props.CellBorders.Top, 0);
						bRecalc_All = true;
					}
					else if (Row_first != PrevRow && true === bBorder_insideh)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideH, 0);
						bRecalc_All = true;
					}

					if (Row_last === PrevRow && true === bBorder_bottom)
					{
						Cell_temp.Set_Border(Props.CellBorders.Bottom, 2);
						bRecalc_All = true;
					}
					else if (Row_last != PrevRow && true === bBorder_insideh)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideH, 2);
						bRecalc_All = true;
					}

					if (CurCell === Cell_start && true === bBorder_left)
					{
						Cell_temp.Set_Border(Props.CellBorders.Left, 3);
						bRecalc_All = true;
					}
					else if (CurCell != Cell_start && true === bBorder_insidev)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideV, 3);
						bRecalc_All = true;
					}

					if (CurCell === Cell_end && true === bBorder_right)
					{
						Cell_temp.Set_Border(Props.CellBorders.Right, 1);
						bRecalc_All = true;
					}
					else if (CurCell != Cell_end && true === bBorder_insidev)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideV, 1);
						bRecalc_All = true;
					}
				}

				Cell_start = Pos.Cell;
				Cell_end   = Pos.Cell;
				PrevRow    = Pos.Row;
			}
			else
				Cell_end = Pos.Cell;


			if (Cells_array.length - 1 === Index)
			{
				var Row_temp = this.Content[PrevRow];
				if (true != bSpacing && Cell_start > 0 && true === bBorder_left)
				{
					Row_temp.Get_Cell(Cell_start - 1).Set_Border(Props.CellBorders.Left, 1);
					bRecalc_All = true;
				}

				if (true != bSpacing && Cell_end < Row_temp.Get_CellsCount() - 1 && true === bBorder_right)
				{
					Row_temp.Get_Cell(Cell_end + 1).Set_Border(Props.CellBorders.Right, 3);
					bRecalc_All = true;
				}

				for (var CurCell = Cell_start; CurCell <= Cell_end; CurCell++)
				{
					var Cell_temp = Row_temp.Get_Cell(CurCell);

					if (Row_first === Pos.Row && true === bBorder_top)
					{
						Cell_temp.Set_Border(Props.CellBorders.Top, 0);
						bRecalc_All = true;
					}
					else if (Row_first != Pos.Row && true === bBorder_insideh)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideH, 0);
						bRecalc_All = true;
					}

					if (Row_last === Pos.Row && true === bBorder_bottom)
					{
						Cell_temp.Set_Border(Props.CellBorders.Bottom, 2);
						bRecalc_All = true;
					}
					else if (Row_last != Pos.Row && true === bBorder_insideh)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideH, 2);
						bRecalc_All = true;
					}

					if (CurCell === Cell_start && true === bBorder_left)
					{
						Cell_temp.Set_Border(Props.CellBorders.Left, 3);
						bRecalc_All = true;
					}
					else if (CurCell != Cell_start && true === bBorder_insidev)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideV, 3);
						bRecalc_All = true;
					}

					if (CurCell === Cell_end && true === bBorder_right)
					{
						Cell_temp.Set_Border(Props.CellBorders.Right, 1);
						bRecalc_All = true;
					}
					else if (CurCell != Cell_end && true === bBorder_insidev)
					{
						Cell_temp.Set_Border(Props.CellBorders.InsideV, 1);
						bRecalc_All = true;
					}
				}
			}
		}
	}

	// TableBackground  (заливка таблицы)
	if ("undefined" != typeof(Props.TableBackground))
	{
		if (Props.TableBackground.Value != TablePr.Shd.Value || Props.TableBackground.Color.r != TablePr.Shd.Color.r || Props.TableBackground.Color.g != TablePr.Shd.Color.g || Props.TableBackground.Color.b != TablePr.Shd.Color.b)
		{
			this.Set_TableShd(Props.TableBackground.Value, Props.TableBackground.Color.r, Props.TableBackground.Color.g, Props.TableBackground.Color.b);
			bRedraw = true;
		}

		// Удаляем собственную заливку ячеек
		if (false === Props.CellSelect && false === bSpacing)
		{
			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row = this.Content[CurRow];
				for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
				{
					var Cell = Row.Get_Cell(CurCell);
					Cell.Set_Shd({Value : Asc.c_oAscShdNil, Color : {r : 0, g : 0, b : 0}});
				}
			}
		}
	}

	// CellsBackground (заливка ячеек)
	if ("undefined" != typeof(Props.CellsBackground) && null != Props.CellsBackground)
	{
		if (false === Props.CellSelect && true === bSpacing)
		{
			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row = this.Content[CurRow];
				for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
				{
					var Cell   = Row.Get_Cell(CurCell);
					var NewShd =
							{
								Value : Props.CellsBackground.Value,
								Color : {
									r : Props.CellsBackground.Color.r,
									g : Props.CellsBackground.Color.g,
									b : Props.CellsBackground.Color.b
								},

								Unifill : Props.CellsBackground.Unifill.createDuplicate()
							};

					Cell.Set_Shd(NewShd);

					bRedraw = true;
				}
			}
		}
		else if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			for (var Index = 0; Index < this.Selection.Data.length; Index++)
			{
				var Pos      = this.Selection.Data[Index];
				var Cell     = this.Content[Pos.Row].Get_Cell(Pos.Cell);
				var Cell_shd = Cell.Get_Shd();

				if (Props.CellsBackground.Value != Cell_shd.Value || Props.CellsBackground.Color.r != Cell_shd.Color.r || Props.CellsBackground.Color.g != Cell_shd.Color.g || Props.CellsBackground.Color.b != Cell_shd.Color.b || !AscFormat.CompareUnifillBool(Props.CellsBackground.Unifill, Cell_shd.Unifill))
				{
					var NewShd =
							{
								Value : Props.CellsBackground.Value,
								Color : {
									r : Props.CellsBackground.Color.r,
									g : Props.CellsBackground.Color.g,
									b : Props.CellsBackground.Color.b
								},

								Unifill : Props.CellsBackground.Unifill.createDuplicate()
							};

					Cell.Set_Shd(NewShd);

					bRedraw = true;
				}
			}
		}
		else
		{
			var Cell     = this.CurCell;
			var Cell_shd = Cell.Get_Shd();

			if (Props.CellsBackground.Value != Cell_shd.Value || Props.CellsBackground.Color.r != Cell_shd.Color.r || Props.CellsBackground.Color.g != Cell_shd.Color.g || Props.CellsBackground.Color.b != Cell_shd.Color.b || !AscFormat.CompareUnifillBool(Props.CellsBackground.Unifill, Cell_shd.Unifill))
			{
				var NewShd =
						{
							Value : Props.CellsBackground.Value,
							Color : {
								r : Props.CellsBackground.Color.r,
								g : Props.CellsBackground.Color.g,
								b : Props.CellsBackground.Color.b
							},

							Unifill : Props.CellsBackground.Unifill.createDuplicate()
						};

				Cell.Set_Shd(NewShd);

				bRedraw = true;
			}
		}
	}

	// CellsVAlign (вертикальное выравнивание ячеек)
	if (undefined != Props.CellsVAlign && null != Props.CellsVAlign)
	{
		if (this.Selection.Use === true && table_Selection_Cell === this.Selection.Type)
		{
			var Count = this.Selection.Data.length;
			for (var Index = 0; Index < Count; Index++)
			{
				var Pos  = this.Selection.Data[Index];
				var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
				Cell.Set_VAlign(Props.CellsVAlign);
			}
		}
		else
		{
			this.CurCell.Set_VAlign(Props.CellsVAlign);
		}

		bRecalc_All = true;
	}

	// CellsTextDirection
	if (undefined !== Props.CellsTextDirection && null !== Props.CellsTextDirection)
	{
		var TextDirection = undefined;
		switch (Props.CellsTextDirection)
		{
			case c_oAscCellTextDirection.LRTB:
				TextDirection = textdirection_LRTB;
				break;
			case c_oAscCellTextDirection.TBRL:
				TextDirection = textdirection_TBRL;
				break;
			case c_oAscCellTextDirection.BTLR:
				TextDirection = textdirection_BTLR;
				break;
		}

		if (undefined !== TextDirection)
		{
			if (this.Selection.Use === true && table_Selection_Cell === this.Selection.Type)
			{
				var Count = this.Selection.Data.length;
				for (var Index = 0; Index < Count; ++Index)
				{
					var Pos  = this.Selection.Data[Index];
					var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
					Cell.Set_TextDirectionFromApi(TextDirection);
				}
			}
			else
			{
				this.CurCell.Set_TextDirectionFromApi(TextDirection);
			}
		}
	}

	// CellsNoWrap
	if (undefined !== Props.CellsNoWrap && null !== Props.CellsNoWrap)
	{
		if (this.Selection.Use === true && table_Selection_Cell === this.Selection.Type)
		{
			var Count = this.Selection.Data.length;
			for (var Index = 0; Index < Count; ++Index)
			{
				var Pos  = this.Selection.Data[Index];
				var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
				Cell.Set_NoWrap(Props.CellsNoWrap);
			}
		}
		else
		{
			this.CurCell.Set_NoWrap(Props.CellsNoWrap);
		}
	}

	// CellsWidth
	if (undefined !== Props.CellsWidth)
	{
		var CellsWidth = Props.CellsWidth;
		if (null !== CellsWidth && Math.abs(CellsWidth) < 0.001)
			CellsWidth = null;

		if (this.Selection.Use === true && table_Selection_Cell === this.Selection.Type)
		{
			var Count = this.Selection.Data.length;
			for (var Index = 0; Index < Count; ++Index)
			{
				var Pos  = this.Selection.Data[Index];
				var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);

				if (null === CellsWidth)
					Cell.Set_W(new CTableMeasurement(tblwidth_Auto, 0));
				else if (CellsWidth > -0.001)
					Cell.Set_W(new CTableMeasurement(tblwidth_Mm, CellsWidth));
				else
					Cell.Set_W(new CTableMeasurement(tblwidth_Pct, Math.abs(CellsWidth)));
			}
		}
		else
		{
			if (null === CellsWidth)
				this.CurCell.Set_W(new CTableMeasurement(tblwidth_Auto, 0));
			else if (CellsWidth > -0.001)
				this.CurCell.Set_W(new CTableMeasurement(tblwidth_Mm, CellsWidth));
			else
				this.CurCell.Set_W(new CTableMeasurement(tblwidth_Pct, Math.abs(CellsWidth)));
		}
	}

	// TableDescription
	if (undefined !== Props.TableDescription && null !== Props.TableDescription)
	{
		this.Set_TableDescription(Props.TableDescription);
	}

	// TableCaption
	if (undefined !== Props.TableCaption && null !== Props.TableCaption)
	{
		this.Set_TableCaption(Props.TableCaption);
	}

	return true;
};
CTable.prototype.Get_Styles = function(Lvl)
{
	return this.Parent.Get_Styles(Lvl);
};
CTable.prototype.Get_TextBackGroundColor = function()
{
	// Сначала проверим заливку данной таблицы, если ее нет, тогда спрашиваем у родительского класса
	var Shd = this.Get_Shd();

	if (Asc.c_oAscShdNil !== Shd.Value)
		return Shd.Get_Color2(this.Get_Theme(), this.Get_ColorMap());

	return this.Parent.Get_TextBackGroundColor();
};
CTable.prototype.Get_Numbering = function()
{
	return this.Parent.Get_Numbering();
};
CTable.prototype.Get_PageBounds = function(CurPage)
{
	return this.Pages[CurPage].Bounds;
};
CTable.prototype.Get_PagesCount = function()
{
	return this.Pages.length;
};
CTable.prototype.Get_AllDrawingObjects = function(DrawingObjs)
{
	if (undefined === DrawingObjs)
		DrawingObjs = [];

	var Rows_Count = this.Content.length;
	for (var CurRow = 0; CurRow < Rows_Count; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Content.Get_AllDrawingObjects(DrawingObjs);
		}
	}

	return DrawingObjs;
};
CTable.prototype.Get_AllComments = function(AllComments)
{
	if (undefined === AllComments)
		AllComments = [];

	var Rows_Count = this.Content.length;
	for (var CurRow = 0; CurRow < Rows_Count; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Content.Get_AllComments(AllComments);
		}
	}

	return AllComments;
};
CTable.prototype.Get_AllMaths = function(AllMaths)
{
	if (undefined === AllMaths)
		AllMaths = [];

	var Rows_Count = this.Content.length;
	for (var CurRow = 0; CurRow < Rows_Count; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Content.Get_AllMaths(AllMaths);
		}
	}

	return AllMaths;
};
CTable.prototype.Get_AllFloatElements = function(FloatObjs)
{
	if (undefined === FloatObjs)
		FloatObjs = [];

	var Rows_Count = this.Content.length;
	for (var CurRow = 0; CurRow < Rows_Count; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Content.Get_AllFloatElements(FloatObjs);
		}
	}

	return FloatObjs;
};
/**
 * Данная функция запрашивает новую позицию для содержимого у ячейки, разбивающейся на несколько страниц
 */
CTable.prototype.Get_PageContentStartPos = function(CurPage, RowIndex, CellIndex)
{
	var Row      = this.Content[RowIndex];
	var Cell     = Row.Get_Cell(CellIndex);
	var CellMar  = Cell.Get_Margins();
	var CellInfo = Row.Get_CellInfo(CellIndex);

	var VMerge_count = this.Internal_GetVertMergeCount(RowIndex, CellInfo.StartGridCol, Cell.Get_GridSpan());

	// Возможно первая ячейка, для которой мы рассчитваем перенос на следующую страницу
	// имеет вертикальное объединение. Поэтому строка, по которой идет перенос не RowIndex,
	// а последняя строка в объединении.
	RowIndex = RowIndex + VMerge_count - 1;
	Row      = this.Content[RowIndex];

	var Pos = this.Parent.Get_PageContentStartPos2(this.PageNum, this.ColumnNum, CurPage, this.Index);

	// На момент обращения к данной функции, у всех ячеек всех строк до текущей (включительно) должны быть
	// просчитаны верхние границы. И также должен быть просчитан заголовок на данной странице, если он есть.

	var bHeader = false;
	var Y       = Pos.Y;
	if (-1 != this.HeaderInfo.PageIndex && this.HeaderInfo.Count > 0 && CurPage > this.HeaderInfo.PageIndex && true === this.HeaderInfo.Pages[CurPage].Draw)
	{
		Y       = this.HeaderInfo.Pages[CurPage].RowsInfo[this.HeaderInfo.Count - 1].TableRowsBottom;
		bHeader = true;
	}

	var CellSpacing = Row.Get_CellSpacing();
	if (null != CellSpacing)
	{
		var Table_Border_Top = this.Get_Borders().Top;
		if (border_Single === Table_Border_Top.Value)
			Y += Table_Border_Top.Size;

		if (true === bHeader || 0 === CurPage || ( 1 === CurPage && true != this.RowsInfo[0].FirstPage ))
			Y += CellSpacing;
		else
			Y += CellSpacing / 2;
	}

	// Далее вычислим маскимальную ширину верхней границы всех ячеек в данной
	// строке, учитывая ячейки, учавствующие в вертикальном объединении.

	var MaxTopBorder = 0;
	var CellsCount   = Row.Get_CellsCount();
	var TableBorders = this.Get_Borders();
	for (var CurCell = 0; CurCell < CellsCount; CurCell++)
	{
		var Cell   = Row.Get_Cell(CurCell);
		var VMerge = Cell.Get_VMerge();

		if (vmerge_Continue === VMerge)
			Cell = this.Internal_Get_StartMergedCell(RowIndex, Row.Get_CellInfo(CurCell).StartGridCol, Cell.Get_GridSpan());

		var BorderInfo_Top = Cell.Get_BorderInfo().Top;
		if (null === BorderInfo_Top)
			continue;

		for (var Index = 0; Index < BorderInfo_Top.length; Index++)
		{
			var CurBorder = BorderInfo_Top[Index];

			var ResultBorder = this.Internal_CompareBorders(CurBorder, TableBorders.Top, false, true);

			if (border_Single === ResultBorder.Value && MaxTopBorder < ResultBorder.Size)
				MaxTopBorder = ResultBorder.Size;
		}
	}

	Pos.X = this.Pages[CurPage].X;

	Y += MaxTopBorder;

	// Учтем верхнее поле ячейки
	Y += CellMar.Top.W;

	var YLimit = Pos.YLimit;

	YLimit -= this.Pages[CurPage].FootnotesH;

	// TODO: Здесь надо учитывать нижнюю границу ячейки и вычесть ее ширину из YLimit
	return {X        : Pos.X + CellInfo.X_content_start,
		XLimit       : Pos.X + CellInfo.X_content_end,
		Y            : Y,
		YLimit       : YLimit,
		MaxTopBorder : MaxTopBorder
	};
};
CTable.prototype.Get_MaxTopBorder = function(RowIndex)
{
	// Вычислим маскимальную ширину верхней границы всех ячеек в данной
	// строке, учитывая ячейки, учавствующие в вертикальном объединении.

	var Row = this.Content[RowIndex];

	var MaxTopBorder = 0;
	var CellsCount   = Row.Get_CellsCount();
	var TableBorders = this.Get_Borders();
	for (var CurCell = 0; CurCell < CellsCount; CurCell++)
	{
		var Cell   = Row.Get_Cell(CurCell);
		var VMerge = Cell.Get_VMerge();

		if (vmerge_Continue === VMerge)
			Cell = this.Internal_Get_StartMergedCell(RowIndex, Row.Get_CellInfo(CurCell).StartGridCol, Cell.Get_GridSpan());

		var BorderInfo_Top = Cell.Get_BorderInfo().Top;
		if (null === BorderInfo_Top)
			continue;

		for (var Index = 0; Index < BorderInfo_Top.length; Index++)
		{
			var CurBorder = BorderInfo_Top[Index];

			var ResultBorder = this.Internal_CompareBorders(CurBorder, TableBorders.Top, false, true);

			if (border_Single === ResultBorder.Value && MaxTopBorder < ResultBorder.Size)
				MaxTopBorder = ResultBorder.Size;
		}
	}

	return MaxTopBorder;
};
/**
 * Вычисляем небольшое смещение по X, необходимое для совместимости с Word разных версий
 */
CTable.prototype.Get_TableOffsetCorrection = function()
{
	var X = 0;

	if (true === this.Parent.Is_TableCellContent())
		return 0;

	var Row     = this.Content[0];
	var Cell    = Row.Get_Cell(0);
	var Margins = Cell.Get_Margins();

	var CellSpacing = Row.Get_CellSpacing();
	if (null != CellSpacing)
	{
		var TableBorder_Left = this.Get_Borders().Left;
		if (border_None != TableBorder_Left.Value)
			X += TableBorder_Left.Size / 2;

		X += CellSpacing;

		var CellBorder_Left = Cell.Get_Borders().Left;
		if (border_None != CellBorder_Left.Value)
			X += CellBorder_Left.Size;

		X += Margins.Left.W;
	}
	else
	{
		var TableBorder_Left = this.Get_Borders().Left;
		var CellBorder_Left  = Cell.Get_Borders().Left;
		var Result_Border    = this.Internal_CompareBorders(TableBorder_Left, CellBorder_Left, true, false);

		if (border_None != Result_Border.Value)
			X += Math.max(Result_Border.Size / 2, Margins.Left.W);
		else
			X += Margins.Left.W;
	}

	return -X;
};
CTable.prototype.Get_RightTableOffsetCorrection = function()
{
	var X = 0;

	if (true === this.Parent.Is_TableCellContent())
		return 0;

	var Row         = this.Content[0];
	var Cell        = Row.Get_Cell(Row.Get_CellsCount() - 1);
	var Margins     = Cell.Get_Margins();
	var CellSpacing = Row.Get_CellSpacing();
	if (null != CellSpacing)
	{
		var TableBorder_Right = this.Get_Borders().Right;
		if (border_None != TableBorder_Right.Value)
			X += TableBorder_Right.Size / 2;

		X += CellSpacing;

		var CellBorder_Right = Cell.Get_Borders().Right;
		if (border_None != CellBorder_Right.Value)
			X += CellBorder_Right.Size;

		X += Margins.Right.W;
	}
	else
	{
		var TableBorder_Right = this.Get_Borders().Right;
		var CellBorder_Right  = Cell.Get_Borders().Right;
		var Result_Border     = this.Internal_CompareBorders(TableBorder_Right, CellBorder_Right, true, false);

		if (border_None != Result_Border.Value)
			X += Math.max(Result_Border.Size / 2, Margins.Right.W);
		else
			X += Margins.Right.W;
	}

	return X;
};
/**
 * Получаем первый параграф первой ячейки. (Нужно, например, для контроля ContextualSpacing)
 */
CTable.prototype.Get_FirstParagraph = function()
{
	if (this.Content.length <= 0 || this.Content[0].Content.length <= 0)
		return null;

	return this.Content[0].Content[0].Content.Get_FirstParagraph();
};
CTable.prototype.GetAllParagraphs = function(Props, ParaArray)
{
	var Count = this.Content.length;
	for (var CurRow = 0; CurRow < Count; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Content.GetAllParagraphs(Props, ParaArray);
		}
	}
};
CTable.prototype.Get_EndInfo = function()
{
	var RowsCount = this.Content.length;
	if (RowsCount > 0)
		return this.Content[RowsCount - 1].Get_EndInfo();

	return null;
};
CTable.prototype.Get_PrevElementEndInfo = function(RowIndex)
{
	if (0 === RowIndex)
		return this.Parent.Get_PrevElementEndInfo(this);
	else
		return this.Content[RowIndex - 1].Get_EndInfo();
};
//----------------------------------------------------------------------------------------------------------------------
// Функции к которым идет обращение из родительского класса
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.Copy = function(Parent)
{
	var TableGrid = this.private_CopyTableGrid();
	var Table     = new CTable(this.DrawingDocument, Parent, this.Inline, 0, 0, TableGrid, this.bPresentation);

	Table.Set_Distance(this.Distance.L, this.Distance.T, this.Distance.R, this.Distance.B);
	Table.Set_PositionH(this.PositionH.RelativeFrom, this.PositionH.Align, this.PositionH.Value);
	Table.Set_PositionV(this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value);

	// Копируем настройки
	Table.Set_TableStyle(this.TableStyle);
	Table.Set_TableLook(this.TableLook.Copy());
	Table.Set_Pr(this.Pr.Copy());

	Table.Rows = this.Rows;
	Table.Cols = this.Cols;

	// Копируем строки
	var Rows = this.Content.length;
	for (var Index = 0; Index < Rows; Index++)
	{
		Table.Content[Index] = this.Content[Index].Copy(Table);
		History.Add(new CChangesTableAddRow(Table, Index, [Table.Content[Index]]));
	}

	Table.Internal_ReIndexing(0);

	if (Table.Content.length > 0 && Table.Content[0].Get_CellsCount() > 0)
		Table.CurCell = Table.Content[0].Get_Cell(0);

	return Table;
};
CTable.prototype.Shift = function(CurPage, Dx, Dy)
{
	this.Pages[CurPage].Shift(Dx, Dy);

	if (0 === CurPage)
	{
		this.X_origin += Dx;
		this.X += Dx;
		this.Y += Dy;
		this.XLimit += Dx;
		this.YLimit += Dy;
	}

	var StartRow = this.Pages[CurPage].FirstRow;
	var LastRow  = this.Pages[CurPage].LastRow;
	for (var CurRow = StartRow; CurRow <= LastRow; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell          = Row.Get_Cell(CurCell);
			var CellPageIndex = CurPage - Cell.Content.Get_StartPage_Relative();
			if (vmerge_Restart === Cell.Get_VMerge())
			{
				Cell.Content_Shift(CellPageIndex, Dx, Dy);
			}
		}

		this.RowsInfo[CurRow].Y[CurPage] += Dy;
		this.TableRowsBottom[CurRow][CurPage] += Dy;
	}
};
CTable.prototype.Update_EndInfo = function()
{
	for (var RowIndex = 0, RowsCount = this.Content.length; RowIndex < RowsCount; RowIndex++)
	{
		var Row = this.Content[RowIndex];
		for (var CellIndex = 0, CellsCount = Row.Get_CellsCount(); CellIndex < CellsCount; CellIndex++)
		{
			var Cell = Row.Get_Cell(CellIndex);
			Cell.Content.Update_EndInfo();
		}
	}
};
CTable.prototype.Internal_UpdateFlowPosition = function(X, Y)
{
	this.X_origin = X;
	var Dx        = this.Get_TableOffsetCorrection();

	this.X = X + Dx;
	this.Y = Y;

	this.Set_PositionH(c_oAscHAnchor.Page, false, this.X);
	this.Set_PositionV(c_oAscVAnchor.Page, false, this.Y);
};
CTable.prototype.Move = function(X, Y, PageNum, NearestPos)
{
	var oLogicDocument = editor.WordControl.m_oLogicDocument;

	this.Document_SetThisElementCurrent(false);
	this.MoveCursorToStartPos();

	var oTargetTable = this;
	if (true != this.Is_Inline())
	{
		if (false === oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Table_Properties, null, true))
		{
			oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_MoveInlineTable);

			// Переносим привязку (если получается, что заносим таблицу саму в себя, тогда привязку не меняем)
			var NewDocContent = NearestPos.Paragraph.Parent;
			var OldDocContent = this.Parent;

			if (true != NewDocContent.CheckTableCoincidence(this))
			{
				var OldIndex = this.Index;
				var NewIndex = NearestPos.Paragraph.Index;

				// Проверим можем ли мы добавить таблицу перед параграфом так, чтобы таблица осталась на данной странице
				if (PageNum > NearestPos.Paragraph.Get_StartPage_Absolute())
				{
					if (NearestPos.Paragraph.Pages.length > 2)
					{
						// Параграф начинается до заданной страницы и заканчивается после. Нам нужно разделить его на
						// 2 параграфа в заданной точке.

						var NewParagraph = new Paragraph(NewDocContent.DrawingDocument, NewDocContent);
						NearestPos.Paragraph.Split(NewParagraph, NearestPos.ContentPos);
						NewDocContent.Internal_Content_Add(NewIndex + 1, NewParagraph);

						// Если все происходило в одном классе-документе, тогда проверяем индексы
						if (NewDocContent === OldDocContent && NewIndex + 1 <= OldIndex)
							OldIndex++;

						NewIndex++;
					}
					else
					{
						// Вставляем таблицу после найденного параграфа. Если параграф последний, тогда
						// в конец добавляем новый пустой параграф
						NewIndex++;
						if (NewIndex >= NewDocContent.Content.length - 1)
							NewDocContent.Internal_Content_Add(NewDocContent.Content.length, new Paragraph(NewDocContent.DrawingDocument, NewDocContent));
					}

				}

				oTargetTable = AscCommon.CollaborativeEditing.Is_SingleUser() ? this : this.Copy(NewDocContent);
				if (NewDocContent != OldDocContent)
				{
					// Сначала добавляем таблицу в новый класс
					NewDocContent.Internal_Content_Add(NewIndex, oTargetTable);

					// Удаляем таблицу из родительского класса
					OldDocContent.Internal_Content_Remove(OldIndex, 1);

					oTargetTable.Parent = NewDocContent;
				}
				else
				{
					if (NearestPos.Paragraph.Index > this.Index)
					{
						NewDocContent.Internal_Content_Add(NewIndex, oTargetTable);
						OldDocContent.Internal_Content_Remove(OldIndex, 1);
					}
					else
					{
						OldDocContent.Internal_Content_Remove(OldIndex, 1);
						NewDocContent.Internal_Content_Add(NewIndex, oTargetTable);
					}
				}
			}

			// Обновляем координаты

			// Здесь мы должны для первого рассчета оставить привязку относительно страницы, а после рассчета
			// изменить привязку на старую, при этом пересчитав координаты так, чтобы картинка не изменила
			// своего положения.

			oTargetTable.PositionH_Old = {
				RelativeFrom : oTargetTable.PositionH.RelativeFrom,
				Align        : oTargetTable.PositionH.Align,
				Value        : oTargetTable.PositionH.Value
			};

			oTargetTable.PositionV_Old = {
				RelativeFrom : oTargetTable.PositionV.RelativeFrom,
				Align        : oTargetTable.PositionV.Align,
				Value        : oTargetTable.PositionV.Value
			};

			oTargetTable.PositionH.RelativeFrom = c_oAscHAnchor.PageInternal;
			oTargetTable.PositionH.Align        = false;
			oTargetTable.PositionH.Value        = X;

			oTargetTable.PositionV.RelativeFrom = c_oAscVAnchor.Page;
			oTargetTable.PositionV.Align        = false;
			oTargetTable.PositionV.Value        = Y;

			oTargetTable.PageNum = PageNum;

			editor.WordControl.m_oLogicDocument.Recalculate();
			oTargetTable.Start_TrackTable();
		}
	}
	else
	{
		// Проверяем, можно ли двигать данную таблицу
		if (false === oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_Table_Properties, {
				Type    : AscCommon.changestype_2_InlineObjectMove,
				PageNum : PageNum,
				X       : X,
				Y       : Y
			}, true))
		{
			oLogicDocument.Create_NewHistoryPoint(AscDFH.historydescription_Document_MoveFlowTable);

			var NewDocContent = NearestPos.Paragraph.Parent;
			var OldDocContent = this.Parent;

			if (true != NewDocContent.CheckTableCoincidence(this))
			{
				var TarParagraph   = NearestPos.Paragraph;
				var ParaContentPos = NearestPos.ContentPos;

				var OldIndex = this.Index;
				var NewIndex = NearestPos.Paragraph.Index;

				// Если позиция в начале параграфа, тогда добавляем таблицу до параграфа, если в конце, тогда
				// после параграфа, в противном случае разделяем параграф.
				if (true === TarParagraph.IsCursorAtEnd(ParaContentPos))
				{
					NewIndex++;
				}
				else if (true != TarParagraph.IsCursorAtBegin(ParaContentPos))
				{
					var NewParagraph = new Paragraph(NewDocContent.DrawingDocument, NewDocContent);
					NearestPos.Paragraph.Split(NewParagraph, NearestPos.ContentPos);
					NewDocContent.Internal_Content_Add(NewIndex + 1, NewParagraph);

					// Если все происходило в одном классе-документе, тогда проверяем индексы
					if (NewDocContent === OldDocContent && NewIndex + 1 <= OldIndex)
						OldIndex++;

					NewIndex++;
				}

				var oTargetTable = AscCommon.CollaborativeEditing.Is_SingleUser() ? this : this.Copy(NewDocContent);
				if (NewDocContent != OldDocContent)
				{
					// Сначала добавляем таблицу в новый класс
					NewDocContent.Internal_Content_Add(NewIndex, oTargetTable);

					// Удаляем таблицу из родительского класса
					OldDocContent.Internal_Content_Remove(OldIndex, 1);

					oTargetTable.Parent = NewDocContent;
				}
				else
				{
					if (NearestPos.Paragraph.Index > this.Index)
					{
						NewDocContent.Internal_Content_Add(NewIndex, oTargetTable);
						OldDocContent.Internal_Content_Remove(OldIndex, 1);
					}
					else
					{
						OldDocContent.Internal_Content_Remove(OldIndex, 1);
						NewDocContent.Internal_Content_Add(NewIndex, oTargetTable);
					}
				}

				editor.WordControl.m_oLogicDocument.Recalculate();
			}
			oTargetTable.Start_TrackTable();
		}
	}
	editor.WordControl.m_oLogicDocument.RemoveSelection();
	oTargetTable.Document_SetThisElementCurrent(true);
	oTargetTable.MoveCursorToStartPos();
	editor.WordControl.m_oLogicDocument.Document_UpdateSelectionState();
};
CTable.prototype.Reset = function(X, Y, XLimit, YLimit, PageNum, ColumnNum, ColumnsCount)
{
	if (this.Parent.RecalcInfo.FlowObject === this && c_oAscVAnchor.Text === this.PositionV.RelativeFrom)
	{
		this.Y -= this.PositionV.Value;
		this.YLimit -= this.PositionV.Value;
		return;
	}

	this.X_origin = X;
	this.X        = X;
	this.Y        = Y + 0.001; // Погрешность для Flow-таблиц
	this.XLimit   = XLimit;
	this.YLimit   = YLimit;

	this.PageNum      = PageNum;
	this.ColumnNum    = ColumnNum ? ColumnNum : 0;
	this.ColumnsCount = ColumnsCount ? ColumnsCount : 1;

	this.Pages.length = 1;
	this.Pages[0]     = new CTablePage(X, Y, XLimit, YLimit, 0, 0);
};
CTable.prototype.Recalculate = function()
{
	// Пересчитываем сетку колонок
	this.private_RecalculateGrid();
	this.Internal_Recalculate_1();
};
CTable.prototype.Reset_RecalculateCache = function()
{
	this.RecalcInfo.Reset(true);

	var RowsCount = this.Content.length;
	for (var RowIndex = 0; RowIndex < RowsCount; RowIndex++)
	{
		var Row        = this.Content[RowIndex];
		var CellsCount = Row.Get_CellsCount();
		for (var CellIndex = 0; CellIndex < CellsCount; CellIndex++)
		{
			var Cell = Row.Get_Cell(CellIndex);
			Cell.Content.Reset_RecalculateCache();
		}
	}
};
CTable.prototype.RecalculateCurPos = function()
{
	if (null != this.CurCell)
		return this.CurCell.Content_RecalculateCurPos();

	return null;
};
CTable.prototype.Recalculate_MinMaxContentWidth = function(isRotated)
{
	if (true === isRotated)
	{
		var MinMargin = [], MinContent = [], MaxContent = [];

		var RowsCount = this.Content.length;
		for (var CurRow = 0; CurRow < RowsCount; ++CurRow)
		{
			MinMargin[CurRow]  = 0;
			MinContent[CurRow] = 0;
			MaxContent[CurRow] = 0;
		}

		for (var CurRow = 0; CurRow < RowsCount; CurRow++)
		{
			var Row        = this.Content[CurRow];
			var CellsCount = Row.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell         = Row.Get_Cell(CurCell);
				var CellMinMax   = Cell.Content_Recalculate_MinMaxContentWidth(isRotated);
				var CellMin      = CellMinMax.Min;
				var CellMax      = CellMinMax.Max;
				var CellMargins  = Cell.Get_Margins();
				var CellMarginsW = CellMargins.Top.W + CellMargins.Bottom.W;

				if (MinMargin[CurRow] < CellMarginsW)
					MinMargin[CurRow] = CellMarginsW;

				if (MinContent[CurRow] < CellMin)
					MinContent[CurRow] = CellMin;

				if (MaxContent[CurRow] < CellMax)
					MaxContent[CurRow] = CellMax;
			}

			var RowH = Row.Get_Height();
			if (Asc.linerule_Exact === RowH.HRule || (linerule_AtLeast === RowH.HRule && MinContent[CurRow] < RowH.Value))
				MinContent[CurRow] = RowH.Value;

			if (Asc.linerule_Exact === RowH.HRule || (linerule_AtLeast === RowH.HRule && MaxContent[CurRow] < RowH.Value))
				MaxContent[CurRow] = RowH.Value;
		}

		var Min = 0;
		var Max = 0;
		for (var CurRow = 0; CurRow < RowsCount; ++CurRow)
		{
			Min += MinMargin[CurRow] + MinContent[CurRow];
			Max += MinMargin[CurRow] + MaxContent[CurRow];
		}

		return {Min : Min, Max : Max};
	}
	else
	{
		var MinMargin = [], MinContent = [], MaxContent = [], MaxFlags = [];

		var GridCount = this.TableGridCalc.length;
		for (var CurCol = 0; CurCol < GridCount; CurCol++)
		{
			MinMargin[CurCol]  = 0;
			MinContent[CurCol] = 0;
			MaxContent[CurCol] = 0;
			MaxFlags[CurCol]   = false; // false - ориентируемся на содержимое ячеек, true - ориентируемся только на
										// ширину ячеек записанную в свойствах
		}

		var RowsCount = this.Content.length;
		for (var CurRow = 0; CurRow < RowsCount; CurRow++)
		{
			var Row = this.Content[CurRow];

			// Смотрим на ширину пропущенных колонок сетки в начале строки
			var BeforeInfo = Row.Get_Before();
			var CurGridCol = BeforeInfo.GridBefore;

			var CellsCount = Row.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell         = Row.Get_Cell(CurCell);
				var CellMinMax   = Cell.Content_Recalculate_MinMaxContentWidth(isRotated);
				var CellMin      = CellMinMax.Min;
				var CellMax      = CellMinMax.Max;
				var GridSpan     = Cell.Get_GridSpan();
				var CellMargins  = Cell.Get_Margins();
				var CellMarginsW = CellMargins.Left.W + CellMargins.Right.W;
				var CellW        = Cell.Get_W();
				var CellWW       = null;

				if (tblwidth_Mm === CellW.Type)
					CellWW = CellW.W;
				else if (tblwidth_Pct === CellW.Type)
					CellWW = (this.XLimit - this.X) * CellW.W / 100;

				// Если GridSpan > 1, тогда все равно маргины учитываются в первую колоноку спана
				if (MinMargin[CurGridCol] < CellMarginsW)
					MinMargin[CurGridCol] = CellMarginsW;

				// На самом деле, случай 1 === GridSpan нормально обработается и как случай GridSpan > 1,
				// но поскольку он наиболее распространен, делаем его обработку максимально быстрой (без циклов)
				if (1 === GridSpan)
				{
					if (MinContent[CurGridCol] < CellMin)
						MinContent[CurGridCol] = CellMin;

					if (false === MaxFlags[CurGridCol] && MaxContent[CurGridCol] < CellMax)
						MaxContent[CurGridCol] = CellMax;

					if (null !== CellWW)
					{
						if (false === MaxFlags[CurGridCol])
						{
							MaxFlags[CurGridCol]   = true;
							MaxContent[CurGridCol] = Math.max(CellWW, CellMin);
						}
						else
						{
							MaxContent[CurGridCol] = Math.max(MaxContent[CurGridCol], CellWW, CellMin);
						}
					}
				}
				else
				{
					var SumSpanMinContent = 0;
					var SumSpanMaxContent = 0;
					for (var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; CurSpan++)
					{
						SumSpanMinContent += MinContent[CurSpan];
						SumSpanMaxContent += MaxContent[CurSpan];
					}

					if (SumSpanMinContent < CellMin)
					{
						var TempAdd = (CellMin - SumSpanMinContent) / GridSpan;
						for (var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; CurSpan++)
							MinContent[CurSpan] += TempAdd;
					}

					// Если у нас в объединении несколько колонок, тогда явно записанная ширина ячейки не
					// перекрывает ширину ни одной из колонок, она всего лишь участвует в определении
					// максимальной ширины.
					if (null !== CellWW && CellWW > CellMax)
						CellMax = CellWW;

					if (SumSpanMaxContent < CellMax)
					{
						// TODO: На самом деле, распределение здесь идет в каком-то отношении.
						//       Неплохо было бы выяснить как именно.
						var TempAdd = (CellMax - SumSpanMaxContent) / GridSpan;
						for (var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; CurSpan++)
							MaxContent[CurSpan] += TempAdd;
					}
				}

				CurGridCol += GridSpan;
			}
		}

		var Min = 0;
		var Max = 0;
		for (var CurCol = 0; CurCol < GridCount; CurCol++)
		{
			Min += MinMargin[CurCol] + MinContent[CurCol];

			if (false === MaxFlags[CurCol])
				Max += MinMargin[CurCol] + MaxContent[CurCol];
			else
				Max += MaxContent[CurCol];
		}

		return {Min : Min, Max : Max};
	}
};
CTable.prototype.Recalculate_AllTables = function()
{
	this.private_RecalculateGrid();
	this.private_RecalculateBorders();

	var RowsCount = this.Content.length;
	for (var CurRow = 0; CurRow < RowsCount; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Content.Recalculate_AllTables();
		}
	}
};
CTable.prototype.Get_LastRangeVisibleBounds = function()
{
	var CurPage = this.Pages.length - 1;
	var Page    = this.Pages[CurPage];
	var CurRow  = this.Content.length - 1;
	var Row     = this.Content[CurRow];

	// Ищем границы по горизонтали для последней ячейки
	var CurCell = Row.Get_CellsCount() - 1;

	var Cell     = Row.Get_Cell(CurCell);
	var CellInfo = Row.Get_CellInfo(CurCell);
	var CellMar  = Cell.Get_Margins();

	var X_start = Page.X + CellInfo.X_cell_start;
	var X_end   = Page.X + CellInfo.X_cell_end;

	var Cell_PageRel = CurPage - Cell.Content.Get_StartPage_Relative();

	// Не все ячейки могут иметь страницу с номером Cell_PageRel, но хотя бы одна такая должна быть (иначе переноса
	// на новую страницу не было бы)
	var CellsCount = Row.Get_CellsCount();
	for (CurCell = 0; CurCell < CellsCount; CurCell++)
	{
		Cell = Row.Get_Cell(CurCell);

		if (Cell_PageRel <= Cell.PagesCount - 1)
			break;
	}

	if (CurCell >= CellsCount)
		return {X : X_start, Y : 0, W : X_end - X_start, H : 0, BaseLine : 0, XLimit : Page.XLimit};

	var Bounds   = Cell.Content_Get_PageBounds(Cell_PageRel);
	var Y_offset = Cell.Temp.Y_VAlign_offset[Cell_PageRel];

	var Y = 0;
	var H = 0;
	if (0 != Cell_PageRel)
	{
		// мы должны определить ряд, на котором случился перенос на новую страницу
		var TempRowIndex = this.Pages[CurPage].FirstRow;

		Y = this.RowsInfo[TempRowIndex].Y[CurPage] + this.RowsInfo[TempRowIndex].TopDy[CurPage] + CellMar.Top.W + Y_offset;
		H = this.RowsInfo[TempRowIndex].H[CurPage];
	}
	else
	{
		Y = this.RowsInfo[CurRow].Y[CurPage] + this.RowsInfo[CurRow].TopDy[CurPage] + CellMar.Top.W + Y_offset;
		H = this.RowsInfo[CurRow].H[CurPage];
	}

	return {X : X_start, Y : Y, W : X_end - X_start, H : H, BaseLine : H, XLimit : Page.XLimit};
};
CTable.prototype.Get_NearestPos = function(CurPage, X, Y, bAnchor, Drawing)
{
	var Pos  = this.Internal_GetCellByXY(X, Y, CurPage);
	var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);

	return Cell.Content_Get_NearestPos(CurPage - Cell.Content.Get_StartPage_Relative(), X, Y, bAnchor, Drawing);
};
CTable.prototype.Get_ParentTextTransform = function()
{
	return this.Parent.Get_ParentTextTransform();
};
/**
 * Проверяем начинается ли текущий параграф с новой страницы.
 */
CTable.prototype.IsStartFromNewPage = function()
{
	if ((this.Pages.length > 1 && true === this.Is_EmptyPage(0)) || (null === this.Get_DocumentPrev() && true === this.Parent.Is_TopDocument()))
		return true;

	return false;
};
CTable.prototype.Is_ContentOnFirstPage = function()
{
	if (this.Pages.length >= 1 && true === this.RowsInfo[0].FirstPage)
		return true;

	return false;
};
CTable.prototype.IsTableBorder = function(X, Y, CurPage)
{
	if (true === this.DrawingDocument.IsMobileVersion())
		return null;

	CurPage = Math.max(0, Math.min(this.Pages.length - 1, CurPage));

	if (true === this.Is_EmptyPage(CurPage))
		return null;

	var Result = this.Internal_CheckBorders(X, Y, CurPage);
	if (Result.Border != -1)
	{
		return this;
	}
	else
	{
		var Cell = this.Content[Result.Pos.Row].Get_Cell(Result.Pos.Cell);
		return Cell.Content_Is_TableBorder(X, Y, CurPage - Cell.Content.Get_StartPage_Relative());
	}
};
CTable.prototype.IsInText = function(X, Y, CurPage)
{
	if (CurPage < 0 || CurPage >= this.Pages.length)
		CurPage = 0;

	var Result = this.Internal_CheckBorders(X, Y, CurPage);
	if (Result.Border != -1)
	{
		return null;
	}
	else
	{
		var Cell = this.Content[Result.Pos.Row].Get_Cell(Result.Pos.Cell);
		return Cell.Content_Is_InText(X, Y, CurPage - Cell.Content.Get_StartPage_Relative());
	}
};
CTable.prototype.IsInDrawing  = function(X, Y, CurPage)
{
	if (CurPage < 0 || CurPage >= this.Pages.length)
		CurPage = 0;

	var Result = this.Internal_CheckBorders(X, Y, CurPage);
	if (Result.Border != -1)
	{
		return null;
	}
	else
	{
		var Cell = this.Content[Result.Pos.Row].Get_Cell(Result.Pos.Cell);
		return Cell.Content_Is_InDrawing(X, Y, CurPage - Cell.Content.Get_StartPage_Relative());
	}
};
CTable.prototype.IsInnerTable = function()
{
	if (this.Content.length <= 0)
		return false;

	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		return this.CurCell.Content.Is_CurrentElementTable();

	return false;
};
CTable.prototype.Is_UseInDocument = function(Id)
{
	var bUse = false;
	if (null != Id)
	{
		var RowsCount = this.Content.length;
		for (var Index = 0; Index < RowsCount; Index++)
		{
			if (Id === this.Content[Index].Get_Id())
			{
				bUse = true;
				break;
			}
		}
	}
	else
		bUse = true;

	if (true === bUse && null != this.Parent)
		return this.Parent.Is_UseInDocument(this.Get_Id());

	return false;
};
CTable.prototype.Get_CurrentPage_Absolute = function()
{
	if (true === this.Selection.Use)
	{
		var Pos = this.Selection.EndPos.Pos;
		return this.Content[Pos.Row].Get_Cell(Pos.Cell).Content.Get_CurrentPage_Absolute();
	}
	else
		return this.CurCell.Content.Get_CurrentPage_Absolute();
};
CTable.prototype.Get_CurrentPage_Relative = function()
{
	if (true === this.Selection.Use)
		return 0;

	return this.CurCell.Content.Get_CurrentPage_Absolute() - this.Get_StartPage_Absolute();
};
CTable.prototype.UpdateCursorType = function(X, Y, CurPage)
{
	if (CurPage < 0 || CurPage >= this.Pages.length)
		CurPage = 0;

	if (true === this.Lock.Is_Locked())
	{
		var _X = this.Pages[CurPage].Bounds.Left;
		var _Y = this.Pages[CurPage].Bounds.Top;

		var MMData              = new CMouseMoveData();
		var Coords              = this.DrawingDocument.ConvertCoordsToCursorWR(_X, _Y, this.Get_AbsolutePage(CurPage));
		MMData.X_abs            = Coords.X - 5;
		MMData.Y_abs            = Coords.Y - 5;
		MMData.Type             = AscCommon.c_oAscMouseMoveDataTypes.LockedObject;
		MMData.UserId           = this.Lock.Get_UserId();
		MMData.HaveChanges      = this.Lock.Have_Changes();
		MMData.LockedObjectType = c_oAscMouseMoveLockedObjectType.Common;

		editor.sync_MouseMoveCallback(MMData);
	}

	if (true === this.Selection.Start || table_Selection_Border === this.Selection.Type2 || table_Selection_Border_InnerTable === this.Selection.Type2)
		return;

	var NewOutline = null;
	if (true === this.Check_EmptyPages(CurPage - 1) && true !== this.Is_EmptyPage(CurPage))
	{
		this.private_StartTrackTable(CurPage);
	}

	var Result = this.Internal_CheckBorders(X, Y, CurPage);
	if (-1 !== Result.Border)
	{
		var Transform = this.Get_ParentTextTransform();
		if (null !== Transform)
		{
			var dX = Math.abs(Transform.TransformPointX(0, 0) - Transform.TransformPointX(0, 1));
			var dY = Math.abs(Transform.TransformPointY(0, 0) - Transform.TransformPointY(0, 1));

			if (Math.abs(dY) > Math.abs(dX))
			{
				switch (Result.Border)
				{
					case 0:
					case 2:
						return this.DrawingDocument.SetCursorType("s-resize", new CMouseMoveData());
					case 1:
					case 3:
						return this.DrawingDocument.SetCursorType("w-resize", new CMouseMoveData());
				}
			}
			else
			{
				switch (Result.Border)
				{
					case 0:
					case 2:
						return this.DrawingDocument.SetCursorType("w-resize", new CMouseMoveData());
					case 1:
					case 3:
						return this.DrawingDocument.SetCursorType("s-resize", new CMouseMoveData());
				}
			}
		}
		else
		{
			switch (Result.Border)
			{
				case 0:
				case 2:
					return this.DrawingDocument.SetCursorType("s-resize", new CMouseMoveData());
				case 1:
				case 3:
					return this.DrawingDocument.SetCursorType("w-resize", new CMouseMoveData());
			}
		}
	}

	var Cell_Pos = this.Internal_GetCellByXY(X, Y, CurPage);
	var Cell     = this.Content[Cell_Pos.Row].Get_Cell(Cell_Pos.Cell);
	Cell.Content_UpdateCursorType(X, Y, CurPage - Cell.Content.Get_StartPage_Relative());
};
CTable.prototype.Start_TrackTable = function()
{
	var CurPage = 0;
	while (CurPage < this.Pages.length)
	{
		if (true != this.Is_EmptyPage(CurPage))
			break;

		CurPage++;
	}

	this.private_StartTrackTable(CurPage);
};
CTable.prototype.DocumentStatistics = function(Stats)
{
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			Row.Get_Cell(CurCell).Content.DocumentStatistics(Stats);
		}
	}
};
CTable.prototype.Document_CreateFontMap = function(FontMap)
{
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			Row.Get_Cell(CurCell).Content_Document_CreateFontMap(FontMap);
		}
	}
};
CTable.prototype.Document_CreateFontCharMap = function(FontCharMap)
{
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			Row.Get_Cell(CurCell).Content.Document_CreateFontCharMap(0x00B7);
		}
	}
};
CTable.prototype.Document_Get_AllFontNames = function(AllFonts)
{
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			Row.Get_Cell(CurCell).Content.Document_Get_AllFontNames(AllFonts);
		}
	}
};
CTable.prototype.Document_UpdateInterfaceState = function()
{
	// Если у нас выделено несколько ячеек, тогда данная таблица - нижний уровень
	if (true != this.Selection.Use || table_Selection_Cell != this.Selection.Type)
	{
		this.CurCell.Content.Document_UpdateInterfaceState();
	}
	else
	{
		var ParaPr         = this.GetCalculatedParaPr();
		ParaPr.CanAddTable = false;
		if (null != ParaPr)
			editor.UpdateParagraphProp(ParaPr);

		var TextPr = this.GetCalculatedTextPr();
		if (null != TextPr)
		{
			var theme = this.Get_Theme();
			if (theme && theme.themeElements && theme.themeElements.fontScheme)
			{
				if (TextPr.FontFamily)
				{
					TextPr.FontFamily.Name = theme.themeElements.fontScheme.checkFont(TextPr.FontFamily.Name);
				}
				if (TextPr.RFonts)
				{
					if (TextPr.RFonts.Ascii)
						TextPr.RFonts.Ascii.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.Ascii.Name);
					if (TextPr.RFonts.EastAsia)
						TextPr.RFonts.EastAsia.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.EastAsia.Name);
					if (TextPr.RFonts.HAnsi)
						TextPr.RFonts.HAnsi.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.HAnsi.Name);
					if (TextPr.RFonts.CS)
						TextPr.RFonts.CS.Name = theme.themeElements.fontScheme.checkFont(TextPr.RFonts.CS.Name);
				}
			}
			editor.UpdateTextPr(TextPr);
		}
	}
};
CTable.prototype.Document_UpdateRulersState = function(CurPage)
{
	if (CurPage < 0 || CurPage >= this.Pages.length)
		CurPage = 0;

	if (true == this.Selection.Use && table_Selection_Cell == this.Selection.Type)
	{
		this.Internal_Update_TableMarkup(this.Selection.EndPos.Pos.Row, this.Selection.EndPos.Pos.Cell, CurPage);
	}
	else
	{
		this.Internal_Update_TableMarkup(this.CurCell.Row.Index, this.CurCell.Index, CurPage);
		this.CurCell.Content.Document_UpdateRulersState(CurPage - this.CurCell.Content.Get_StartPage_Relative());
	}
};
CTable.prototype.Document_SetThisElementCurrent = function(bUpdateStates)
{
	this.Parent.Update_ContentIndexing();
	this.Parent.Set_CurrentElement(this.Index, bUpdateStates);
};
CTable.prototype.Can_CopyCut = function()
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		return true;
	else
		return this.CurCell.Content.Can_CopyCut();
};
CTable.prototype.Set_Inline = function(Value)
{
	History.Add(new CChangesTableInline(this, this.Inline, Value));
	this.Inline = Value;
};
CTable.prototype.Is_Inline = function()
{
	if (this.Parent && true === this.Parent.Is_DrawingShape())
		return true;

	return this.Inline;
};
CTable.prototype.Set_ApplyToAll = function(bValue)
{
	this.ApplyToAll = bValue;
};
CTable.prototype.Get_ApplyToAll = function()
{
	return this.ApplyToAll;
};
/**
 * Функция, которую нужно вызвать перед удалением данного элемента
 */
CTable.prototype.PreDelete = function()
{
	this.DrawingDocument.EndTrackTable(this, false);

	var RowsCount = this.Content.length;
	for (var CurRow = 0; CurRow < RowsCount; CurRow++)
	{
		var Row = this.Content[CurRow];
		Row.PreDelete();
	}
};
CTable.prototype.RemoveInnerTable = function()
{
	this.CurCell.Content.RemoveTable();
};
CTable.prototype.SelectTable = function(Type)
{
	if (true === this.IsInnerTable())
	{
		this.CurCell.Content.SelectTable(Type);
		if (true === this.CurCell.Content.IsSelectionUse())
		{
			this.Selection.Use   = true;
			this.Selection.Start = false;
			this.Selection.Type  = table_Selection_Text;
			this.Selection.Data  = null;
			this.Selection.Type2 = table_Selection_Common;
			this.Selection.Data2 = null;
		}

		return;
	}

	var NewSelectionData = [];

	switch (Type)
	{
		case c_oAscTableSelectionType.Table :
		{
			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row         = this.Content[CurRow];
				var Cells_Count = Row.Get_CellsCount();
				for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
				{
					var Cell   = Row.Get_Cell(CurCell);
					var Vmerge = Cell.Get_VMerge();

					if (vmerge_Continue === Vmerge)
						continue;

					NewSelectionData.push({Row : CurRow, Cell : CurCell});
				}
			}

			break;
		}

		case c_oAscTableSelectionType.Row :
		{
			var Rows_to_select = [];

			if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
			{
				var Row_prev = -1;
				for (var Index = 0; Index < this.Selection.Data.length; Index++)
				{
					var Pos = this.Selection.Data[Index];
					if (-1 === Row_prev || Row_prev != Pos.Row)
					{
						Rows_to_select.push(Pos.Row);
						Row_prev = Pos.Row;
					}
				}
			}
			else
			{
				Rows_to_select.push(this.CurCell.Row.Index);
			}

			for (var Index = 0; Index < Rows_to_select.length; Index++)
			{
				var Row         = this.Content[Rows_to_select[Index]];
				var Cells_Count = Row.Get_CellsCount();
				for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
				{
					var Cell   = Row.Get_Cell(CurCell);
					var Vmerge = Cell.Get_VMerge();
					if (vmerge_Continue === Vmerge)
						continue;

					NewSelectionData.push({Cell : CurCell, Row : Rows_to_select[Index]});
				}
			}

			break;
		}

		case c_oAscTableSelectionType.Column :
		{
			var Grid_start = -1;
			var Grid_end   = -1;

			if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
			{
				for (var Index = 0; Index < this.Selection.Data.length; Index++)
				{
					var Pos  = this.Selection.Data[Index];
					var Row  = this.Content[Pos.Row];
					var Cell = Row.Get_Cell(Pos.Cell);

					var StartGridCol = Row.Get_CellInfo(Pos.Cell).StartGridCol;
					var EndGridCol   = StartGridCol + Cell.Get_GridSpan() - 1;

					if (-1 === Grid_start || Grid_start > StartGridCol)
						Grid_start = StartGridCol;

					if (-1 === Grid_end || Grid_end < EndGridCol)
						Grid_end = EndGridCol;
				}
			}
			else
			{
				Grid_start = this.Content[this.CurCell.Row.Index].Get_CellInfo(this.CurCell.Index).StartGridCol;
				Grid_end   = Grid_start + this.CurCell.Get_GridSpan() - 1;
			}


			for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
			{
				var Row         = this.Content[CurRow];
				var Cells_Count = Row.Get_CellsCount();

				for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
				{
					var Cell   = Row.Get_Cell(CurCell);
					var Vmerge = Cell.Get_VMerge();
					if (vmerge_Continue === Vmerge)
						continue;

					var StartGridCol = Row.Get_CellInfo(CurCell).StartGridCol;
					var EndGridCol   = StartGridCol + Cell.Get_GridSpan() - 1;

					if (EndGridCol >= Grid_start && StartGridCol <= Grid_end)
						NewSelectionData.push({Cell : CurCell, Row : CurRow});
				}
			}

			break;
		}

		case c_oAscTableSelectionType.Cell :
		default :
		{
			if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
				NewSelectionData = this.Selection.Data;
			else
				NewSelectionData.push({Row : this.CurCell.Row.Index, Cell : this.CurCell.Index});
			break;
		}
	}

	this.Selection.Use   = true;
	this.Selection.Start = false;
	this.Selection.Type  = table_Selection_Cell;
	this.Selection.Data  = NewSelectionData;
	this.Selection.Type2 = table_Selection_Common;
	this.Selection.Data2 = null;

	this.Selection.StartPos.Pos = {Row : NewSelectionData[0].Row, Cell : NewSelectionData[0].Cell};
	this.Selection.EndPos.Pos   = {
		Row  : NewSelectionData[NewSelectionData.length - 1].Row,
		Cell : NewSelectionData[NewSelectionData.length - 1].Cell
	};

};
CTable.prototype.CanSplitTableCells = function()
{
	if (true === this.IsInnerTable())
		return this.CurCell.Content.CanSplitTableCells();

	// Разделение ячейки работает, только если выделена ровно одна ячейка.
	if (!( false === this.Selection.Use || ( true === this.Selection.Use && ( table_Selection_Text === this.Selection.Type || ( table_Selection_Cell === this.Selection.Type && 1 === this.Selection.Data.length  ) ) ) ))
		return false;

	return true;
};
CTable.prototype.CanMergeTableCells = function()
{
	if (true === this.IsInnerTable())
		return this.CurCell.Content.CanMergeTableCells();

	if (true != this.Selection.Use || table_Selection_Cell != this.Selection.Type || this.Selection.Data.length <= 1)
		return false;

	return this.Internal_CheckMerge().bCanMerge;
};
//----------------------------------------------------------------------------------------------------------------------
// Undo/Redo функции
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.GetSelectionState = function()
{
	var TableState       = {};
	TableState.Selection = {
		Start    : this.Selection.Start,
		Use      : this.Selection.Use,
		StartPos : {
			Pos        : {Row : this.Selection.StartPos.Pos.Row, Cell : this.Selection.StartPos.Pos.Cell},
			X          : this.Selection.StartPos.X,
			Y          : this.Selection.StartPos.Y,
			PageIndex  : this.Selection.StartPos.PageIndex,
			MouseEvent : {
				// TODO : Если в MouseEvent будет использоваться что-то кроме ClickCount, Type и CtrlKey, добавить
				// здесь
				ClickCount : this.Selection.StartPos.MouseEvent.ClickCount,
				Type       : this.Selection.StartPos.MouseEvent.Type,
				CtrlKey    : this.Selection.StartPos.MouseEvent.CtrlKey
			}
		},
		EndPos   : {
			Pos        : {Row : this.Selection.EndPos.Pos.Row, Cell : this.Selection.EndPos.Pos.Cell},
			X          : this.Selection.EndPos.X,
			Y          : this.Selection.EndPos.Y,
			PageIndex  : this.Selection.EndPos.PageIndex,
			MouseEvent : {
				// TODO : Если в MouseEvent будет использоваться что-то кроме ClickCount, Type и CtrlKey, добавить
				// здесь
				ClickCount : this.Selection.EndPos.MouseEvent.ClickCount,
				Type       : this.Selection.EndPos.MouseEvent.Type,
				CtrlKey    : this.Selection.EndPos.MouseEvent.CtrlKey
			}
		},
		Type     : this.Selection.Type,
		Data     : null,
		Type2    : this.Selection.Type2,
		Data2    : null,
		CurRow   : this.Selection.CurRow
	};

	TableState.Selection.Data = [];
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		for (var Index = 0; Index < this.Selection.Data.length; Index++)
			TableState.Selection.Data[Index] = {
				Row  : this.Selection.Data[Index].Row,
				Cell : this.Selection.Data[Index].Cell
			};
	}

	TableState.CurCell = {Row : this.CurCell.Row.Index, Cell : this.CurCell.Index};

	var State = this.CurCell.Content.GetSelectionState();
	State.push(TableState);
	return State;
};
CTable.prototype.SetSelectionState = function(State, StateIndex)
{
	if (State.length <= 0)
		return;

	var TableState = State[StateIndex];

	this.Selection = {
		Start    : TableState.Selection.Start,
		Use      : TableState.Selection.Use,
		StartPos : {
			Pos        : {
				Row  : TableState.Selection.StartPos.Pos.Row,
				Cell : TableState.Selection.StartPos.Pos.Cell
			},
			X          : TableState.Selection.StartPos.X,
			Y          : TableState.Selection.StartPos.Y,
			PageIndex  : TableState.Selection.StartPos.PageIndex,
			MouseEvent : {
				// TODO : Если в MouseEvent будет использоваться что-то кроме ClickCount, Type и CtrlKey, добавить
				// здесь
				ClickCount : TableState.Selection.StartPos.MouseEvent.ClickCount,
				Type       : TableState.Selection.StartPos.MouseEvent.Type,
				CtrlKey    : TableState.Selection.StartPos.MouseEvent.CtrlKey
			}
		},
		EndPos   : {
			Pos        : {Row : TableState.Selection.EndPos.Pos.Row, Cell : TableState.Selection.EndPos.Pos.Cell},
			X          : TableState.Selection.EndPos.X,
			Y          : TableState.Selection.EndPos.Y,
			PageIndex  : TableState.Selection.EndPos.PageIndex,
			MouseEvent : {
				// TODO : Если в MouseEvent будет использоваться что-то кроме ClickCount, Type и CtrlKey, добавить
				// здесь
				ClickCount : TableState.Selection.EndPos.MouseEvent.ClickCount,
				Type       : TableState.Selection.EndPos.MouseEvent.Type,
				CtrlKey    : TableState.Selection.EndPos.MouseEvent.CtrlKey
			}
		},
		Type     : TableState.Selection.Type,
		Data     : null,
		Type2    : TableState.Selection.Type2,
		Data2    : null,
		CurRow   : TableState.Selection.CurRow
	};

	this.Selection.Data = [];
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		for (var Index = 0; Index < TableState.Selection.Data.length; Index++)
			this.Selection.Data[Index] = {
				Row  : TableState.Selection.Data[Index].Row,
				Cell : TableState.Selection.Data[Index].Cell
			};
	}

	this.CurCell = this.Content[TableState.CurCell.Row].Get_Cell(TableState.CurCell.Cell);
	this.CurCell.Content.SetSelectionState(State, StateIndex - 1);
};
CTable.prototype.Get_ParentObject_or_DocumentPos = function()
{
	return this.Parent.Get_ParentObject_or_DocumentPos(this.Index);
};
CTable.prototype.Refresh_RecalcData = function(Data)
{
	var Type = Data.Type;

	var bNeedRecalc = false;
	var nRowIndex   = 0;

	switch (Type)
	{
		case AscDFH.historyitem_Table_TableShd:
		{
			break;
		}

		case AscDFH.historyitem_Table_TableW:
		case AscDFH.historyitem_Table_TableLayout:
		case AscDFH.historyitem_Table_TableCellMar:
		case AscDFH.historyitem_Table_TableAlign:
		case AscDFH.historyitem_Table_TableInd:
		case AscDFH.historyitem_Table_TableBorder_Left:
		case AscDFH.historyitem_Table_TableBorder_Right:
		case AscDFH.historyitem_Table_TableBorder_Top:
		case AscDFH.historyitem_Table_TableBorder_Bottom:
		case AscDFH.historyitem_Table_TableBorder_InsideH:
		case AscDFH.historyitem_Table_TableBorder_InsideV:
		case AscDFH.historyitem_Table_Inline:
		case AscDFH.historyitem_Table_AllowOverlap:
		case AscDFH.historyitem_Table_PositionH:
		case AscDFH.historyitem_Table_PositionV:
		case AscDFH.historyitem_Table_Distance:
		case AscDFH.historyitem_Table_TableStyleColBandSize:
		case AscDFH.historyitem_Table_TableStyleRowBandSize:
		case AscDFH.historyitem_Table_Pr:
		{
			bNeedRecalc = true;
			break;
		}
		case AscDFH.historyitem_Table_AddRow:
		case AscDFH.historyitem_Table_RemoveRow:
		{
			bNeedRecalc = true;
			nRowIndex   = Data.Pos;
			break;
		}
		case AscDFH.historyitem_Table_TableGrid:
		{
			bNeedRecalc = true;
			break;
		}
		case AscDFH.historyitem_Table_TableStyle:
		case AscDFH.historyitem_Table_TableLook:
		{
			var Count = this.Content.length;
			for (var CurRow = 0; CurRow < Count; CurRow++)
			{
				var Row         = this.Content[CurRow];
				var Cells_Count = Row.Get_CellsCount();
				for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
				{
					var Cell = Row.Get_Cell(CurCell);
					Cell.Recalc_CompiledPr();
				}
				Row.Recalc_CompiledPr();
			}
			this.Recalc_CompiledPr();
			bNeedRecalc = true;
			break;
		}
	}

	this.RecalcInfo.Recalc_AllCells();
	this.RecalcInfo.Recalc_Borders();

	if (true === bNeedRecalc)
	{
		History.Add_RecalcTableGrid(this.Get_Id());
		this.Refresh_RecalcData2(nRowIndex, 0);
	}
};
CTable.prototype.Refresh_RecalcData2 = function(RowIndex, Page_rel)
{
	// Если Index < 0, значит данный элемент еще не был добавлен в родительский класс
	if (this.Index >= 0)
	{
		var _RowIndex = Math.min(RowIndex, this.RowsInfo.length - 1);
		var _Page_rel = ( _RowIndex < 0 ? this.PageNum : Page_rel + this.PageNum );
		this.Parent.Refresh_RecalcData2(this.Index, _Page_rel);
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с совместным редактирования
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.Write_ToBinary2 = function(Writer)
{
	Writer.WriteLong(AscDFH.historyitem_type_Table);

	// Long               : type_Table
	// String             : Id самой таблицы
	// String             : Id стиля (если стока пустая, то null)
	// Bool               : Inline
	// Long               : количество элементов в TableGrid
	// Array of doubles   : массив TableGrid
	// Double             : X_origin
	// Double             : X
	// Double             : Y
	// Double             : XLimit
	// Double             : YLimit
	// Variable           : свойства таблицы (TablePr)
	// Long               : количество строк
	// Array of Strings   : массив Id строк

	Writer.WriteLong(type_Table);
	Writer.WriteString2(this.Id);
	Writer.WriteString2(null === this.TableStyle ? "" : this.TableStyle);
	Writer.WriteBool(this.Inline);

	var GridCount = this.TableGrid.length;
	Writer.WriteLong(GridCount);
	for (var Index = 0; Index < GridCount; Index++)
		Writer.WriteDouble(this.TableGrid[Index]);

	Writer.WriteDouble(this.X_origin);
	Writer.WriteDouble(this.X);
	Writer.WriteDouble(this.Y);
	Writer.WriteDouble(this.XLimit);
	Writer.WriteDouble(this.YLimit);

	this.Pr.Write_ToBinary(Writer);

	var RowsCount = this.Content.length;
	Writer.WriteLong(RowsCount);
	for (var Index = 0; Index < RowsCount; Index++)
		Writer.WriteString2(this.Content[Index].Get_Id());
	Writer.WriteBool(this.bPresentation);
};
CTable.prototype.Read_FromBinary2 = function(Reader)
{
	// Long               : type_Table
	// String             : Id самой таблицы
	// String             : Id стиля (если стока пустая, то null)
	// Bool               : Inline
	// Long               : количество элементов в TableGrid
	// Array of doubles   : массив TableGrid
	// Double             : X_origin
	// Double             : X
	// Double             : Y
	// Double             : XLimit
	// Double             : YLimit
	// Variable           : свойства таблицы (TablePr)
	// Long               : количество строк
	// Array of Strings   : массив Id строк

	this.Prev = null;
	this.Next = null;

	Reader.GetLong();
	this.Id = Reader.GetString2();

	var TableStyleId = Reader.GetString2();
	this.TableStyle  = ( TableStyleId === "" ? null : TableStyleId );

	this.Inline = Reader.GetBool();

	var GridCount  = Reader.GetLong();
	this.TableGrid = [];
	for (var Index = 0; Index < GridCount; Index++)
		this.TableGrid.push(Reader.GetDouble());

	this.X_origin = Reader.GetDouble();
	this.X        = Reader.GetDouble();
	this.Y        = Reader.GetDouble();
	this.XLimit   = Reader.GetDouble();
	this.YLimit   = Reader.GetDouble();

	this.Pr = new CTablePr();
	this.Pr.Read_FromBinary(Reader);
	this.Recalc_CompiledPr();

	var Count    = Reader.GetLong();
	this.Content = [];
	for (var Index = 0; Index < Count; Index++)
	{
		var Row = g_oTableId.Get_ById(Reader.GetString2());
		this.Content.push(Row);
	}
	this.bPresentation = Reader.GetBool();

	this.Internal_ReIndexing();

	AscCommon.CollaborativeEditing.Add_NewObject(this);

	var DrawingDocument = editor.WordControl.m_oDrawingDocument;
	if (undefined !== DrawingDocument && null !== DrawingDocument)
	{
		this.DrawingDocument = DrawingDocument;
		this.LogicDocument   = this.DrawingDocument.m_oLogicDocument;
	}

	// Добавляем, чтобы в конце выставить CurCell
	var LinkData     = {};
	LinkData.CurCell = true;
	AscCommon.CollaborativeEditing.Add_LinkData(this, LinkData);
};
CTable.prototype.Load_LinkData = function(LinkData)
{
	if ("undefined" != typeof(LinkData) && "undefined" != typeof(LinkData.CurCell))
	{
		if (this.Content.length > 0 && this.Content[0].Get_CellsCount() > 0)
			this.CurCell = this.Content[0].Get_Cell(0);
	}
};
CTable.prototype.Get_SelectionState2 = function()
{
	var TableState = {};

	TableState.Id = this.Get_Id();

	TableState.CellId = ( null !== this.CurCell ? this.CurCell.Get_Id() : null );
	TableState.Data   = ( null !== this.CurCell ? this.CurCell.Content.Get_SelectionState2() : null );

	return TableState;
};
CTable.prototype.Set_SelectionState2 = function(TableState)
{
	var CellId = TableState.CellId;

	var CurCell = null;
	var Pos     = {Cell : 0, Row : 0};

	var RowsCount = this.Content.length;
	for (var RowIndex = 0; RowIndex < RowsCount; RowIndex++)
	{
		var Row        = this.Content[RowIndex];
		var CellsCount = Row.Get_CellsCount();
		for (var CellIndex = 0; CellIndex < CellsCount; CellIndex++)
		{
			var Cell = Row.Get_Cell(CellIndex);

			if (Cell.Get_Id() === CellId)
			{
				CurCell = Cell;

				Pos.Cell = CellIndex;
				Pos.Row  = RowIndex;

				break;
			}
		}

		if (null !== CurCell)
			break;
	}

	if (null == CurCell)
	{
		this.MoveCursorToStartPos(false);
	}
	else
	{
		this.CurCell = CurCell;

		this.Selection.Start        = false;
		this.Selection.Use          = false;
		this.Selection.StartPos.Pos = {Row : Pos.Row, Cell : Pos.Cell};
		this.Selection.EndPos.Pos   = {Row : Pos.Row, Cell : Pos.Cell};
		this.Selection.Type         = table_Selection_Common;
		this.Selection.Type2        = table_Selection_Common;
		this.Selection.Data         = null;
		this.Selection.Data2        = null;
		this.Selection.CurRow       = 0;

		this.CurCell.Content.Set_SelectionState2(TableState.Data);
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с гиперссылками
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.AddHyperlink = function(HyperProps)
{
	// Выделения по ячейкам быть не должно
	return this.CurCell.Content.AddHyperlink(HyperProps);
};
CTable.prototype.ModifyHyperlink = function(HyperProps)
{
	if (false === this.Selection.Use || (true === this.Selection.Use && table_Selection_Text === this.Selection.Type))
		this.CurCell.Content.ModifyHyperlink(HyperProps);

	return false;
};
CTable.prototype.RemoveHyperlink = function()
{
	if (false === this.Selection.Use || (true === this.Selection.Use && table_Selection_Text === this.Selection.Type))
		this.CurCell.Content.RemoveHyperlink();
};
CTable.prototype.CanAddHyperlink = function(bCheckInHyperlink)
{
	if (false === this.Selection.Use || (true === this.Selection.Use && table_Selection_Text === this.Selection.Type))
		return this.CurCell.Content.CanAddHyperlink(bCheckInHyperlink);

	return false;
};
CTable.prototype.IsCursorInHyperlink = function(bCheckEnd)
{
	if (false === this.Selection.Use || (true === this.Selection.Use && table_Selection_Text === this.Selection.Type))
		return this.CurCell.Content.IsCursorInHyperlink(bCheckEnd);

	return null;
};
//----------------------------------------------------------------------------------------------------------------------
// Функции для работы с комментариями
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.AddComment = function(Comment, bStart, bEnd)
{
	if (true === this.ApplyToAll)
	{
		var RowsCount  = this.Content.length;
		var CellsCount = this.Content[RowsCount - 1].Get_CellsCount();

		if (true === bStart && true === bEnd && RowsCount <= 1 && CellsCount <= 1)
		{
			var Cell_Content = this.Content[0].Get_Cell(0).Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell_Content.AddComment(Comment, true, true);
			Cell_Content.Set_ApplyToAll(false);
		}
		else
		{
			if (true === bStart)
			{
				var Cell_Content = this.Content[0].Get_Cell(0).Content;
				Cell_Content.Set_ApplyToAll(true);
				Cell_Content.AddComment(Comment, true, false);
				Cell_Content.Set_ApplyToAll(false);
			}

			if (true === bEnd)
			{
				var Cell_Content = this.Content[RowsCount - 1].Get_Cell(CellsCount - 1).Content;
				Cell_Content.Set_ApplyToAll(true);
				Cell_Content.AddComment(Comment, false, true);
				Cell_Content.Set_ApplyToAll(false);
			}

			// TODO: Пока нам приходится пересчитывать ячейки после добавления комментариев. Как только
			//       избавимся от этого, то надо будет переделать здесь.

			var RowsCount = this.Content.length;
			for (var RowIndex = 0; RowIndex < RowsCount; RowIndex++)
			{
				var Row        = this.Content[RowIndex];
				var CellsCount = Row.Get_CellsCount();

				for (var CellIndex = 0; CellIndex < CellsCount; CellIndex++)
				{
					var Cell = Row.Get_Cell(CellIndex);
					this.RecalcInfo.Add_Cell(Cell);
				}
			}
		}
	}
	else
	{
		if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			if (true === bStart && true === bEnd && this.Selection.Data.length <= 1)
			{
				var Pos          = this.Selection.Data[0];
				var Cell_Content = this.Content[Pos.Row].Get_Cell(Pos.Cell).Content;
				Cell_Content.Set_ApplyToAll(true);
				Cell_Content.AddComment(Comment, true, true);
				Cell_Content.Set_ApplyToAll(false);
			}
			else
			{
				var StartPos = null, EndPos = null;

				if (true === bStart)
				{
					StartPos         = this.Selection.Data[0];
					var Cell_Content = this.Content[StartPos.Row].Get_Cell(StartPos.Cell).Content;
					Cell_Content.Set_ApplyToAll(true);
					Cell_Content.AddComment(Comment, true, false);
					Cell_Content.Set_ApplyToAll(false);
				}

				if (true === bEnd)
				{
					EndPos           = this.Selection.Data[this.Selection.Data.length - 1];
					var Cell_Content = this.Content[EndPos.Row].Get_Cell(EndPos.Cell).Content;
					Cell_Content.Set_ApplyToAll(true);
					Cell_Content.AddComment(Comment, false, true);
					Cell_Content.Set_ApplyToAll(false);
				}

				// TODO: Пока нам приходится пересчитывать ячейки после добавления комментариев. Как только
				//       избавимся от этого, то надо будет переделать здесь.

				var StartRow = 0, EndRow = -1, StartCell = 0, EndCell = -1;
				if (null !== StartPos && null !== EndPos)
				{
					StartRow  = StartPos.Row;
					EndRow    = EndPos.Row;
					StartCell = StartPos.Cell;
					EndCell   = EndPos.Cell;
				}
				else if (null !== StartPos)
				{
					StartRow  = StartPos.Row;
					StartCell = StartPos.Cell;
					EndRow    = this.Content.length - 1;
					EndCell   = this.Content[EndRow].Get_CellsCount() - 1;
				}
				else if (null !== EndPos)
				{
					StartRow  = 0;
					StartCell = 0;
					EndRow    = EndPos.Row;
					EndCell   = EndPos.Cell;
				}

				for (var RowIndex = StartRow; RowIndex <= EndRow; RowIndex++)
				{
					var Row = this.Content[RowIndex];

					var _StartCell = ( RowIndex === StartRow ? StartCell : 0 );
					var _EndCell   = ( RowIndex === EndRow ? EndCell : Row.Get_CellsCount() - 1 );

					for (var CellIndex = _StartCell; CellIndex <= _EndCell; CellIndex++)
					{
						var Cell = Row.Get_Cell(CellIndex);
						this.RecalcInfo.Add_Cell(Cell);
					}
				}
			}
		}
		else
		{
			this.CurCell.Content.AddComment(Comment, bStart, bEnd);
		}
	}
};
CTable.prototype.CanAddComment = function()
{
	if (true === this.ApplyToAll)
	{
		if (this.Content.length > 1 || this.Content[0].Get_CellsCount() > 1)
			return true;

		this.Content[0].Get_Cell(0).Content.Set_ApplyToAll(true);
		var Result = this.Content[0].Get_Cell(0).Content.CanAddComment();
		this.Content[0].Get_Cell(0).Content.Set_ApplyToAll(false);
		return Result;
	}
	else
	{
		if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			if (this.Selection.Data.length > 1)
				return true;
			else
			{
				var Pos  = this.Selection.Data[0];
				var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
				return Cell.Content.CanAddComment();
			}
		}
		else
		{
			return this.CurCell.Content.CanAddComment();
		}
	}
};
CTable.prototype.Can_IncreaseParagraphLevel = function(bIncrease)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		if (this.Selection.Data.length > 0)
		{
			var Data = this.Selection.Data;
			for (var i = 0; i < Data.length; ++i)
			{
				var Pos          = Data[i];
				var Cell_Content = this.Content[Pos.Row].Get_Cell(Pos.Cell).Content;
				if (Cell_Content)
				{
					Cell_Content.Set_ApplyToAll(true);
					var bCan = Cell_Content.Can_IncreaseParagraphLevel(bIncrease);
					Cell_Content.Set_ApplyToAll(false);
					if (!bCan)
					{
						return false;
					}
				}
			}
			return true;
		}
		else
		{
			return false;
		}
	}
	else
	{
		this.CurCell.Content.Can_IncreaseParagraphLevel(bIncrease);
	}
};
CTable.prototype.GetSelectionBounds = function()
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();

		var StartPos = Cells_array[0];

		var Row  = this.Content[StartPos.Row];
		var Cell = Row.Get_Cell(StartPos.Cell);

		var X0 = Cell.Metrics.X_cell_start;
		var X1 = Cell.Metrics.X_cell_end;

		var CurPage = this.RowsInfo[StartPos.Row].StartPage;

		var Y = this.RowsInfo[StartPos.Row].Y[CurPage];
		var H = this.RowsInfo[StartPos.Row].H[CurPage];

		var TableX = this.Pages[CurPage].X + this.RowsInfo[StartPos.Row].X0;

		var BeginRect = {X : TableX + X0, Y : Y, W : X1 - X0, H : H, Page : CurPage + this.Get_StartPage_Absolute()};

		var EndPos = Cells_array[Cells_array.length - 1];

		Row  = this.Content[EndPos.Row];
		Cell = Row.Get_Cell(EndPos.Cell);

		X0 = Cell.Metrics.X_cell_start;
		X1 = Cell.Metrics.X_cell_end;

		CurPage = this.RowsInfo[EndPos.Row].StartPage + this.RowsInfo[EndPos.Row].Pages - 1;

		Y = this.RowsInfo[EndPos.Row].Y[CurPage];
		H = this.RowsInfo[EndPos.Row].H[CurPage];

		var Direction = 1;
		if (this.Selection.StartPos.Pos.Row < this.Selection.EndPos.Pos.Row || (this.Selection.StartPos.Pos.Row === this.Selection.EndPos.Pos.Row && this.Selection.StartPos.Pos.Cell <= this.Selection.EndPos.Pos.Cell))
			Direction = 1;
		else
			Direction = -1;

		var EndRect = {X : TableX + X0, Y : Y, W : X1 - X0, H : H, Page : CurPage + this.Get_StartPage_Absolute()};

		return {Start : BeginRect, End : EndRect, Direction : Direction};
	}
	else
	{
		return this.CurCell.Content.GetSelectionBounds();
	}
};
CTable.prototype.GetSelectionAnchorPos = function()
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();

		var Pos  = Cells_array[0];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.Get_Cell(Pos.Cell);

		var X0 = Cell.Metrics.X_cell_start;
		var X1 = Cell.Metrics.X_cell_end;

		var Y    = this.RowsInfo[Pos.Row].Y[this.RowsInfo[Pos.Row].StartPage];
		var Page = this.RowsInfo[Pos.Row].StartPage + this.Get_StartPage_Absolute();

		return {X0 : X0, X1 : X1, Y : Y, Page : Page};
	}
	else
	{
		return this.CurCell.Content.GetSelectionAnchorPos();
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Работаем с текущей позицией и селектом таблицы
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.MoveCursorToXY = function(X, Y, bLine, bDontChangeRealPos, CurPage)
{
	var Pos  = this.Internal_GetCellByXY(X, Y, CurPage);
	var Row  = this.Content[Pos.Row];
	var Cell = Row.Get_Cell(Pos.Cell);

	this.Selection.Type         = table_Selection_Text;
	this.Selection.Type2        = table_Selection_Common;
	this.Selection.StartPos.Pos = {Row : Pos.Row, Cell : Pos.Cell};
	this.Selection.EndPos.Pos   = {Row : Pos.Row, Cell : Pos.Cell};
	this.Selection.CurRow       = Pos.Row;

	// Устанавливаем найденную ячейку текущей и перемещаемся в контент ячейки по координатам X,Y
	this.CurCell = Cell;
	this.DrawingDocument.TargetStart();
	this.DrawingDocument.TargetShow();
	this.CurCell.Content_MoveCursorToXY(X, Y, false, true, CurPage - this.CurCell.Content.Get_StartPage_Relative());
	if (this.LogicDocument)
	{
		this.LogicDocument.RecalculateCurPos();
	}
};
CTable.prototype.Selection_SetStart = function(X, Y, CurPage, MouseEvent)
{
	if (CurPage < 0 || CurPage >= this.Pages.length)
		CurPage = 0;

	var Page = this.Pages[CurPage];

	var Result = this.Internal_CheckBorders(X, Y, CurPage);

	var Pos = Result.Pos;
	if (-1 === Result.Border)
	{
		var bInnerTableBorder = ( null != this.IsTableBorder(X, Y, CurPage) ? true : false );
		if (true === bInnerTableBorder)
		{
			// Значит двигается граница внутренней таблицы, мы не должны отменять селект
			var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			Cell.Content_Selection_SetStart(X, Y, CurPage - Cell.Content.Get_StartPage_Relative(), MouseEvent);

			this.Selection.Type2 = table_Selection_Border_InnerTable;
			this.Selection.Data2 = Cell;
		}
		else
		{
			this.RemoveSelection();

			this.CurCell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			this.CurCell.Content_Selection_SetStart(X, Y, CurPage - this.CurCell.Content.Get_StartPage_Relative(), MouseEvent);

			this.Selection.Use   = true;
			this.Selection.Start = true;
			this.Selection.Type  = table_Selection_Text;
			this.Selection.Type2 = table_Selection_Common;
			this.Selection.Data2 = null;

			this.Selection.StartPos.Pos        = Pos;
			this.Selection.StartPos.X          = X;
			this.Selection.StartPos.Y          = Y;
			this.Selection.StartPos.PageIndex  = CurPage;
			this.Selection.StartPos.MouseEvent =
				{
					// TODO : Если в MouseEvent будет использоваться что-то кроме ClickCount, Type и CtrlKey, добавить
					// здесь
					ClickCount : MouseEvent.ClickCount,
					Type       : MouseEvent.Type,
					CtrlKey    : MouseEvent.CtrlKey
				};
		}
	}
	else
	{
		this.Internal_Update_TableMarkup(Pos.Row, Pos.Cell, CurPage);
		this.Selection.Type2         = table_Selection_Border;
		this.Selection.Data2         = {};
		this.Selection.Data2.PageNum = CurPage;

		var Row = this.Content[Pos.Row];

		var _X = X;
		var _Y = Y;

		if (0 === Result.Border || 2 === Result.Border)
		{
			var PageH = this.LogicDocument.Get_PageLimits(this.Get_StartPage_Absolute()).YLimit;

			var Y_min = 0;
			var Y_max = PageH;

			this.Selection.Data2.bCol = false;

			var Row_start = this.Pages[CurPage].FirstRow;
			var Row_end   = this.Pages[CurPage].LastRow;
			if (0 === Result.Border)
				this.Selection.Data2.Index = Pos.Row - Row_start;
			else
				this.Selection.Data2.Index = Result.Row - Row_start + 1;

			if (0 != this.Selection.Data2.Index)
			{
				var TempRow = this.Selection.Data2.Index + Row_start - 1;
				Y_min       = this.RowsInfo[TempRow].Y[CurPage];
			}

			// Подправим Y, чтобы первоначально точно по границе проходила линия
			if (this.Selection.Data2.Index !== Row_end - Row_start + 1)
				_Y = this.RowsInfo[this.Selection.Data2.Index + Row_start].Y[CurPage];
			else
				_Y = this.RowsInfo[this.Selection.Data2.Index + Row_start - 1].Y[CurPage] + this.RowsInfo[this.Selection.Data2.Index + Row_start - 1].H[CurPage];

			this.Selection.Data2.Min = Y_min;
			this.Selection.Data2.Max = Y_max;

			this.Selection.Data2.Pos =
				{
					Row  : Pos.Row,
					Cell : Pos.Cell
				};

			if (null != this.Selection.Data2.Min)
				_Y = Math.max(_Y, this.Selection.Data2.Min);

			if (null != this.Selection.Data2.Max)
				_Y = Math.min(_Y, this.Selection.Data2.Max);
		}
		else
		{
			var CellsCount  = Row.Get_CellsCount();
			var CellSpacing = ( null === Row.Get_CellSpacing() ? 0 : Row.Get_CellSpacing() );
			var X_min       = null;
			var X_max       = null;

			this.Selection.Data2.bCol = true;
			if (3 === Result.Border)
				this.Selection.Data2.Index = Pos.Cell;
			else
				this.Selection.Data2.Index = Pos.Cell + 1;

			if (0 != this.Selection.Data2.Index)
			{
				var Margins = Row.Get_Cell(this.Selection.Data2.Index - 1).Get_Margins();
				if (0 != this.Selection.Data2.Index - 1 && this.Selection.Data2.Index != CellsCount)
					X_min = Page.X + Row.Get_CellInfo(this.Selection.Data2.Index - 1).X_grid_start + Margins.Left.W + Margins.Right.W + CellSpacing;
				else
					X_min = Page.X + Row.Get_CellInfo(this.Selection.Data2.Index - 1).X_grid_start + Margins.Left.W + Margins.Right.W + 1.5 * CellSpacing;
			}

			if (CellsCount != this.Selection.Data2.Index)
			{
				var Margins = Row.Get_Cell(this.Selection.Data2.Index).Get_Margins();
				if (CellsCount - 1 != this.Selection.Data2.Index)
					X_max = Page.X + Row.Get_CellInfo(this.Selection.Data2.Index).X_grid_end - (Margins.Left.W + Margins.Right.W + CellSpacing);
				else
					X_max = Page.X + Row.Get_CellInfo(this.Selection.Data2.Index).X_grid_end - (Margins.Left.W + Margins.Right.W + 1.5 * CellSpacing);
			}

			// Подправим значение по X, чтобы первоначально точно по границе проходила линия
			if (CellsCount != this.Selection.Data2.Index)
				_X = Page.X + Row.Get_CellInfo(this.Selection.Data2.Index).X_grid_start;
			else
				_X = Page.X + Row.Get_CellInfo(this.Selection.Data2.Index - 1).X_grid_end;

			this.Selection.Data2.Min = X_min;
			this.Selection.Data2.Max = X_max;

			this.Selection.Data2.Pos =
				{
					Row  : Pos.Row,
					Cell : Pos.Cell
				};

			if (null != this.Selection.Data2.Min)
				_X = Math.max(_X, this.Selection.Data2.Min);

			if (null != this.Selection.Data2.Max)
				_X = Math.min(_X, this.Selection.Data2.Max);
		}

		this.Selection.Data2.X = _X;
		this.Selection.Data2.Y = _Y;

		this.Selection.Data2.StartCX = _X; // Начальная позиция скорректированная относительно положения границы
		this.Selection.Data2.StartCY = _Y;
		this.Selection.Data2.StartX  = X; // Начальная позиция нажатия мыши (без корректировки)
		this.Selection.Data2.StartY  = Y;
		this.Selection.Data2.Start   = true;

		this.DrawingDocument.LockCursorTypeCur();
	}
};
CTable.prototype.Selection_SetEnd = function(X, Y, CurPage, MouseEvent)
{
	var TablePr = this.Get_CompiledPr(false).TablePr;
	if (CurPage < 0 || CurPage >= this.Pages.length)
		CurPage = 0;

	var Page = this.Pages[CurPage];
	if (this.Selection.Type2 === table_Selection_Border)
	{
		if (true === editor.isViewMode || this.Selection.Data2.PageNum != CurPage)
			return;

		var _X = X;
		var _Y = Y;

		// Проверяем, случайное нажатие на границу. (т.е. случайное однократное нажатие или с малым смещением)
		if (true !== this.Selection.Data2.Start || Math.abs(X - this.Selection.Data2.StartX) > 0.05 || Math.abs(Y - this.Selection.Data2.StartY) > 0.05)
		{
			_X                         = this.DrawingDocument.CorrectRulerPosition(X);
			_Y                         = this.DrawingDocument.CorrectRulerPosition(Y);
			this.Selection.Data2.Start = false;
		}
		else
		{
			_X = this.Selection.Data2.X;
			_Y = this.Selection.Data2.Y;
		}

		if (true === this.Selection.Data2.bCol)
			_X = this.private_UpdateTableRulerOnBorderMove(_X);
		else
			_Y = this.private_UpdateTableRulerOnBorderMove(_Y);

		this.Selection.Data2.X = _X;
		this.Selection.Data2.Y = _Y;

		if (MouseEvent.Type === AscCommon.g_mouse_event_type_up)
		{
			// Обрабатываем случай, когда граница не изменила своего первоначального положения
			if (Math.abs(_X - this.Selection.Data2.StartCX) < 0.001 && Math.abs(_Y - this.Selection.Data2.StartCY) < 0.001)
			{
				this.Selection.Type2 = table_Selection_Common;
				this.Selection.Data2 = null;

				return;
			}

			var LogicDocument = (editor && true !== editor.isViewMode ? editor.WordControl.m_oLogicDocument : null);
			if (LogicDocument && false === LogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_None, {
					Type      : AscCommon.changestype_2_Element_and_Type,
					Element   : this,
					CheckType : AscCommon.changestype_Table_Properties
				}))
			{
				History.Create_NewPoint(AscDFH.historydescription_Document_MoveTableBorder);

				if (true === this.Selection.Data2.bCol)
				{
					// Найдем колонку в TableGrid, с которой мы работаем
					var Index  = this.Selection.Data2.Index;
					var CurRow = this.Selection.Data2.Pos.Row;
					var Row    = this.Content[CurRow];

					var Col = 0;

					// границ на 1 больше, чем самих ячеек в строке
					if (Index === this.Markup.Cols.length)
						Col = Row.Get_CellInfo(Index - 1).StartGridCol + Row.Get_Cell(Index - 1).Get_GridSpan();
					else
						Col = Row.Get_CellInfo(Index).StartGridCol;

					var Dx = _X - (Page.X + this.TableSumGrid[Col - 1]);

					// Строим новую секту для таблицы
					var Rows_info = [];

					// Если граница, которую мы двигаем не попадает в селект, тогда работает, как будто селекта и нет
					var bBorderInSelection = false;
					if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 && !this.bPresentation)
					{
						var CellsFlag = [];
						for (CurRow = 0; CurRow < this.Content.length; CurRow++)
						{
							CellsFlag[CurRow] = [];
							Row               = this.Content[CurRow];
							var CellsCount    = Row.Get_CellsCount();
							for (var CurCell = 0; CurCell < CellsCount; CurCell++)
							{
								CellsFlag[CurRow][CurCell] = 0;
							}
						}

						var CurSelectedCell  = this.Selection.Data[0];
						var CurSelectedIndex = 0;
						for (CurRow = 0; CurRow < this.Content.length; CurRow++)
						{
							Row            = this.Content[CurRow];
							var CellsCount = Row.Get_CellsCount();
							for (var CurCell = 0; CurCell < CellsCount; CurCell++)
							{
								if (CurSelectedCell.Cell === CurCell && CurSelectedCell.Row === CurRow)
								{
									CellsFlag[CurRow][CurCell] = 1;

									var StartGridCol = Row.Get_CellInfo(CurCell).StartGridCol;
									var GridSpan     = Row.Get_Cell(CurCell).Get_GridSpan();
									var VMergeCount  = this.Internal_GetVertMergeCount(CurRow, StartGridCol, GridSpan);

									if (CurRow === this.Selection.Data2.Pos.Row && Col >= StartGridCol && Col <= StartGridCol + GridSpan)
										bBorderInSelection = true;

									for (var TempIndex = 1; TempIndex < VMergeCount; TempIndex++)
									{
										var TempCell = this.Internal_Get_Cell_ByStartGridCol(CurRow + TempIndex, StartGridCol);
										if (-1 != TempCell)
										{
											CellsFlag[CurRow + TempIndex][TempCell] = 1;

											if (CurRow + TempIndex === this.Selection.Data2.Pos.Row && Col >= StartGridCol && Col <= StartGridCol + GridSpan)
												bBorderInSelection = true;
										}
									}

									if (CurSelectedIndex < this.Selection.Data.length - 1)
										CurSelectedCell = this.Selection.Data[++CurSelectedIndex];
									else
										CurSelectedCell = {Row : -1, Cell : -1};
								}
							}
						}

					}

					var OldTableInd = TablePr.TableInd;
					var NewTableInd = TablePr.TableInd;
					if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && true === bBorderInSelection && !this.bPresentation)
					{
						var BeforeFlag   = false;
						var BeforeSpace2 = null;
						if (0 === Col)
						{
							BeforeSpace2 = _X - Page.X;

							if (BeforeSpace2 < 0)
							{
								this.Set_TableW(tblwidth_Auto, 0);
								Page.X += BeforeSpace2;

								if (true === this.Is_Inline())
									NewTableInd = NewTableInd + BeforeSpace2;
								else
									this.Internal_UpdateFlowPosition(Page.X, Page.Y);
							}
						}

						var BeforeSpace = null;
						if (0 === Index && 0 != Col && _X < Page.X)
						{
							BeforeSpace = Page.X - _X;
							Page.X -= BeforeSpace;
							this.Set_TableW(tblwidth_Auto, 0);

							if (true === this.Is_Inline())
								NewTableInd = NewTableInd - BeforeSpace;
							else
								this.Internal_UpdateFlowPosition(Page.X, Page.Y);
						}

						if (Index === this.Markup.Cols.length)
							this.Set_TableW(tblwidth_Auto, 0);

						for (CurRow = 0; CurRow < this.Content.length; CurRow++)
						{
							Rows_info[CurRow] = [];
							Row               = this.Content[CurRow];
							var Before_Info   = Row.Get_Before();

							var WBefore = 0;

							if (null === BeforeSpace2)
							{
								if (Before_Info.GridBefore > 0 && Col === Before_Info.GridBefore && 1 === CellsFlag[CurRow][0])
									WBefore = this.TableSumGrid[Before_Info.GridBefore - 1] + Dx;
								else
								{
									if (null != BeforeSpace)
										WBefore = this.TableSumGrid[Before_Info.GridBefore - 1] + BeforeSpace;
									else
										WBefore = this.TableSumGrid[Before_Info.GridBefore - 1];
								}
							}
							else
							{
								if (BeforeSpace2 > 0)
								{
									if (0 === Before_Info.GridBefore && 1 === CellsFlag[CurRow][0])
										WBefore = BeforeSpace2;
									else if (0 != Before_Info.GridBefore)
										WBefore = this.TableSumGrid[Before_Info.GridBefore - 1];
								}
								else
								{
									if (0 === Before_Info.GridBefore && 1 != CellsFlag[CurRow][0])
										WBefore = -BeforeSpace2;
									else if (0 != Before_Info.GridBefore)
										WBefore = -BeforeSpace2 + this.TableSumGrid[Before_Info.GridBefore - 1];
								}
							}

							if (WBefore > 0.001)
								Rows_info[CurRow].push({W : WBefore, Type : -1, GridSpan : 1});


							var CellsCount = Row.Get_CellsCount();
							var TempDx     = Dx;
							for (var CurCell = 0; CurCell < CellsCount; CurCell++)
							{
								var Cell           = Row.Get_Cell(CurCell);
								var CellMargins    = Cell.Get_Margins();
								var Cur_Grid_start = Row.Get_CellInfo(CurCell).StartGridCol;
								var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

								var W = 0;
								if (Cur_Grid_end + 1 === Col && ( 1 === CellsFlag[CurRow][CurCell] || ( CurCell + 1 < CellsCount && 1 === CellsFlag[CurRow][CurCell + 1] ) ))
									W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1] + Dx;
								else if (Cur_Grid_start === Col && ( 1 === CellsFlag[CurRow][CurCell] || ( CurCell > 0 && 1 === CellsFlag[CurRow][CurCell - 1] ) ))
									W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1] - TempDx;
								else
									W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1];

								W = Math.max(1, Math.max(W, CellMargins.Left.W + CellMargins.Right.W));
								if (Cur_Grid_end + 1 === Col && ( 1 === CellsFlag[CurRow][CurCell] || ( CurCell + 1 < CellsCount && 1 === CellsFlag[CurRow][CurCell + 1] ) ))
									TempDx = W - (this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1]);

								Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
							}
						}

						// Возможно, что во всех рядах RowsInfo в начале есть запись BeforeGrid
						var MinBefore = 0;
						for (CurRow = 0; CurRow < this.Content.length; CurRow++)
						{
							if (-1 != Rows_info[CurRow][0].Type)
							{
								MinBefore = 0;
								break;
							}

							if (0 === MinBefore || MinBefore > Rows_info[CurRow][0].W)
								MinBefore = Rows_info[CurRow][0].W;
						}

						if (0 != MinBefore)
						{
							for (CurRow = 0; CurRow < this.Content.length; CurRow++)
							{
								if (Math.abs(MinBefore - Rows_info[CurRow][0].W) < 0.001)
									Rows_info[CurRow].splice(0, 1);
								else // if ( MinBefore < Rows_info[CurRow][0].W )
									Rows_info[CurRow][0].W -= MinBefore;
							}

							Page.X += MinBefore;
							if (true === this.Is_Inline())
								NewTableInd = NewTableInd + MinBefore;
							else
								this.Internal_UpdateFlowPosition(Page.X, Page.Y);
						}
					}
					else
					{
						var BeforeFlag   = false;
						var BeforeSpace2 = null;
						if (0 === Col)
						{
							BeforeSpace2 = Page.X - _X;

							if (-BeforeSpace2 > this.TableSumGrid[0])
							{
								BeforeFlag = true;
								Page.X += this.TableSumGrid[0];
							}
							else
								Page.X += Dx;

							this.Set_TableW(tblwidth_Auto, 0);

							if (true === this.Is_Inline())
							{
								if (-BeforeSpace2 > this.TableSumGrid[0])
									NewTableInd = NewTableInd + this.TableSumGrid[0];
								else
									NewTableInd = NewTableInd + Dx;
							}
							else
								this.Internal_UpdateFlowPosition(Page.X, Page.Y);
						}

						if (Index === this.Markup.Cols.length)
							this.Set_TableW(tblwidth_Auto, 0);

						var BeforeSpace = null;
						if (0 === Index && 0 != Col && _X < Page.X)
						{
							BeforeSpace = Page.X - _X;
							Page.X -= BeforeSpace;
							if (true === this.Is_Inline())
								NewTableInd = NewTableInd - BeforeSpace;
							else
								this.Internal_UpdateFlowPosition(Page.X, Page.Y);
						}

						for (CurRow = 0; CurRow < this.Content.length; CurRow++)
						{
							Rows_info[CurRow] = [];
							Row               = this.Content[CurRow];
							var Before_Info   = Row.Get_Before();

							var WBefore = 0;

							if (Before_Info.GridBefore > 0 && Col === Before_Info.GridBefore)
								WBefore = this.TableSumGrid[Before_Info.GridBefore - 1] + Dx;
							else
							{
								if (null != BeforeSpace)
									WBefore = this.TableSumGrid[Before_Info.GridBefore - 1] + BeforeSpace;
								else
									WBefore = this.TableSumGrid[Before_Info.GridBefore - 1];

								if (null != BeforeSpace2)
								{
									if (Before_Info.GridBefore > 0)
									{
										if (true === BeforeFlag)
											WBefore = this.TableSumGrid[Before_Info.GridBefore - 1] - this.TableSumGrid[0];
										else
											WBefore = this.TableSumGrid[Before_Info.GridBefore - 1] + BeforeSpace2;

									}
									else if (0 === Before_Info.GridBefore && true === BeforeFlag)
										WBefore = ( -BeforeSpace2 ) - this.TableSumGrid[0];
								}
							}

							if (WBefore > 0.001)
								Rows_info[CurRow].push({W : WBefore, Type : -1, GridSpan : 1});

							var CellsCount = Row.Get_CellsCount();
							var TempDx     = Dx;
							for (var CurCell = 0; CurCell < CellsCount; CurCell++)
							{
								var Cell           = Row.Get_Cell(CurCell);
								var CellMargins    = Cell.Get_Margins();
								var Cur_Grid_start = Row.Get_CellInfo(CurCell).StartGridCol;
								var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

								var W = 0;
								if (Cur_Grid_end + 1 === Col)
									W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1] + Dx;
								else if (Cur_Grid_start === Col)
									W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1] - TempDx;
								else
									W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1];

								W = Math.max(1, Math.max(W, CellMargins.Left.W + CellMargins.Right.W));
								if (Cur_Grid_end + 1 === Col)
									TempDx = W - (this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1]);

								Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
							}
						}
					}

					if (Math.abs(NewTableInd - OldTableInd) > 0.001)
						this.Set_TableInd(NewTableInd);

					if (tbllayout_AutoFit === this.Get_CompiledPr(false).TablePr.TableLayout)
						this.Set_TableLayout(tbllayout_Fixed);

					this.Internal_CreateNewGrid(Rows_info);
					this.private_RecalculateGrid();
				}
				else
				{
					var RowIndex = this.Pages[this.Selection.Data2.PageNum].FirstRow + this.Selection.Data2.Index;
					if (0 === RowIndex)
					{
						if (true === this.Is_Inline())
						{
							// Ничего не делаем
						}
						else
						{
							var Dy = _Y - this.Markup.Rows[0].Y;
							Page.Y += Dy;
							this.Internal_UpdateFlowPosition(Page.X, Page.Y);

							//var NewH = this.Markup.Rows[0].H + Dy;
							//this.Content[0].Set_Height( NewH, Asc.linerule_AtLeast );
						}
					}
					else
					{
						if (this.Selection.Data2.PageNum > 0 && 0 === this.Selection.Data2.Index)
						{
							// Ничего не делаем
						}
						else
						{
							var _Y_old = this.Markup.Rows[this.Selection.Data2.Index - 1].Y + this.Markup.Rows[this.Selection.Data2.Index - 1].H;
							var Dy     = _Y - _Y_old;
							var NewH   = this.Markup.Rows[this.Selection.Data2.Index - 1].H + Dy;
							this.Content[RowIndex - 1].Set_Height(NewH, linerule_AtLeast);
						}
					}
				}

				this.Internal_Recalculate_1();
			}

			this.Selection.Type2 = table_Selection_Common;
			this.Selection.Data2 = null;
		}

		return;
	}
	else if (table_Selection_Border_InnerTable === this.Selection.Type2)
	{
		var Cell = this.Selection.Data2;
		Cell.Content_Selection_SetEnd(X, Y, CurPage - Cell.Content.Get_StartPage_Relative(), MouseEvent);

		if (MouseEvent.Type === AscCommon.g_mouse_event_type_up)
		{
			this.Selection.Type2 = table_Selection_Common;
			this.Selection.Data2 = null;
		}

		return;
	}

	var Pos = this.Internal_GetCellByXY(X, Y, CurPage);
	this.Content[Pos.Row].Get_Cell(Pos.Cell).Content_Set_CurPosXY(X, Y);
	this.Selection.Data              = null;
	this.Selection.EndPos.Pos        = Pos;
	this.Selection.EndPos.X          = X;
	this.Selection.EndPos.Y          = Y;
	this.Selection.EndPos.PageIndex  = CurPage;
	this.Selection.EndPos.MouseEvent = MouseEvent;
	this.Selection.CurRow            = Pos.Row;

	// При селекте внутри ячейки мы селектим содержимое ячейки
	if (0 === this.Parent.GetSelectDirection() && this.Selection.StartPos.Pos.Row === this.Selection.EndPos.Pos.Row && this.Selection.StartPos.Pos.Cell === this.Selection.EndPos.Pos.Cell)
	{
		this.CurCell.Content_Selection_SetStart(this.Selection.StartPos.X, this.Selection.StartPos.Y, this.Selection.StartPos.PageIndex - this.CurCell.Content.Get_StartPage_Relative(), this.Selection.StartPos.MouseEvent);

		this.Selection.Type = table_Selection_Text;

		this.CurCell.Content_Selection_SetEnd(X, Y, CurPage - this.CurCell.Content.Get_StartPage_Relative(), MouseEvent);

		if (AscCommon.g_mouse_event_type_up == MouseEvent.Type)
			this.Selection.Start = false;

		if (false === this.CurCell.Content.Selection.Use)
		{
			this.Selection.Use   = false;
			this.Selection.Start = false;
			this.MoveCursorToXY(X, Y, false, false, CurPage);
			return;
		}
	}
	else
	{
		if (AscCommon.g_mouse_event_type_up == MouseEvent.Type)
		{
			this.Selection.Start = false;
			this.CurCell         = this.Content[Pos.Row].Get_Cell(Pos.Cell);
		}

		this.Selection.Type = table_Selection_Cell;
		this.Internal_Selection_UpdateCells();
	}
};
CTable.prototype.Selection_Stop = function()
{
	if (true != this.Selection.Use)
		return;

	this.Selection.Start = false;
	var Cell             = this.Content[this.Selection.StartPos.Pos.Row].Get_Cell(this.Selection.StartPos.Pos.Cell);
	Cell.Content_Selection_Stop();
};
CTable.prototype.DrawSelectionOnPage = function(CurPage)
{
	if (false === this.Selection.Use)
		return;

	if (CurPage < 0 || CurPage >= this.Pages.length)
		return;

	var Page    = this.Pages[CurPage];
	var PageAbs = this.private_GetAbsolutePageIndex(CurPage);

	if (this.Parent && selectionflag_Numbering === this.Parent.Selection.Flag)
	{
		for (var CurRow = 0, RowsCount = this.Get_RowsCount(); CurRow < RowsCount; ++CurRow)
		{
			var Row = this.Get_Row(CurRow);
			for (var CurCell = 0, CellsCount = Row.Get_CellsCount(); CurCell < CellsCount; ++CurCell)
			{
				var Cell         = Row.Get_Cell(CurCell);
				var Cell_PageRel = CurPage - Cell.Content.Get_StartPage_Relative();
				Cell.Content_DrawSelectionOnPage(Cell_PageRel);
			}
		}
		return;
	}

	switch (this.Selection.Type)
	{
		case table_Selection_Cell:
		{
			for (var Index = 0; Index < this.Selection.Data.length; ++Index)
			{
				var Pos      = this.Selection.Data[Index];
				var Row      = this.Content[Pos.Row];
				var Cell     = Row.Get_Cell(Pos.Cell);
				var CellInfo = Row.Get_CellInfo(Pos.Cell);
				var CellMar  = Cell.Get_Margins();

				var X_start = (0 === Pos.Cell ? Page.X + CellInfo.X_content_start : Page.X + CellInfo.X_cell_start);
				var X_end   = Page.X + CellInfo.X_cell_end;

				var Cell_Pages   = Cell.Content_Get_PagesCount();
				var Cell_PageRel = CurPage - Cell.Content.Get_StartPage_Relative();
				if (Cell_PageRel < 0 || Cell_PageRel >= Cell_Pages)
					continue;

				var Bounds   = Cell.Content_Get_PageBounds(Cell_PageRel);
				var Y_offset = Cell.Temp.Y_VAlign_offset[Cell_PageRel];

				var RowIndex = 0 != Cell_PageRel ? this.Pages[CurPage].FirstRow : Pos.Row;

				if (true === Cell.Is_VerticalText())
				{
					var X_start       = Page.X + CellInfo.X_cell_start;
					var TextDirection = Cell.Get_TextDirection();

					var MergeCount = this.private_GetVertMergeCountOnPage(CurPage, RowIndex, CellInfo.StartGridCol, Cell.Get_GridSpan());
					if (MergeCount <= 0)
						continue;

					var LastRow = Math.min(RowIndex + MergeCount - 1, this.Pages[CurPage].LastRow);
					var Y_start = this.RowsInfo[RowIndex].Y[CurPage] + this.RowsInfo[RowIndex].TopDy[CurPage] + CellMar.Top.W;
					var Y_end   = this.TableRowsBottom[LastRow][CurPage] - CellMar.Bottom.W;

					if (TextDirection === textdirection_BTLR)
					{
						var SelectionW = Math.min(X_end - X_start - CellMar.Left.W, Bounds.Bottom - Bounds.Top);
						this.DrawingDocument.AddPageSelection(PageAbs, X_start + CellMar.Left.W + Y_offset, Y_start, SelectionW, Y_end - Y_start);
					}
					else if (TextDirection === textdirection_TBRL)
					{
						var SelectionW = Math.min(X_end - X_start - CellMar.Right.W, Bounds.Bottom - Bounds.Top);
						this.DrawingDocument.AddPageSelection(PageAbs, X_end - CellMar.Right.W - Y_offset - SelectionW, Y_start, SelectionW, Y_end - Y_start);
					}
				}
				else
				{
					this.DrawingDocument.AddPageSelection(PageAbs, X_start, this.RowsInfo[RowIndex].Y[CurPage] + this.RowsInfo[RowIndex].TopDy[CurPage] + CellMar.Top.W + Y_offset, X_end - X_start, Bounds.Bottom - Bounds.Top);
				}
			}
			break;
		}
		case table_Selection_Text:
		{
			var Cell         = this.Content[this.Selection.StartPos.Pos.Row].Get_Cell(this.Selection.StartPos.Pos.Cell);
			var Cell_PageRel = CurPage - Cell.Content.Get_StartPage_Relative();
			Cell.Content_DrawSelectionOnPage(Cell_PageRel);
			break;
		}
	}
};
CTable.prototype.RemoveSelection = function()
{
	if (false === this.Selection.Use)
		return;

	if (this.Content.length <= 0)
	{
		this.CurCell = null;
	}
	else
	{
		if (table_Selection_Text === this.Selection.Type)
		{
			this.CurCell = this.Content[this.Selection.StartPos.Pos.Row].Get_Cell(this.Selection.StartPos.Pos.Cell);
			this.CurCell.Content.RemoveSelection();
		}
		else if (this.Content.length > 0 && this.Content[0].Get_CellsCount() > 0)
		{
			this.CurCell = this.Content[0].Get_Cell(0);
			this.CurCell.Content.RemoveSelection();
		}
	}

	this.Selection.Use   = false;
	this.Selection.Start = false;

	this.Selection.StartPos.Pos = {Row : 0, Cell : 0};
	this.Selection.EndPos.Pos   = {Row : 0, Cell : 0};

	this.Markup.Internal.RowIndex  = 0;
	this.Markup.Internal.CellIndex = 0;
	this.Markup.Internal.PageNum   = 0;
};
CTable.prototype.CheckPosInSelection = function(X, Y, CurPage, NearPos)
{
	if (undefined != NearPos)
	{
		if ((true === this.Selection.Use && table_Selection_Cell === this.Selection.Type) || true === this.ApplyToAll)
		{
			var Cells_array = this.Internal_Get_SelectionArray();
			for (var Index = 0; Index < Cells_array.length; Index++)
			{
				var CurPos      = Cells_array[Index];
				var CurCell     = this.Content[CurPos.Row].Get_Cell(CurPos.Cell);
				var CellContent = CurCell.Content;

				CellContent.Set_ApplyToAll(true);

				if (true === CellContent.CheckPosInSelection(0, 0, 0, NearPos))
				{
					CellContent.Set_ApplyToAll(false);
					return true;
				}

				CellContent.Set_ApplyToAll(false);
			}
		}
		else
			return this.CurCell.Content_CheckPosInSelection(0, 0, 0, NearPos);

		return false;
	}
	else
	{
		if (CurPage < 0 || CurPage >= this.Pages.length)
			return false;

		var CellPos = this.Internal_GetCellByXY(X, Y, CurPage);
		if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			for (var Index = 0; Index < this.Selection.Data.length; Index++)
			{
				var CurPos = this.Selection.Data[Index];

				if (CurPos.Cell === CellPos.Cell && CurPos.Row === CellPos.Row)
					return true;
			}

			return false;
		}
		else if (CellPos.Cell === this.CurCell.Index && CellPos.Row === this.CurCell.Row.Index)
			return this.CurCell.Content_CheckPosInSelection(X, Y, CurPage - this.CurCell.Content.Get_StartPage_Relative(), undefined);

		return false;
	}
};
CTable.prototype.IsSelectionEmpty = function(bCheckHidden)
{
	if (true === this.Selection.Use)
	{
		if (table_Selection_Cell === this.Selection.Type)
			return false;
		else
			return this.CurCell.Content.IsSelectionEmpty(bCheckHidden);
	}

	return true;
};
CTable.prototype.SelectAll = function(nDirection)
{
	this.Selection.Use   = true;
	this.Selection.Start = false;
	this.Selection.Type  = table_Selection_Cell;
	this.Selection.Type2 = table_Selection_Common;

	this.Selection.Data2 = null;

	if (nDirection && nDirection < 0)
	{
		this.Selection.EndPos.Pos       = {
			Row  : 0,
			Cell : 0
		};
		this.Selection.EndPos.PageIndex = 0;

		this.Selection.StartPos.Pos       = {
			Row  : this.Content.length - 1,
			Cell : this.Content[this.Content.length - 1].Get_CellsCount() - 1
		};
		this.Selection.StartPos.PageIndex = this.Pages.length - 1;
	}
	else
	{
		this.Selection.StartPos.Pos       = {
			Row  : 0,
			Cell : 0
		};
		this.Selection.StartPos.PageIndex = 0;

		this.Selection.EndPos.Pos       = {
			Row  : this.Content.length - 1,
			Cell : this.Content[this.Content.length - 1].Get_CellsCount() - 1
		};
		this.Selection.EndPos.PageIndex = this.Pages.length - 1;
	}

	this.Internal_Selection_UpdateCells();
};
/**
 * В данной функции проверяется идет ли выделение таблицы до конца таблицы.
 */
CTable.prototype.IsSelectionToEnd = function()
{
	if (true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		var Len         = Cells_array.length;

		if (Len < 1)
			return false;

		var Pos = Cells_array[Len - 1];
		if (Pos.Row !== this.Content.length - 1 || Pos.Cell !== this.Content[Pos.Row].Get_CellsCount() - 1)
			return false;

		return true;
	}
	else
		return false;
};
CTable.prototype.SetSelectionUse = function(isUse)
{
	if (true === isUse)
		this.Selection.Use = true;
	else
		this.RemoveSelection();
};
CTable.prototype.SetSelectionToBeginEnd = function(isSelectionStart, isElementStart)
{
	var Pos;
	if (false === isElementStart)
	{
		var Row  = this.Content.length - 1;
		var Cell = this.Content[Row].Get_CellsCount() - 1;

		Pos = {Row : Row, Cell : Cell};
	}
	else
	{
		Pos = {Row : 0, Cell : 0};
	}

	if (isSelectionStart)
		this.Selection.StartPos.Pos = Pos;
	else
		this.Selection.EndPos.Pos = Pos;


	this.Internal_Selection_UpdateCells();
};
CTable.prototype.MoveCursorToStartPos = function(AddToSelect)
{
	if (true === AddToSelect)
	{
		var StartRow = ( true === this.Selection.Use ? this.Selection.StartPos.Pos.Row : this.CurCell.Row.Index );
		var EndRow   = 0;

		this.Selection.Use          = true;
		this.Selection.Start        = false;
		this.Selection.Type         = table_Selection_Cell;
		this.Selection.Type2        = table_Selection_Common;
		this.Selection.StartPos.Pos = {Row : StartRow, Cell : this.Content[StartRow].Get_CellsCount() - 1};
		this.Selection.EndPos.Pos   = {Row : EndRow, Cell : 0};
		this.Selection.CurRow       = EndRow;

		this.Internal_Selection_UpdateCells();
	}
	else
	{
		this.CurCell = this.Content[0].Get_Cell(0);

		this.Selection.Use          = false;
		this.Selection.Start        = false;
		this.Selection.StartPos.Pos = {Row : 0, Cell : 0};
		this.Selection.EndPos.Pos   = {Row : 0, Cell : 0};
		this.Selection.CurRow       = 0;

		this.CurCell.Content_MoveCursorToStartPos();
	}
};
CTable.prototype.MoveCursorToEndPos = function(AddToSelect)
{
	if (true === AddToSelect)
	{
		var StartRow = ( true === this.Selection.Use ? this.Selection.StartPos.Pos.Row : this.CurCell.Row.Index );
		var EndRow   = this.Content.length - 1;

		this.Selection.Use          = true;
		this.Selection.Start        = false;
		this.Selection.Type         = table_Selection_Cell;
		this.Selection.Type2        = table_Selection_Common;
		this.Selection.StartPos.Pos = {Row : StartRow, Cell : 0};
		this.Selection.EndPos.Pos   = {Row : EndRow, Cell : this.Content[EndRow].Get_CellsCount() - 1};
		this.Selection.CurRow       = EndRow;

		this.Internal_Selection_UpdateCells();
	}
	else
	{
		var Row      = this.Content[this.Content.length - 1];
		this.CurCell = Row.Get_Cell(Row.Get_CellsCount() - 1);

		this.Selection.Use          = false;
		this.Selection.Start        = false;
		this.Selection.StartPos.Pos = {Row : Row.Index, Cell : this.CurCell.Index};
		this.Selection.EndPos.Pos   = {Row : Row.Index, Cell : this.CurCell.Index};
		this.Selection.CurRow       = Row.Index;

		this.CurCell.Content_MoveCursorToEndPos();
	}
};
CTable.prototype.IsCursorAtBegin = function(bOnlyPara)
{
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
	{
		if (0 === this.CurCell.Index && 0 === this.CurCell.Row.Index)
		{
			return this.CurCell.Content.IsCursorAtBegin(bOnlyPara);
		}
	}

	return false;
};
CTable.prototype.IsCursorAtEnd = function()
{
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
	{
		if (0 === this.CurCell.Index && 0 === this.CurCell.Row.Index)
		{
			return this.CurCell.Content.IsCursorAtEnd();
		}
	}

	return false;
};
//----------------------------------------------------------------------------------------------------------------------
// Работаем с содержимым таблицы
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.AddNewParagraph = function()
{
	this.CurCell.Content.AddNewParagraph();
};
CTable.prototype.AddInlineImage = function(W, H, Img, Chart, bFlow)
{
	this.Selection.Use  = true;
	this.Selection.Type = table_Selection_Text;
	this.CurCell.Content.AddInlineImage(W, H, Img, Chart, bFlow);
};
CTable.prototype.AddOleObject = function(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId)
{
	this.Selection.Use  = true;
	this.Selection.Type = table_Selection_Text;
	this.CurCell.Content.AddOleObject(W, H, nWidthPix, nHeightPix, Img, Data, sApplicationId);
};
CTable.prototype.AddTextArt = function(nStyle)
{
	this.Selection.Use  = true;
	this.Selection.Type = table_Selection_Text;
	this.CurCell.Content.AddTextArt(nStyle);
};
CTable.prototype.AddInlineTable = function(Cols, Rows)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		return;

	this.CurCell.Content.AddInlineTable(Cols, Rows);
};
CTable.prototype.Add = function(ParaItem, bRecalculate)
{
	this.AddToParagraph(ParaItem, bRecalculate);
};
CTable.prototype.AddToParagraph = function(ParaItem, bRecalculate)
{
	if (para_TextPr === ParaItem.Type && ( true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ) ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.AddToParagraph(ParaItem, bRecalculate);
			Cell_Content.Set_ApplyToAll(false);
		}

		// Если в TextPr только HighLight, тогда не надо ничего пересчитывать, только перерисовываем
		if (true === ParaItem.Value.Check_NeedRecalc())
		{
			if (Cells_array[0].Row - 1 >= 0)
				this.Internal_RecalculateFrom(Cells_array[0].Row - 1, 0, true, true);
			else
			{
				this.Internal_Recalculate_1();
			}
		}
		else
		{
			this.Parent.OnContentReDraw(this.Get_AbsolutePage(0), this.Get_AbsolutePage(this.Pages.length - 1));
		}
	}
	else
	{
		this.CurCell.Content.AddToParagraph(ParaItem, bRecalculate);
	}
};
CTable.prototype.ClearParagraphFormatting = function()
{
	if (true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.ClearParagraphFormatting();
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		this.CurCell.Content.ClearParagraphFormatting();
	}
};
CTable.prototype.PasteFormatting = function(TextPr, ParaPr, ApplyPara)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.PasteFormatting(TextPr, ParaPr, true);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		this.CurCell.Content.PasteFormatting(TextPr, ParaPr, false);
	}
};
CTable.prototype.Remove = function(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();

		if (true === bOnTextAdd && Cells_array.length > 0)
		{
			// Снимаем выделением со всех ячеек, кроме первой, попавшей в выделение
			var Pos  = Cells_array[0];
			var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			Cell.Content.SelectAll();
			Cell.Content.Remove(Count, bOnlyText, bRemoveOnlySelection, true);

			this.CurCell = Cell;

			this.Selection.Use   = false;
			this.Selection.Start = false;

			this.Selection.StartPos.Pos = {Row : Cell.Row.Index, Cell : Cell.Index};
			this.Selection.EndPos.Pos   = {Row : Cell.Row.Index, Cell : Cell.Index};

			this.Document_SetThisElementCurrent(true);

			editor.WordControl.m_oLogicDocument.Recalculate();
		}
		else
		{
			var Cells_array = this.Internal_Get_SelectionArray();
			for (var Index = 0; Index < Cells_array.length; Index++)
			{
				var Pos  = Cells_array[Index];
				var Row  = this.Content[Pos.Row];
				var Cell = Row.Get_Cell(Pos.Cell);

				var Cell_Content = Cell.Content;
				Cell_Content.Set_ApplyToAll(true);
				Cell.Content.Remove(Count, bOnlyText, bRemoveOnlySelection, false);
				Cell_Content.Set_ApplyToAll(false);
			}

			// Снимаем выделение
			var Pos      = Cells_array[0];
			var Cell     = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			this.CurCell = Cell;

			this.Selection.Use   = false;
			this.Selection.Start = false;

			this.Selection.StartPos.Pos = {Row : Cell.Row.Index, Cell : Cell.Index};
			this.Selection.EndPos.Pos   = {Row : Cell.Row.Index, Cell : Cell.Index};

			if (Cells_array[0].Row - 1 >= 0)
				this.Internal_RecalculateFrom(Cells_array[0].Row - 1, 0, true, true);
			else
			{
				this.Internal_Recalculate_1();
			}
		}
	}
	else
	{
		this.CurCell.Content.Remove(Count, bOnlyText, bRemoveOnlySelection, bOnTextAdd);

		if (false === this.CurCell.Content.IsSelectionUse())
		{
			var Cell = this.CurCell;

			this.Selection.Use   = false;
			this.Selection.Start = false;

			this.Selection.StartPos.Pos = {Row : Cell.Row.Index, Cell : Cell.Index};
			this.Selection.EndPos.Pos   = {Row : Cell.Row.Index, Cell : Cell.Index};
		}
	}
};
CTable.prototype.GetCursorPosXY = function()
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		if (this.Selection.Data.length < 0)
			return {X : 0, Y : 0};

		var Pos  = this.Selection.Data[0];
		var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
		var Para = Cell.Content.Get_FirstParagraph();

		return {X : Para.X, Y : Para.Y}
	}
	else
		return this.CurCell.Content.GetCursorPosXY();
};
CTable.prototype.MoveCursorLeft = function(AddToSelect, Word)
{
	if (true === this.Selection.Use && this.Selection.Type === table_Selection_Cell)
	{
		if (true === AddToSelect)
		{
			var StartPos = this.Selection.StartPos.Pos;
			var EndPos   = this.Selection.EndPos.Pos;

			if (StartPos.Cell == EndPos.Cell && StartPos.Row == EndPos.Row && 0 === this.Parent.GetSelectDirection())
			{
				// Если была выделена одна ячейка, тогда мы убираем выделение по ячейкам
				this.Selection.Type = table_Selection_Text;
				return true;
			}
			else
			{
				// Если текущая ячейка - первая в первой строке и данная таблица - первый элемент, тогда мы ничего не
				// делаем
				if (0 == EndPos.Cell && 0 == EndPos.Row && ( null === this.Get_DocumentPrev() && true === this.Parent.Is_TopDocument() ))
					return false;

				// Если текущая ячейка - первая в первой строке (и таблица не первый элемент документа),
				// тогда мы выделаяем первую строку

				var bRet = true;
				if (0 == EndPos.Cell && 0 == EndPos.Row || ( 0 !== this.Parent.GetSelectDirection() && 0 == EndPos.Row && 0 == StartPos.Row ))
				{
					this.Selection.EndPos.Pos = {Cell : 0, Row : 0};
					bRet                      = false;
				}
				//else if ( EndPos.Cell > 0 && EndPos.Cell > StartPos.Cell && 0 ===
				// this.Parent.GetSelectDirection() ) this.Selection.EndPos.Pos = { Cell : EndPos.Cell - 1, Row :
				// EndPos.Row }; else if ( EndPos.Row > 0 && EndPos.Row > StartPos.Row && 0 ===
				// this.Parent.GetSelectDirection() ) this.Selection.EndPos.Pos = { Cell : Math.min( EndPos.Cell,
				// this.Content[EndPos.Row - 1].Get_CellsCount() - 1 ), Row : EndPos.Row - 1 };
				else if (EndPos.Cell > 0 && 0 === this.Parent.GetSelectDirection())
					this.Selection.EndPos.Pos = {Cell : EndPos.Cell - 1, Row : EndPos.Row};
				else
					this.Selection.EndPos.Pos = {Cell : 0, Row : EndPos.Row - 1};

				var bForceSelectByLines = false;
				if (false === bRet && true == this.Is_Inline())
					bForceSelectByLines = true;

				this.Internal_Selection_UpdateCells(bForceSelectByLines);

				return bRet;
			}
		}
		else
		{
			// Перемещаем курсор в начало первой выделенной ячейки
			this.Selection.Use = false;
			var Pos            = this.Selection.Data[0];
			this.CurCell       = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			this.CurCell.Content_MoveCursorToStartPos();
			return true;
		}
	}
	else
	{
		if (false === this.CurCell.Content.MoveCursorLeft(AddToSelect, Word))
		{
			if (false === AddToSelect)
			{
				if (0 != this.CurCell.Index || 0 != this.CurCell.Row.Index)
				{
					if (0 != this.CurCell.Index)
					{
						this.CurCell = this.Internal_Get_StartMergedCell2(this.CurCell.Index - 1, this.Selection.CurRow);
					}
					else //if ( 0 != this.CurCell.Row.Index  )
					{
						this.Selection.CurRow = Math.max(this.Selection.CurRow - 1, 0);
						this.CurCell          = this.Internal_Get_StartMergedCell2(this.Content[this.Selection.CurRow].Get_CellsCount() - 1, this.Selection.CurRow);
					}

					this.CurCell.Content.MoveCursorToEndPos();
				}
				else
					return false;
			}
			else
			{
				// Если текущая ячейка - первая в первой строке и данная таблица - первый элемент, тогда мы ничего не
				// делаем
				if (0 == this.CurCell.Index && 0 == this.CurCell.Row.Index && ( null === this.Get_DocumentPrev() && true === this.Parent.Is_TopDocument() ))
					return false;

				this.Selection.Use  = true;
				this.Selection.Type = table_Selection_Cell;

				// Если текущая ячейка - первая в первой строке (и таблица не первый элемент документа),
				// тогда мы выделаяем первую строку

				var bRet                    = true;
				this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};

				if (0 == this.CurCell.Index && 0 == this.CurCell.Row.Index)
				{
					this.Selection.EndPos.Pos = {Cell : this.CurCell.Row.Get_CellsCount() - 1, Row : 0};
					bRet                      = false;
				}
				else if (this.CurCell.Index > 0)
					this.Selection.EndPos.Pos = {Cell : this.CurCell.Index - 1, Row : this.CurCell.Row.Index};
				else
					this.Selection.EndPos.Pos = {Cell : 0, Row : this.CurCell.Row.Index - 1};

				this.Internal_Selection_UpdateCells();

				return bRet;
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use          = true;
				this.Selection.Type         = table_Selection_Text;
				this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
				this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
			}

			return true;
		}
	}
};
CTable.prototype.MoveCursorLeftWithSelectionFromEnd = function(Word)
{
	if (true === this.IsSelectionUse())
		this.RemoveSelection();

	if (this.Content.length <= 0)
		return;

	var LastRow = this.Content[this.Content.length - 1];

	// Нам нужно выделить последний ряд таблицы

	this.Selection.Use          = true;
	this.Selection.Type         = table_Selection_Cell;
	this.Selection.StartPos.Pos = {
		Row  : LastRow.Index,
		Cell : LastRow.Get_CellsCount() - 1
	};
	this.Selection.EndPos.Pos   = {
		Row  : LastRow.Index,
		Cell : 0
	};
	this.CurCell                = LastRow.Get_Cell(0);
	this.Selection.Data         = [];

	for (var CellIndex = 0; CellIndex < LastRow.Get_CellsCount(); CellIndex++)
	{
		this.Selection.Data.push({Cell : CellIndex, Row : LastRow.Index});
	}
};
CTable.prototype.MoveCursorRight = function(AddToSelect, Word, FromPaste)
{
	if (true === this.Selection.Use && this.Selection.Type === table_Selection_Cell)
	{
		if (true === AddToSelect)
		{
			var StartPos = this.Selection.StartPos.Pos;
			var EndPos   = this.Selection.EndPos.Pos;

			if (StartPos.Cell == EndPos.Cell && StartPos.Row == EndPos.Row && 0 === this.Parent.GetSelectDirection())
			{
				// Если была выделена одна ячейка, тогда мы убираем выделение по ячейкам
				this.Selection.Type = table_Selection_Text;
				return true;
			}
			else
			{
				// Если текущая ячейка - последняя в последней строке, тогда мы выделаяем последнюю строку
				var LastRow = this.Content[this.Content.length - 1];
				var EndRow  = this.Content[EndPos.Row];

				var bRet = true;
				if ((LastRow.Get_CellsCount() - 1 == EndPos.Cell && this.Content.length - 1 == EndPos.Row) || ( 0 !== this.Parent.GetSelectDirection() && this.Content.length - 1 == EndPos.Row && this.Content.length - 1 == StartPos.Row ))
				{
					this.Selection.EndPos.Pos = {Cell : LastRow.Get_CellsCount() - 1, Row : LastRow.Index};
					bRet                      = false;
				}
				//else if ( EndPos.Cell < EndRow.Get_CellsCount() - 1 && EndPos.Cell < StartPos.Cell && 0 ===
				// this.Parent.GetSelectDirection() ) this.Selection.EndPos.Pos = { Cell : EndPos.Cell + 1, Row :
				// EndPos.Row }; else if ( EndPos.Row < this.Content.length - 1 && EndPos.Row < StartPos.Row && 0 ===
				// this.Parent.GetSelectDirection() ) this.Selection.EndPos.Pos = { Cell : Math.min( EndPos.Cell,
				// this.Content[EndPos.Row + 1].Get_CellsCount() - 1 ), Row : EndPos.Row + 1 };
				else if (EndPos.Cell < EndRow.Get_CellsCount() - 1 && 0 === this.Parent.GetSelectDirection())
					this.Selection.EndPos.Pos = {Cell : EndPos.Cell + 1, Row : EndPos.Row};
				else
					this.Selection.EndPos.Pos = {
						Cell : this.Content[EndPos.Row + 1].Get_CellsCount() - 1,
						Row  : EndPos.Row + 1
					};

				var bForceSelectByLines = false;
				if (false === bRet && true == this.Is_Inline())
					bForceSelectByLines = true;

				this.Internal_Selection_UpdateCells(bForceSelectByLines);

				return bRet;
			}
		}
		else
		{
			// Перемещаем курсор в конец последней выделенной ячейки
			this.Selection.Use = false;
			var Pos            = this.Selection.Data[this.Selection.Data.length - 1];
			this.CurCell       = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			this.CurCell.Content_MoveCursorToEndPos();
			return true;
		}
	}
	else
	{
		if (false === this.CurCell.Content.MoveCursorRight(AddToSelect, Word, FromPaste))
		{
			if (false === AddToSelect)
			{
				if (this.Content.length - 1 > this.CurCell.Row.Index || this.Content[this.CurCell.Row.Index].Get_CellsCount() - 1 > this.CurCell.Index)
				{
					if (this.Content[this.CurCell.Row.Index].Get_CellsCount() - 1 > this.CurCell.Index)
					{
						this.CurCell = this.Internal_Get_StartMergedCell2(this.CurCell.Index + 1, this.Selection.CurRow);
					}
					else //if ( this.Content.length - 1 > this.CurCell.Row.Index  )
					{
						this.Selection.CurRow = Math.min(this.Content.length - 1, this.Selection.CurRow + 1);
						this.CurCell          = this.Internal_Get_StartMergedCell2(0, this.Selection.CurRow);
					}

					this.CurCell.Content.MoveCursorToStartPos();
				}
				else
					return false;
			}
			else
			{
				this.Selection.Use  = true;
				this.Selection.Type = table_Selection_Cell;

				// Если текущая ячейка - последняя в последней строке, тогда мы выделаяем последнюю строку
				var LastRow = this.Content[this.Content.length - 1];
				var CurRow  = this.CurCell.Row;

				var bRet                    = true;
				this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};

				if (LastRow.Get_CellsCount() - 1 == this.CurCell.Index && LastRow.Index == this.CurCell.Row.Index)
				{
					this.Selection.EndPos.Pos = {Cell : LastRow.Get_CellsCount() - 1, Row : LastRow.Index};
					bRet                      = false;
				}
				else if (this.CurCell.Index < CurRow.Get_CellsCount() - 1)
					this.Selection.EndPos.Pos = {Cell : this.CurCell.Index + 1, Row : this.CurCell.Row.Index};
				else
					this.Selection.EndPos.Pos = {
						Cell : this.Content[this.CurCell.Row.Index + 1].Get_CellsCount() - 1,
						Row  : this.CurCell.Row.Index + 1
					};

				var bForceSelectByLines = false;
				if (false === bRet && true == this.Is_Inline())
					bForceSelectByLines = true;

				this.Internal_Selection_UpdateCells(bForceSelectByLines);

				return bRet;
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use          = true;
				this.Selection.Type         = table_Selection_Text;
				this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
				this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};

			}

			return true;
		}
	}
};
CTable.prototype.MoveCursorRightWithSelectionFromStart = function(Word)
{
	if (true === this.IsSelectionUse())
		this.RemoveSelection();

	if (this.Content.length <= 0)
		return;

	var FirstRow = this.Content[0];

	// Нам нужно выделить первый ряд таблицы
	this.Selection.Use          = true;
	this.Selection.Type         = table_Selection_Cell;
	this.Selection.StartPos.Pos = {
		Row  : 0,
		Cell : 0
	};
	this.Selection.EndPos.Pos   = {
		Row  : 0,
		Cell : FirstRow.Get_CellsCount() - 1
	};
	this.CurCell                = FirstRow.Get_Cell(FirstRow.Get_CellsCount() - 1);
	this.Selection.Data         = [];

	for (var CellIndex = 0; CellIndex < FirstRow.Get_CellsCount(); CellIndex++)
	{
		this.Selection.Data.push({Cell : CellIndex, Row : 0});
	}
};
CTable.prototype.MoveCursorUp = function(AddToSelect)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		if (true === AddToSelect)
		{
			var bRetValue = true;
			var EndPos    = this.Selection.EndPos.Pos;
			if (0 === EndPos.Row)
			{
				bRetValue = false;
			}
			else
			{
				var EndCell = this.Content[EndPos.Row].Get_Cell(EndPos.Cell);

				var X = EndCell.Content_GetCurPosXY().X;
				var Y = EndCell.Content_GetCurPosXY().Y;

				var PrevRow = this.Content[EndPos.Row - 1];
				var Cell    = null;
				for (var CurCell = 0; CurCell < PrevRow.Get_CellsCount(); CurCell++)
				{
					Cell         = PrevRow.Get_Cell(CurCell);
					var CellInfo = PrevRow.Get_CellInfo(CurCell);
					if (X <= CellInfo.X_grid_end)
						break;
				}

				if (null === Cell)
					return true;

				Cell.Content_Set_CurPosXY(X, Y);
				this.CurCell              = Cell;
				this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
			}

			var bForceSelectByLines = false;
			if (false === bRetValue && true === this.Is_Inline())
				bForceSelectByLines = true;

			this.Internal_Selection_UpdateCells(bForceSelectByLines);
			return bRetValue;
		}
		else
		{
			if (this.Selection.Data.length < 0)
				return true;

			var Pos  = this.Selection.Data[0];
			var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			var Para = Cell.Content.Get_FirstParagraph();
			var X    = Para.X;
			var Y    = Para.Y;

			this.Selection.Use = false;
			if (0 === Pos.Row)
			{
				this.CurCell = Cell;
				this.CurCell.Content.MoveCursorToStartPos();
				this.CurCell.Content_Set_CurPosXY(X, Y);

				return false;
			}
			else
			{
				var PrevRow  = this.Content[Pos.Row - 1];
				var PrevCell = null;
				for (var CurCell = 0; CurCell < PrevRow.Get_CellsCount(); CurCell++)
				{
					PrevCell     = PrevRow.Get_Cell(CurCell);
					var CellInfo = PrevRow.Get_CellInfo(CurCell);
					if (X <= CellInfo.X_grid_end)
						break;
				}

				if (null === PrevCell)
					return true;

				PrevCell.Content_MoveCursorUpToLastRow(X, Y, false);
				this.CurCell = PrevCell;
				return true;
			}

		}
	}
	else
	{
		if (false === this.CurCell.Content.MoveCursorUp(AddToSelect))
		{
			// Ничего не делаем, если это "плавающая" таблица или первый элемент документа
			if (0 === this.CurCell.Row.Index && (false === this.Is_Inline() || ( null === this.Get_DocumentPrev() && true === this.Parent.Is_TopDocument() )))
				return true;

			if (true === AddToSelect)
			{
				this.Selection.Use          = true;
				this.Selection.Type         = table_Selection_Cell;
				this.Selection.StartPos.Pos = {Row : this.CurCell.Row.Index, Cell : this.CurCell.Index};

				var bRetValue = true;
				if (0 === this.CurCell.Row.Index)
				{
					this.Selection.EndPos.Pos = {Row : 0, Cell : 0};
					bRetValue                 = false;
				}
				else
				{
					var X       = this.CurCell.Content_GetCurPosXY().X;
					var Y       = this.CurCell.Content_GetCurPosXY().Y;
					var PrevRow = this.Content[this.CurCell.Row.Index - 1];
					var Cell    = null;
					for (var CurCell = 0; CurCell < PrevRow.Get_CellsCount(); CurCell++)
					{
						Cell         = PrevRow.Get_Cell(CurCell);
						var CellInfo = PrevRow.Get_CellInfo(CurCell);
						if (X <= CellInfo.X_grid_end)
							break;
					}

					if (null === Cell)
						return true;

					Cell.Content_Set_CurPosXY(X, Y);
					this.CurCell              = Cell;
					this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
				}

				var bForceSelectByLines = false;
				if (false === bRetValue && true === this.Is_Inline())
					bForceSelectByLines = true;

				this.Internal_Selection_UpdateCells(bForceSelectByLines);
				return bRetValue;
			}
			else
			{
				if (0 === this.CurCell.Row.Index)
					return false;
				else
				{
					var X       = this.CurCell.Content_GetCurPosXY().X;
					var Y       = this.CurCell.Content_GetCurPosXY().Y;
					var PrevRow = this.Content[this.CurCell.Row.Index - 1];
					var Cell    = null;
					for (var CurCell = 0; CurCell < PrevRow.Get_CellsCount(); CurCell++)
					{
						Cell         = PrevRow.Get_Cell(CurCell);
						var CellInfo = PrevRow.Get_CellInfo(CurCell);
						if (X <= CellInfo.X_grid_end)
							break;
					}

					if (null === Cell)
						return true;

					Cell = this.Internal_Get_StartMergedCell2(Cell.Index, Cell.Row.Index);
					Cell.Content_MoveCursorUpToLastRow(X, Y, false);
					this.CurCell              = Cell;
					this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
					this.Selection.CurRow     = Cell.Row.Index;

					return true;
				}
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use          = true;
				this.Selection.Type         = table_Selection_Text;
				this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
				this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
			}

			return true;
		}
	}
};
CTable.prototype.MoveCursorDown = function(AddToSelect)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		if (true === AddToSelect)
		{
			var bRetValue = true;
			var EndPos    = this.Selection.EndPos.Pos;
			if (this.Content.length - 1 === EndPos.Row)
			{
				bRetValue = false;
			}
			else
			{
				var EndCell = this.Content[EndPos.Row].Get_Cell(EndPos.Cell);

				var X = EndCell.Content_GetCurPosXY().X;
				var Y = EndCell.Content_GetCurPosXY().Y;

				var NextRow = this.Content[EndPos.Row + 1];
				var Cell    = null;
				for (var CurCell = 0; CurCell < NextRow.Get_CellsCount(); CurCell++)
				{
					Cell         = NextRow.Get_Cell(CurCell);
					var CellInfo = NextRow.Get_CellInfo(CurCell);
					if (X <= CellInfo.X_grid_end)
						break;
				}

				if (null === Cell)
					return true;

				Cell.Content_Set_CurPosXY(X, Y);
				this.CurCell              = Cell;
				this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
			}

			var bForceSelectByLines = false;
			if (false === bRetValue && true === this.Is_Inline())
				bForceSelectByLines = true;

			this.Internal_Selection_UpdateCells(bForceSelectByLines);
			return bRetValue;
		}
		else
		{
			if (this.Selection.Data.length < 0)
				return true;

			var Pos  = this.Selection.Data[this.Selection.Data.length - 1];
			var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
			var Para = Cell.Content.Get_FirstParagraph();
			var X    = Para.X;
			var Y    = Para.Y;

			this.Selection.Use = false;
			if (this.Content.length - 1 === Pos.Row)
			{
				this.CurCell = Cell;
				this.CurCell.Content.MoveCursorToStartPos();
				this.CurCell.Content_Set_CurPosXY(X, Y);

				return false;
			}
			else
			{
				var NextRow  = this.Content[Pos.Row + 1];
				var NextCell = null;
				for (var CurCell = 0; CurCell < NextRow.Get_CellsCount(); CurCell++)
				{
					NextCell     = NextRow.Get_Cell(CurCell);
					var CellInfo = NextRow.Get_CellInfo(CurCell);
					if (X <= CellInfo.X_grid_end)
						break;
				}

				if (null === NextCell)
					return true;

				NextCell.Content_MoveCursorDownToFirstRow(X, Y, false);
				this.CurCell = NextCell;
				return true;
			}

		}
	}
	else
	{
		if (false === this.CurCell.Content.MoveCursorDown(AddToSelect))
		{
			if (true === AddToSelect)
			{
				this.Selection.Use          = true;
				this.Selection.Type         = table_Selection_Cell;
				this.Selection.StartPos.Pos = {Row : this.CurCell.Row.Index, Cell : this.CurCell.Index};

				var bRetValue = true;
				if (this.Content.length - 1 === this.CurCell.Row.Index)
				{
					this.Selection.EndPos.Pos = {
						Row  : this.Content.length - 1,
						Cell : this.Content[this.Content.length - 1].Get_CellsCount() - 1
					};
					bRetValue                 = false;
				}
				else
				{
					var X       = this.CurCell.Content_GetCurPosXY().X;
					var Y       = this.CurCell.Content_GetCurPosXY().Y;
					var NextRow = this.Content[this.CurCell.Row.Index + 1];
					var Cell    = null;
					for (var CurCell = 0; CurCell < NextRow.Get_CellsCount(); CurCell++)
					{
						Cell         = NextRow.Get_Cell(CurCell);
						var CellInfo = NextRow.Get_CellInfo(CurCell);
						if (X <= CellInfo.X_grid_end)
							break;
					}

					if (null === Cell)
						return true;

					Cell.Content_Set_CurPosXY(X, Y);
					this.CurCell              = Cell;
					this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
				}

				var bForceSelectByLines = false;
				if (false === bRetValue && true === this.Is_Inline())
					bForceSelectByLines = true;

				this.Internal_Selection_UpdateCells(bForceSelectByLines);
				return bRetValue;
			}
			else
			{
				var VMerge_count = this.Internal_GetVertMergeCount(this.CurCell.Row.Index, this.CurCell.Row.Get_CellInfo(this.CurCell.Index).StartGridCol, this.CurCell.Get_GridSpan());

				if (this.Content.length - 1 === this.CurCell.Row.Index + VMerge_count - 1)
					return false;
				else
				{
					var X = this.CurCell.Content_GetCurPosXY().X;
					var Y = this.CurCell.Content_GetCurPosXY().Y;

					var NextRow = this.Content[this.CurCell.Row.Index + VMerge_count];
					var Cell    = null;
					for (var CurCell = 0; CurCell < NextRow.Get_CellsCount(); CurCell++)
					{
						Cell         = NextRow.Get_Cell(CurCell);
						var CellInfo = NextRow.Get_CellInfo(CurCell);
						if (X <= CellInfo.X_grid_end)
							break;
					}

					if (null === Cell)
						return true;

					Cell.Content_MoveCursorDownToFirstRow(X, Y, false);
					this.CurCell              = Cell;
					this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
					this.Selection.CurRow     = Cell.Row.Index;

					return true;
				}
			}
		}
		else
		{
			if (true === AddToSelect)
			{
				this.Selection.Use          = true;
				this.Selection.Type         = table_Selection_Text;
				this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
				this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
			}

			return true;
		}
	}
};
CTable.prototype.MoveCursorToEndOfLine = function(AddToSelect)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		return this.MoveCursorRight(AddToSelect, false);
	else
	{
		var bRetValue = this.CurCell.Content.MoveCursorToEndOfLine(AddToSelect);
		if (true === this.CurCell.Content.IsSelectionUse())
		{
			this.Selection.Use          = true;
			this.Selection.Type         = table_Selection_Text;
			this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
			this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
		}
		else
		{
			this.Selection.Use = false;
		}

		return bRetValue;
	}
};
CTable.prototype.MoveCursorToStartOfLine = function(AddToSelect)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		return this.MoveCursorLeft(AddToSelect, false);
	else
	{
		var bRetValue = this.CurCell.Content.MoveCursorToStartOfLine(AddToSelect);
		if (true === this.CurCell.Content.IsSelectionUse())
		{
			this.Selection.Use          = true;
			this.Selection.Type         = table_Selection_Text;
			this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
			this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
		}
		else
		{
			this.Selection.Use = false;
		}

		return bRetValue;
	}
};
CTable.prototype.MoveCursorUpToLastRow = function(X, Y, AddToSelect)
{
	if (true === AddToSelect)
	{
		if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			var Row  = this.Content[this.Content.length - 1];
			var Cell = null;
			for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
			{
				Cell         = Row.Get_Cell(CurCell);
				var CellInfo = Row.Get_CellInfo(CurCell);
				if (X <= CellInfo.X_grid_end)
					break;
			}

			if (null === Cell)
				return true;

			Cell.Content_Set_CurPosXY(X, Y);
			this.CurCell              = Cell;
			this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
			this.Internal_Selection_UpdateCells();
		}
		else
		{
			this.Selection.Use          = true;
			this.Selection.Type         = table_Selection_Cell;
			this.Selection.StartPos.Pos = {
				Row  : this.Content.length - 1,
				Cell : this.Content[this.Content.length - 1].Get_CellsCount() - 1
			};
			this.Selection.EndPos.Pos   = {Row : this.Content.length - 1, Cell : 0};

			this.Internal_Selection_UpdateCells();

			// У последней ячейки у первого параграфа, мы выставим RealX, RealY
			var Cell = this.Content[this.Content.length - 1].Get_Cell(0);
			Cell.Content_Set_CurPosXY(X, Y);
		}
	}
	else
	{
		this.RemoveSelection();
		var Row  = this.Content[this.Content.length - 1];
		var Cell = null;
		for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
		{
			Cell         = Row.Get_Cell(CurCell);
			var CellInfo = Row.Get_CellInfo(CurCell);
			if (X <= CellInfo.X_grid_end)
				break;
		}

		if (null === Cell)
			return;
		Cell = this.Internal_Get_StartMergedCell2(Cell.Index, Cell.Row.Index);
		Cell.Content_MoveCursorUpToLastRow(X, Y, false);
		this.Selection.CurRow = Cell.Row.Index;

		this.CurCell = Cell;
	}
};
CTable.prototype.MoveCursorDownToFirstRow = function(X, Y, AddToSelect)
{
	if (true === AddToSelect)
	{
		if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			var Row  = this.Content[0];
			var Cell = null;
			for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
			{
				Cell         = Row.Get_Cell(CurCell);
				var CellInfo = Row.Get_CellInfo(CurCell);
				if (X <= CellInfo.X_grid_end)
					break;
			}

			if (null === Cell)
				return true;

			Cell.Content_Set_CurPosXY(X, Y);
			this.CurCell              = Cell;
			this.Selection.EndPos.Pos = {Cell : Cell.Index, Row : Cell.Row.Index};
			this.Internal_Selection_UpdateCells();
		}
		else
		{
			this.Selection.Use          = true;
			this.Selection.Type         = table_Selection_Cell;
			this.Selection.StartPos.Pos = {Row : 0, Cell : 0};
			this.Selection.EndPos.Pos   = {Row : 0, Cell : this.Content[0].Get_CellsCount() - 1};

			this.Internal_Selection_UpdateCells();

			// У последней ячейки у первого параграфа, мы выставим RealX, RealY
			var Cell = this.Content[0].Get_Cell(0);
			Cell.Content_Set_CurPosXY(X, Y);
		}
	}
	else
	{
		this.RemoveSelection();
		var Row  = this.Content[0];
		var Cell = null;
		for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
		{
			Cell         = Row.Get_Cell(CurCell);
			var CellInfo = Row.Get_CellInfo(CurCell);
			if (X <= CellInfo.X_grid_end)
				break;
		}

		if (null === Cell)
			return;

		Cell.Content_MoveCursorDownToFirstRow(X, Y, false);
		this.Selection.CurRow = Cell.Row.Index;
		this.CurCell          = Cell;
	}
};
CTable.prototype.MoveCursorToCell = function(bNext)
{
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		var Pos             = this.Selection.Data[0];
		this.Selection.Type = table_Selection_Text;
		this.CurCell        = this.Content[Pos.Row].Get_Cell(Pos.Cell);
		this.CurCell.Content.SelectAll();
	}
	else
	{
		if (true === this.IsInnerTable())
			return this.CurCell.Content.MoveCursorToCell(bNext);

		var CurCell = this.CurCell;
		var Pos_c   = this.CurCell.Index;
		var Pos_r   = this.CurCell.Row.Index;
		var Pos     = {
			Cell : Pos_c,
			Row  : Pos_r
		};

		if (true === bNext)
		{
			var TempCell = this.Internal_Get_NextCell(Pos);
			while (null != TempCell && vmerge_Restart != TempCell.Get_VMerge())
				TempCell = this.Internal_Get_NextCell(Pos);

			if (null != TempCell)
				CurCell = TempCell;
			else
			{
				if (false == editor.WordControl.m_oLogicDocument.Document_Is_SelectionLocked(AscCommon.changestype_None, {
						Type      : AscCommon.changestype_2_Element_and_Type,
						Element   : this,
						CheckType : AscCommon.changestype_Table_Properties
					}))
				{
					History.Create_NewPoint(AscDFH.historydescription_Document_TableAddNewRowByTab);
					this.AddTableRow(false);
				}
				else
					return;

				var TempCell = this.Internal_Get_NextCell(Pos);
				while (null != TempCell && vmerge_Restart != TempCell.Get_VMerge())
					TempCell = this.Internal_Get_NextCell(Pos);

				if (null != TempCell)
					CurCell = TempCell;
			}
		}
		else
		{
			var TempCell = this.Internal_Get_PrevCell(Pos);
			while (null != TempCell && vmerge_Restart != TempCell.Get_VMerge())
				TempCell = this.Internal_Get_PrevCell(Pos);

			if (null != TempCell)
				CurCell = TempCell;
		}

		// Предварительно очистим текущий селект
		editor.WordControl.m_oLogicDocument.RemoveSelection();

		this.CurCell = CurCell;
		this.CurCell.Content.SelectAll();

		if (true === this.CurCell.Content.IsSelectionEmpty(false))
		{
			this.CurCell.Content.MoveCursorToStartPos();

			this.Selection.Use    = false;
			this.Selection.Type   = table_Selection_Text;
			this.Selection.CurRow = CurCell.Row.Index;
		}
		else
		{
			this.Selection.Use          = true;
			this.Selection.Type         = table_Selection_Text;
			this.Selection.StartPos.Pos = {Row : CurCell.Row.Index, Cell : CurCell.Index};
			this.Selection.EndPos.Pos   = {Row : CurCell.Row.Index, Cell : CurCell.Index};
			this.Selection.CurRow       = CurCell.Row.Index;
		}

		this.Document_SetThisElementCurrent(true);
	}
};
CTable.prototype.GetCurPosXY = function()
{
	var Cell = null;
	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		Cell = this.Content[this.Selection.EndPos.Pos.Row].Get_Cell(this.Selection.EndPos.Pos.Cell);
	else
		Cell = this.CurCell;

	return Cell.Content_GetCurPosXY();
};
CTable.prototype.IsSelectionUse = function()
{
	if ((true == this.Selection.Use && table_Selection_Cell == this.Selection.Type) || table_Selection_Border == this.Selection.Type2 || table_Selection_Border_InnerTable == this.Selection.Type2)
		return true;
	else if (true == this.Selection.Use)
		return this.CurCell.Content.IsSelectionUse();

	return false;
};
CTable.prototype.IsTextSelectionUse = function()
{
	if ((true == this.Selection.Use && table_Selection_Cell == this.Selection.Type) || table_Selection_Border == this.Selection.Type2 || table_Selection_Border_InnerTable == this.Selection.Type2)
		return true;
	else if (true == this.Selection.Use)
		return this.CurCell.Content.IsTextSelectionUse();

	return false;
};
CTable.prototype.GetSelectedText = function(bClearText, oPr)
{
	if (true === bClearText && ( (true == this.Selection.Use && table_Selection_Text == this.Selection.Type) || false === this.Selection.Use ))
	{
		return this.CurCell.Content.GetSelectedText(true, oPr);
	}
	else if (false === bClearText)
	{
		if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			var Count      = this.Selection.Data.length;
			var ResultText = "";
			for (var Index = 0; Index < Count; Index++)
			{
				var Pos  = this.Selection.Data[Index];
				var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);

				Cell.Content.Set_ApplyToAll(true);
				ResultText += Cell.Content.GetSelectedText(false, oPr);
				Cell.Content.Set_ApplyToAll(false);
			}

			return ResultText;
		}
		else
		{
			return this.CurCell.Content.GetSelectedText(false, oPr);
		}
	}

	return null;
};
CTable.prototype.GetSelectedElementsInfo = function(Info)
{
	Info.Set_Table();

	if (false === this.Selection.Use || (true === this.Selection.Use && table_Selection_Text === this.Selection.Type))
	{
		this.CurCell.Content.GetSelectedElementsInfo(Info);
	}
	else if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.StartPos.Pos.Row === this.Selection.EndPos.Pos.Row && this.Selection.StartPos.Pos.Cell === this.Selection.EndPos.Pos.Cell)
	{
		var Row = this.Get_Row(this.Selection.StartPos.Pos.Row);
		if (!Row)
			return;

		var Cell = Row.Get_Cell(this.Selection.StartPos.Pos.Cell);
		if (!Cell)
			return;

		Info.Set_SingleCell(Cell);
	}
};
CTable.prototype.GetSelectedContent = function(SelectedContent)
{
	if (true !== this.Selection.Use)
		return;

	if (table_Selection_Cell === this.Selection.Type || true === this.ApplyToAll)
	{
		// Сначала проверим выделена ли таблица целиком, если да, тогда просто копируем ее.
		if (true === this.ApplyToAll)
		{
			SelectedContent.Add(new CSelectedElement(this.Copy(this.Parent), true));
			return;
		}

		var bAllSelected  = true;
		var SelectedCount = this.Selection.Data.length;

		// Собираем информацию по строкам
		var RowsInfoArray = [];

		var RowsCount = this.Content.length;
		for (var CurRow = 0; CurRow < RowsCount; CurRow++)
		{
			var Row        = this.Content[CurRow];
			var CellsCount = Row.Get_CellsCount();

			var CellsInfoArray = [];

			var bSelectedRow = false;

			CellsInfoArray.push({GridSpan : Row.Get_Before().GridBefore, Cell : null, Selected : false});

			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell     = Row.Get_Cell(CurCell);
				var GridSpan = Cell.Get_GridSpan();
				var VMerge   = Cell.Get_VMerge();

				var bSelected = false;
				if (VMerge === vmerge_Restart)
				{
					// Ищем текущую ячейку среди выделенных

					for (var Index = 0; Index < SelectedCount; Index++)
					{
						var TempPos = this.Selection.Data[Index];
						if (CurCell === TempPos.Cell && CurRow === TempPos.Row)
						{
							bSelected = true;
							break;
						}
						else if (CurRow < TempPos.Row)
							break;
					}
				}
				else
				{
					// Данная ячейка попала в вертикальное объединение, находим ячейку, с которой это объединение
					// началось и проверяем была ли она выделена (эту ячейку мы уже проверяли, т.к. она находится
					// выше).

					var StartMergedCell = this.Internal_Get_StartMergedCell2(CurCell, CurRow);
					bSelected           = RowsInfoArray[StartMergedCell.Row.Index].CellsInfoArray[StartMergedCell.Index + 1].Selected;
				}

				if (false === bSelected)
					bAllSelected = false;
				else
					bSelectedRow = true;

				CellsInfoArray.push({GridSpan : GridSpan, Cell : Cell, Selected : bSelected});
			}

			CellsInfoArray.push({GridSpan : Row.Get_After().GridAfter, Cell : null, Selected : false});

			RowsInfoArray.push({CellsInfoArray : CellsInfoArray, Selected : bSelectedRow});
		}

		if (true === bAllSelected)
		{
			SelectedContent.Add(new CSelectedElement(this.Copy(this.Parent), true));
			return;
		}


		var TableGrid = this.Internal_Copy_Grid(this.TableGridCalc);

		// Посчитаем сколько слева и справа пустых спанов
		var MinBefore = -1;
		var MinAfter  = -1;
		for (var CurRow = 0; CurRow < RowsCount; CurRow++)
		{
			var CellsInfoArray = RowsInfoArray[CurRow].CellsInfoArray;

			if (true !== RowsInfoArray[CurRow].Selected)
				continue;

			var bBefore        = true;
			var BeforeGrid     = 0, AfterGrid = 0;
			var CellsInfoCount = CellsInfoArray.length;
			for (var CellIndex = 0, CurCell = 0; CellIndex < CellsInfoCount; CellIndex++)
			{
				var CellInfo = CellsInfoArray[CellIndex];
				if (true === CellInfo.Selected)
				{
					bBefore = false;
				}
				else if (true === bBefore)
				{
					BeforeGrid += CellInfo.GridSpan;
				}
				else
				{
					AfterGrid += CellInfo.GridSpan;
				}
			}

			if (MinBefore > BeforeGrid || -1 === MinBefore)
				MinBefore = BeforeGrid;

			if (MinAfter > AfterGrid || -1 === MinAfter)
				MinAfter = AfterGrid;
		}

		for (var CurRow = 0; CurRow < RowsCount; CurRow++)
		{
			var CellsInfoArray = RowsInfoArray[CurRow].CellsInfoArray;

			if (true === RowsInfoArray[CurRow].Selected)
			{
				CellsInfoArray[0].GridSpan -= MinBefore;
				CellsInfoArray[CellsInfoArray.length - 1].GridSpan -= MinAfter;
			}
		}

		if (MinAfter > 0)
			TableGrid.splice(TableGrid.length - MinAfter, MinAfter); // TableGrid.length - (MinAfter - 1) - 1

		if (MinBefore > 0)
			TableGrid.splice(0, MinBefore);

		// Формируем новую таблицу, по выделенно части.
		var Table = new CTable(this.DrawingDocument, this.Parent, this.Inline, 0, 0, TableGrid);

		// Копируем настройки
		Table.Set_TableStyle(this.TableStyle);
		Table.Set_TableLook(this.TableLook.Copy());
		Table.Set_PositionH(this.PositionH.RelativeFrom, this.PositionH.Align, this.PositionH.Value);
		Table.Set_PositionV(this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value);
		Table.Set_Distance(this.Distance.L, this.Distance.T, this.Distance.R, this.Distance.B);
		Table.Set_Pr(this.Pr.Copy());

		// Копируем строки
		for (var CurRow = 0, CurRow2 = 0; CurRow < RowsCount; CurRow++)
		{
			var RowInfo = RowsInfoArray[CurRow];
			if (true !== RowInfo.Selected)
				continue;

			var CellsInfoArray = RowInfo.CellsInfoArray;

			var Row = new CTableRow(Table, 0);

			// Копируем настройки строки
			Row.Set_Pr(this.Content[CurRow].Pr.Copy());

			var bMergedRow     = true;
			var bBefore        = true;
			var BeforeGrid     = 0, AfterGrid = 0;
			var CellsInfoCount = CellsInfoArray.length;
			for (var CellIndex = 0, CurCell = 0; CellIndex < CellsInfoCount; CellIndex++)
			{
				var CellInfo = CellsInfoArray[CellIndex];
				if (true === CellInfo.Selected)
				{
					bBefore = false;

					// Добавляем ячейку
					Row.Content[CurCell] = CellInfo.Cell.Copy(Row);
					History.Add(new CChangesTableRowAddCell(Row, CurCell, [Row.Content[CurCell]]));
					CurCell++;

					var VMerge = CellInfo.Cell.Get_VMerge();
					if (VMerge === vmerge_Restart)
						bMergedRow = false;
				}
				else if (true === bBefore)
				{
					BeforeGrid += CellInfo.GridSpan;
				}
				else
				{
					AfterGrid += CellInfo.GridSpan;
				}
			}

			// Строку, составленную полностью из вертикально объединенных ячеек не добавляем
			if (true === bMergedRow)
				continue;

			Row.Set_Before(BeforeGrid);
			Row.Set_After(AfterGrid);

			Row.Internal_ReIndexing();

			// Добавляем строку в новую таблицу
			Table.Content[CurRow2] = Row;
			History.Add(new CChangesTableAddRow(Table, CurRow2, [Table.Content[CurRow2]]));
			CurRow2++;
		}

		Table.Internal_ReIndexing(0);

		if (Table.Content.length > 0 && Table.Content[0].Get_CellsCount() > 0)
			Table.CurCell = Table.Content[0].Get_Cell(0);

		SelectedContent.Add(new CSelectedElement(Table, false));
	}
	else
	{
		this.CurCell.Content.GetSelectedContent(SelectedContent);
	}
};
CTable.prototype.Set_ParagraphPrOnAdd = function(Para)
{
	this.ApplyToAll = true;

	// Добавляем стиль во все параграфы
	var PStyleId = Para.Style_Get();
	if (undefined !== PStyleId && null !== this.LogicDocument)
	{
		var Styles = this.LogicDocument.Get_Styles();
		this.SetParagraphStyle(Styles.Get_Name(PStyleId));
	}

	// Добавляем текстовые настройки во все параграфы
	var TextPr = Para.Get_TextPr();
	this.AddToParagraph(new ParaTextPr(TextPr));

	this.ApplyToAll = false;
};
CTable.prototype.SetParagraphAlign = function(Align)
{
	if (true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphAlign(Align);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphAlign(Align);
	}
};
CTable.prototype.SetParagraphSpacing = function(Spacing)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphSpacing(Spacing);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphSpacing(Spacing);
	}
};
CTable.prototype.SetParagraphIndent = function(Ind)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphIndent(Ind);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphIndent(Ind);
	}
};
CTable.prototype.SetParagraphNumbering = function(NumInfo)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphNumbering(NumInfo);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphNumbering(NumInfo);
	}
};
CTable.prototype.Set_ParagraphPresentationNumbering = function(NumInfo)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.Set_ParagraphPresentationNumbering(NumInfo);
			Cell_Content.Set_ApplyToAll(false);
		}

		if (Cells_array[0].Row - 1 >= 0)
			this.Internal_RecalculateFrom(Cells_array[0].Row - 1, 0, true, true);
		else
		{
			this.Internal_Recalculate_1();
		}
	}
	else
		return this.CurCell.Content.Set_ParagraphPresentationNumbering(NumInfo);
};
CTable.prototype.Increase_ParagraphLevel = function(bIncrease)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.Increase_ParagraphLevel(bIncrease);
			Cell_Content.Set_ApplyToAll(false);
		}

		if (Cells_array[0].Row - 1 >= 0)
			this.Internal_RecalculateFrom(Cells_array[0].Row - 1, 0, true, true);
		else
		{
			this.Internal_Recalculate_1();
		}
	}
	else
		return this.CurCell.Content.Increase_ParagraphLevel(bIncrease);
};
CTable.prototype.SetParagraphShd = function(Shd)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphShd(Shd);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphShd(Shd);
	}
};
CTable.prototype.SetParagraphStyle = function(Name)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphStyle(Name);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphStyle(Name);
	}
};
CTable.prototype.SetParagraphTabs = function(Tabs)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphTabs(Tabs);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphTabs(Tabs);
	}
};
CTable.prototype.SetParagraphContextualSpacing = function(Value)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphContextualSpacing(Value);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphContextualSpacing(Value);
	}
};
CTable.prototype.SetParagraphPageBreakBefore = function(Value)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphPageBreakBefore(Value);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphPageBreakBefore(Value);
	}
};
CTable.prototype.SetParagraphKeepLines = function(Value)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphKeepLines(Value);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphKeepLines(Value);
	}
};
CTable.prototype.SetParagraphKeepNext = function(Value)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphKeepNext(Value);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphKeepNext(Value);
	}
};
CTable.prototype.SetParagraphWidowControl = function(Value)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphWidowControl(Value);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphWidowControl(Value);
	}
};
CTable.prototype.SetParagraphBorders = function(Borders)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.SetParagraphBorders(Borders);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.SetParagraphBorders(Borders);
	}
};
CTable.prototype.SetParagraphFramePr = function(FramePr, bDelete)
{
	if (true !== this.ApplyToAll && (true !== this.Selection.Use || table_Selection_Cell !== this.Selection.Type))
	{
		this.CurCell.Content.SetParagraphFramePr(FramePr, bDelete);
	}
};
CTable.prototype.IncreaseDecreaseFontSize = function(bIncrease)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var Cells_array = this.Internal_Get_SelectionArray();
		for (var Index = 0; Index < Cells_array.length; Index++)
		{
			var Pos  = Cells_array[Index];
			var Row  = this.Content[Pos.Row];
			var Cell = Row.Get_Cell(Pos.Cell);

			var Cell_Content = Cell.Content;
			Cell_Content.Set_ApplyToAll(true);
			Cell.Content.IncreaseDecreaseFontSize(bIncrease);
			Cell_Content.Set_ApplyToAll(false);
		}
	}
	else
	{
		return this.CurCell.Content.IncreaseDecreaseFontSize(bIncrease);
	}
};
CTable.prototype.IncreaseDecreaseIndent = function(bIncrease)
{
	if (true === this.ApplyToAll || ( true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0 ))
	{
		var TablePr = this.Get_CompiledPr(false).TablePr;

		var LeftIndOld = TablePr.TableInd;
		if (undefined === LeftIndOld || null === LeftIndOld)
		{
			LeftIndOld = 0;
		}
		else if (LeftIndOld < 0)
		{
			this.Set_TableInd(0);
			return;
		}

		var LeftIndNew = 0;
		if (true === bIncrease)
		{
			if (LeftIndOld >= 0)
			{
				LeftIndOld = 12.5 * parseInt(10 * LeftIndOld / 125);
				LeftIndNew = ( (LeftIndOld - (10 * LeftIndOld) % 125 / 10) / 12.5 + 1) * 12.5;
			}

			if (LeftIndNew < 0)
				LeftIndNew = 12.5;
		}
		else
		{
			var TempValue = (125 - (10 * LeftIndOld) % 125);
			TempValue     = ( 125 === TempValue ? 0 : TempValue );
			LeftIndNew    = Math.max(( (LeftIndOld + TempValue / 10) / 12.5 - 1 ) * 12.5, 0);
		}

		this.Set_TableInd(LeftIndNew);
	}
	else
	{
		this.CurCell.Content.IncreaseDecreaseIndent(bIncrease);
	}
};
CTable.prototype.GetCalculatedParaPr = function()
{
	if (true === this.ApplyToAll)
	{
		var Row  = this.Content[0];
		var Cell = Row.Get_Cell(0);

		Cell.Content.Set_ApplyToAll(true);
		var Result_ParaPr = Cell.Content.GetCalculatedParaPr();
		Cell.Content.Set_ApplyToAll(false);

		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			Row            = this.Content[CurRow];
			var CellsCount = Row.Get_CellsCount();
			var StartCell  = ( CurRow === 0 ? 1 : 0 );

			for (var CurCell = StartCell; CurCell < CellsCount; CurCell++)
			{
				Cell = Row.Get_Cell(CurCell);
				Cell.Content.Set_ApplyToAll(true);
				var CurPr = Cell.Content.GetCalculatedParaPr();
				Cell.Content.Set_ApplyToAll(false);

				Result_ParaPr = Result_ParaPr.Compare(CurPr);
			}
		}

		return Result_ParaPr;
	}

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		var Pos  = this.Selection.Data[0];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.Get_Cell(Pos.Cell);

		Cell.Content.Set_ApplyToAll(true);
		var Result_ParaPr = Cell.Content.GetCalculatedParaPr();
		Cell.Content.Set_ApplyToAll(false);

		for (var Index = 1; Index < this.Selection.Data.length; Index++)
		{
			Pos  = this.Selection.Data[Index];
			Row  = this.Content[Pos.Row];
			Cell = Row.Get_Cell(Pos.Cell);

			Cell.Content.Set_ApplyToAll(true);
			var CurPr = Cell.Content.GetCalculatedParaPr();
			Cell.Content.Set_ApplyToAll(false);

			Result_ParaPr = Result_ParaPr.Compare(CurPr);
		}

		return Result_ParaPr;
	}

	return this.CurCell.Content.GetCalculatedParaPr();
};
CTable.prototype.GetCalculatedTextPr = function()
{
	if (true === this.ApplyToAll)
	{
		var Row  = this.Content[0];
		var Cell = Row.Get_Cell(0);

		Cell.Content.Set_ApplyToAll(true);
		var Result_TextPr = Cell.Content.GetCalculatedTextPr();
		Cell.Content.Set_ApplyToAll(false);

		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			Row            = this.Content[CurRow];
			var CellsCount = Row.Get_CellsCount();
			var StartCell  = ( CurRow === 0 ? 1 : 0 );

			for (var CurCell = StartCell; CurCell < CellsCount; CurCell++)
			{
				Cell = Row.Get_Cell(CurCell);
				Cell.Content.Set_ApplyToAll(true);
				var CurPr = Cell.Content.GetCalculatedTextPr();
				Cell.Content.Set_ApplyToAll(false);

				Result_TextPr = Result_TextPr.Compare(CurPr);
			}
		}

		return Result_TextPr;
	}

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		var Pos  = this.Selection.Data[0];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.Get_Cell(Pos.Cell);

		Cell.Content.Set_ApplyToAll(true);
		var Result_TextPr = Cell.Content.GetCalculatedTextPr();
		Cell.Content.Set_ApplyToAll(false);

		for (var Index = 1; Index < this.Selection.Data.length; Index++)
		{
			Pos  = this.Selection.Data[Index];
			Row  = this.Content[Pos.Row];
			Cell = Row.Get_Cell(Pos.Cell);

			Cell.Content.Set_ApplyToAll(true);
			var CurPr = Cell.Content.GetCalculatedTextPr();
			Cell.Content.Set_ApplyToAll(false);

			Result_TextPr = Result_TextPr.Compare(CurPr);
		}

		return Result_TextPr;
	}

	return this.CurCell.Content.GetCalculatedTextPr();
};
CTable.prototype.GetDirectTextPr = function()
{
	if (true === this.ApplyToAll)
	{
		var Row  = this.Content[0];
		var Cell = Row.Get_Cell(0);

		Cell.Content.Set_ApplyToAll(true);
		var Result_TextPr = Cell.Content.GetDirectTextPr();
		Cell.Content.Set_ApplyToAll(false);

		return Result_TextPr;
	}

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		var Pos  = this.Selection.Data[0];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.Get_Cell(Pos.Cell);

		Cell.Content.Set_ApplyToAll(true);
		var Result_TextPr = Cell.Content.GetDirectTextPr();
		Cell.Content.Set_ApplyToAll(false);

		return Result_TextPr;
	}

	return this.CurCell.Content.GetDirectTextPr();
};
CTable.prototype.GetDirectParaPr = function()
{
	if (true === this.ApplyToAll)
	{
		var Row  = this.Content[0];
		var Cell = Row.Get_Cell(0);

		Cell.Content.Set_ApplyToAll(true);
		var Result_TextPr = Cell.Content.GetDirectParaPr();
		Cell.Content.Set_ApplyToAll(false);

		return Result_TextPr;
	}

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		var Pos  = this.Selection.Data[0];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.Get_Cell(Pos.Cell);

		Cell.Content.Set_ApplyToAll(true);
		var Result_TextPr = Cell.Content.GetDirectParaPr();
		Cell.Content.Set_ApplyToAll(false);

		return Result_TextPr;
	}

	return this.CurCell.Content.GetDirectParaPr();
};
CTable.prototype.GetCurrentParagraph = function()
{
	var SelectionArray = this.Internal_Get_SelectionArray();
	if (SelectionArray.length > 0)
	{
		var CurCell = SelectionArray[0].Cell;
		var CurRow  = SelectionArray[0].Row;

		return this.Get_Row(CurRow).Get_Cell(CurCell).Content.GetCurrentParagraph();
	}

	return null;
};
CTable.prototype.SetImageProps = function(Props)
{
	if ((true === this.Selection.Use && table_Selection_Text === this.Selection.Type) || false === this.Selection.Use)
	{
		return this.CurCell.Content.SetImageProps(Props);
	}
};
//----------------------------------------------------------------------------------------------------------------------
// Работаем со стилем таблицы
//----------------------------------------------------------------------------------------------------------------------
/**
 * Сообщаем таблице, что ей надо будет пересчитать скомпилированный стиль
 * (Такое может случится, если у данной таблицы задан стиль,
 * который меняется каким-то внешним образом)
 *
 */
CTable.prototype.Recalc_CompiledPr = function()
{
	this.CompiledPr.NeedRecalc = true;
};
CTable.prototype.Recalc_CompiledPr2 = function()
{
	this.Recalc_CompiledPr();

	var RowsCount = this.Content.length;
	for (var CurRow = 0; CurRow < RowsCount; CurRow++)
	{
		var Row = this.Content[CurRow];
		Row.Recalc_CompiledPr();

		var CellsCount = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			Cell.Recalc_CompiledPr();
		}
	}
};
/**
 * Формируем конечные свойства параграфа на основе стиля и прямых настроек.
 */
CTable.prototype.Get_CompiledPr = function(bCopy)
{
	if (true === this.CompiledPr.NeedRecalc)
	{
		if (true === AscCommon.g_oIdCounter.m_bLoad && true === AscCommon.g_oIdCounter.m_bRead)
		{
			this.CompiledPr.Pr         = {
				TextPr : g_oDocumentDefaultTextPr,
				ParaPr : g_oDocumentDefaultParaPr,

				TablePr     : g_oDocumentDefaultTablePr,
				TableRowPr  : g_oDocumentDefaultTableRowPr,
				TableCellPr : g_oDocumentDefaultTableCellPr,

				TableFirstCol   : g_oDocumentDefaultTableStylePr,
				TableFirstRow   : g_oDocumentDefaultTableStylePr,
				TableLastCol    : g_oDocumentDefaultTableStylePr,
				TableLastRow    : g_oDocumentDefaultTableStylePr,
				TableBand1Horz  : g_oDocumentDefaultTableStylePr,
				TableBand1Vert  : g_oDocumentDefaultTableStylePr,
				TableBand2Horz  : g_oDocumentDefaultTableStylePr,
				TableBand2Vert  : g_oDocumentDefaultTableStylePr,
				TableTLCell     : g_oDocumentDefaultTableStylePr,
				TableTRCell     : g_oDocumentDefaultTableStylePr,
				TableBLCell     : g_oDocumentDefaultTableStylePr,
				TableBRCell     : g_oDocumentDefaultTableStylePr,
				TableWholeTable : g_oDocumentDefaultTableStylePr
			};
			this.CompiledPr.NeedRecalc = true;
		}
		else
		{
			this.CompiledPr.Pr         = this.Internal_Compile_Pr();
			this.CompiledPr.NeedRecalc = false;
		}
	}

	if (false === bCopy)
		return this.CompiledPr.Pr;
	else
	{
		var Pr    = {};
		Pr.TextPr = this.CompiledPr.Pr.TextPr.Copy();
		Pr.ParaPr = this.CompiledPr.Pr.ParaPr.Copy();

		Pr.TablePr     = this.CompiledPr.Pr.TablePr.Copy();
		Pr.TableRowPr  = this.CompiledPr.Pr.TableRowPr.Copy();
		Pr.TableCellPr = this.CompiledPr.Pr.TableCellPr.Copy();

		Pr.TableFirstCol   = this.CompiledPr.Pr.TableFirstCol.Copy();
		Pr.TableFirstRow   = this.CompiledPr.Pr.TableFirstRow.Copy();
		Pr.TableLastCol    = this.CompiledPr.Pr.TableLastCol.Copy();
		Pr.TableLastRow    = this.CompiledPr.Pr.TableLastRow.Copy();
		Pr.TableBand1Horz  = this.CompiledPr.Pr.TableBand1Horz.Copy();
		Pr.TableBand1Vert  = this.CompiledPr.Pr.TableBand1Vert.Copy();
		Pr.TableBand2Horz  = this.CompiledPr.Pr.TableBand2Horz.Copy();
		Pr.TableBand2Vert  = this.CompiledPr.Pr.TableBand2Vert.Copy();
		Pr.TableTLCell     = this.CompiledPr.Pr.TableTLCell.Copy();
		Pr.TableTRCell     = this.CompiledPr.Pr.TableTRCell.Copy();
		Pr.TableBLCell     = this.CompiledPr.Pr.TableBLCell.Copy();
		Pr.TableBRCell     = this.CompiledPr.Pr.TableBRCell.Copy();
		Pr.TableWholeTable = this.CompiledPr.Pr.TableWholeTable.Copy();

		return Pr; // Отдаем копию объекта, чтобы никто не поменял извне настройки стиля
	}
};
CTable.prototype.Get_Style = function()
{
	if ("undefined" != typeof(this.TableStyle))
		return this.TableStyle;

	return null;
};
CTable.prototype.Set_Style = function(Id)
{
	this.Style_Remove();
	if (null === Id)
		return;

	// Если стиль является стилем по умолчанию для таблицы, тогда не надо его записывать.
	if (Id != this.Get_Styles().Get_Default_Table())
		this.TableStyle = Id;

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
};
CTable.prototype.Remove_Style = function()
{
	if ("undefined" != typeof(this.TableStyle))
		delete this.TableStyle;

	// Надо пересчитать конечный стиль
	this.CompiledPr.NeedRecalc = true;
};
CTable.prototype.Numbering_IsUse = function(NumId, NumLvl)
{
	return false;
};
/**
 * Формируем конечные свойства таблицы на основе стиля и прямых настроек.
 */
CTable.prototype.Internal_Compile_Pr = function()
{
	var Styles  = this.Get_Styles();
	var StyleId = this.Get_Style();

	// Считываем свойства для текущего стиля
	var Pr = Styles.Get_Pr(StyleId, styletype_Table);
	if (this.bPresentation)
	{
		this.Check_PresentationPr(Pr);
	}
	// Копируем прямые настройки параграфа.
	Pr.TablePr.Merge(this.Pr);

	return Pr;
};
CTable.prototype.Check_PresentationPr = function(Pr)
{
	var Theme = this.Get_Theme();
	Pr.TablePr.Check_PresentationPr(Theme);
	Pr.TextPr.Check_PresentationPr(Theme);
	Pr.TableCellPr.Check_PresentationPr(Theme);
	Pr.TableFirstCol.Check_PresentationPr(Theme);
	Pr.TableFirstRow.Check_PresentationPr(Theme);
	Pr.TableLastCol.Check_PresentationPr(Theme);
	Pr.TableLastRow.Check_PresentationPr(Theme);
	Pr.TableBand1Horz.Check_PresentationPr(Theme);
	Pr.TableBand1Vert.Check_PresentationPr(Theme);
	Pr.TableBand2Horz.Check_PresentationPr(Theme);
	Pr.TableBand2Vert.Check_PresentationPr(Theme);
	Pr.TableTLCell.Check_PresentationPr(Theme);
	Pr.TableTRCell.Check_PresentationPr(Theme);
	Pr.TableBLCell.Check_PresentationPr(Theme);
	Pr.TableBRCell.Check_PresentationPr(Theme);
};
//----------------------------------------------------------------------------------------------------------------------
// Устанавливаем прямые настройки таблицы
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.Clear_DirectFormatting = function(bClearMerge)
{
	// Очищаем все прямые настройки таблицы, всех ее строк и всех ее ячеек

	this.Set_TableStyleRowBandSize(undefined);
	this.Set_TableStyleColBandSize(undefined);
	this.Set_TableAlign(undefined);
	this.Set_TableShd(undefined);
	this.Set_TableBorder_Bottom(undefined);
	this.Set_TableBorder_Left(undefined);
	this.Set_TableBorder_Right(undefined);
	this.Set_TableBorder_Top(undefined);
	this.Set_TableBorder_InsideV(undefined);
	this.Set_TableBorder_InsideH(undefined);
	this.Set_TableCellMar(undefined, undefined, undefined, undefined);
	this.Set_TableInd(undefined);

	if (false !== bClearMerge)
		this.Set_TableW(undefined, undefined);

	var Count = this.Content.length;
	for (var Index = 0; Index < Count; Index++)
	{
		this.Content[Index].Clear_DirectFormatting(bClearMerge);
	}
};
CTable.prototype.Set_Pr = function(TablePr)
{
	History.Add(new CChangesTablePr(this, this.Pr, TablePr));
	this.Pr = TablePr;
	this.Recalc_CompiledPr2();
};
CTable.prototype.Set_TableStyle = function(StyleId, bNoClearFormatting)
{
	// Здесь мы не проверяем изменился ли стиль, потому что при выставлении стиля нужно сбрасывать
	// прямые настройки, даже если мы выставляем тот же самый стиль.

	History.Add(new CChangesTableTableStyle(this, this.TableStyle, StyleId));
	this.TableStyle = StyleId;

	// Очищаем все прямое форматирование таблицы
	if (!(bNoClearFormatting === true))
	{
		this.Clear_DirectFormatting(false);
	}
	this.Recalc_CompiledPr2();
};
CTable.prototype.Set_TableStyle2 = function(StyleId)
{
	if (this.TableStyle != StyleId)
	{
		History.Add(new CChangesTableTableStyle(this, this.TableStyle, StyleId));
		this.TableStyle = StyleId;

		this.Recalc_CompiledPr2();
	}
};
CTable.prototype.Get_TableStyle = function()
{
	return this.TableStyle;
};
CTable.prototype.Set_TableLook = function(TableLook)
{
	History.Add(new CChangesTableTableLook(this, this.TableLook, TableLook));
	this.TableLook = TableLook;
	this.Recalc_CompiledPr2();
};
CTable.prototype.Get_TableLook = function()
{
	return this.TableLook;
};
CTable.prototype.Set_AllowOverlap = function(AllowOverlap)
{
	History.Add(new CChangesTableAllowOverlap(this, this.AllowOverlap, AllowOverlap));
	this.AllowOverlap = AllowOverlap;
};
CTable.prototype.Get_AllowOverlap = function()
{
	return this.AllowOverlap;
};
CTable.prototype.Set_PositionH = function(RelativeFrom, Align, Value)
{
	History.Add(new CChangesTablePositionH(this,
		{
			RelativeFrom : this.PositionH.RelativeFrom,
			Align        : this.PositionH.Align,
			Value        : this.PositionH.Value
		},
		{
			RelativeFrom : RelativeFrom,
			Align        : Align,
			Value        : Value
		}));

	this.PositionH.RelativeFrom = RelativeFrom;
	this.PositionH.Align        = Align;
	this.PositionH.Value        = Value;
};
CTable.prototype.Set_PositionV = function(RelativeFrom, Align, Value)
{
	History.Add(new CChangesTablePositionV(this,
		{
			RelativeFrom : this.PositionV.RelativeFrom,
			Align        : this.PositionV.Align,
			Value        : this.PositionV.Value
		},
		{
			RelativeFrom : RelativeFrom,
			Align        : Align,
			Value        : Value
		}));

	this.PositionV.RelativeFrom = RelativeFrom;
	this.PositionV.Align        = Align;
	this.PositionV.Value        = Value;
};
CTable.prototype.Set_Distance = function(L, T, R, B)
{
	if (null === L || undefined === L)
		L = this.Distance.L;

	if (null === T || undefined === T)
		T = this.Distance.T;

	if (null === R || undefined === R)
		R = this.Distance.R;

	if (null === B || undefined === B)
		B = this.Distance.B;

	History.Add(new CChangesTableDistance(this, {
		Left   : this.Distance.L,
		Top    : this.Distance.T,
		Right  : this.Distance.R,
		Bottom : this.Distance.B
	}, {
		Left   : L,
		Top    : T,
		Right  : R,
		Bottom : B
	}));
	this.Distance.L = L;
	this.Distance.R = R;
	this.Distance.T = T;
	this.Distance.B = B;
};
CTable.prototype.Set_TableStyleRowBandSize = function(Value)
{
	if (this.Pr.TableStyleRowBandSize === Value)
		return;

	History.Add(new CChangesTableTableStyleRowBandSize(this, this.Pr.TableStyleRowBandSize, Value));
	this.Pr.TableStyleRowBandSize = Value;
	this.Recalc_CompiledPr();
};
CTable.prototype.Get_TableStyleRowBandSize = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableStyleRowBandSize;
};
CTable.prototype.Set_TableStyleColBandSize = function(Value)
{
	if (this.Pr.TableStyleColBandSize === Value)
		return;

	History.Add(new CChangesTableTableStyleColBandSize(this, this.Pr.TableStyleColBandSize, Value));
	this.Pr.TableStyleColBandSize = Value;
	this.Recalc_CompiledPr();
};
CTable.prototype.Get_TableStyleColBandSize = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableStyleColBandSize;
};
CTable.prototype.Get_ShapeStyleForPara = function()
{
	return this.Parent.Get_ShapeStyleForPara();
};
CTable.prototype.Set_TableW = function(Type, W)
{
	if (undefined === Type)
	{
		if (undefined === this.Pr.TableW)
			return;

		History.Add(new CChangesTableTableW(this, this.Pr.TableW, undefined));
		this.Pr.TableW = undefined;
		this.Recalc_CompiledPr();
	}
	else if (undefined === this.Pr.TableW)
	{
		var TableW = new CTableMeasurement(Type, W);
		History.Add(new CChangesTableTableW(this, undefined, TableW));
		this.Pr.TableW = TableW;
		this.Recalc_CompiledPr();
	}
	else if (Type != this.Pr.TableW.Type || Math.abs(this.Pr.TableW.W - W) > 0.001)
	{
		var TableW = new CTableMeasurement(Type, W);
		History.Add(new CChangesTableTableW(this, this.Pr.TableW, TableW));
		this.Pr.TableW = TableW;
		this.Recalc_CompiledPr();
	}
};
CTable.prototype.Get_TableW = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableW;
};
CTable.prototype.Set_TableLayout = function(Value)
{
	if (this.Pr.TableLayout === Value)
		return;

	History.Add(new CChangesTableTableLayout(this, this.Pr.TableLayout, Value));
	this.Pr.TableLayout = Value;
	this.Recalc_CompiledPr();
};
CTable.prototype.Get_TableLayout = function()
{
	var Pr = this.Get_CompliedPr(false).TablePr;
	return Pr.TableLayout;
};
CTable.prototype.Set_TableCellMar = function(Left, Top, Right, Bottom)
{
	var old_Left   = ( undefined === this.Pr.TableCellMar.Left ? undefined : this.Pr.TableCellMar.Left   );
	var old_Right  = ( undefined === this.Pr.TableCellMar.Right ? undefined : this.Pr.TableCellMar.Right  );
	var old_Top    = ( undefined === this.Pr.TableCellMar.Top ? undefined : this.Pr.TableCellMar.Top    );
	var old_Bottom = ( undefined === this.Pr.TableCellMar.Bottom ? undefined : this.Pr.TableCellMar.Bottom );

	var new_Left   = ( undefined === Left ? undefined : new CTableMeasurement(tblwidth_Mm, Left) );
	var new_Right  = ( undefined === Right ? undefined : new CTableMeasurement(tblwidth_Mm, Right) );
	var new_Top    = ( undefined === Top ? undefined : new CTableMeasurement(tblwidth_Mm, Top) );
	var new_Bottom = ( undefined === Bottom ? undefined : new CTableMeasurement(tblwidth_Mm, Bottom) );

	History.Add(new CChangesTableTableCellMar(this,
		{
			Left   : old_Left,
			Right  : old_Right,
			Top    : old_Top,
			Bottom : old_Bottom
		},
		{
			Left   : new_Left,
			Right  : new_Right,
			Top    : new_Top,
			Bottom : new_Bottom
		})
	);

	this.Pr.TableCellMar.Left   = new_Left;
	this.Pr.TableCellMar.Right  = new_Right;
	this.Pr.TableCellMar.Top    = new_Top;
	this.Pr.TableCellMar.Bottom = new_Bottom;

	this.Recalc_CompiledPr();
};
CTable.prototype.Get_TableCellMar = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableCellMar;
};
CTable.prototype.Set_TableAlign = function(Align)
{
	if (undefined === Align)
	{
		if (undefined === this.Pr.Jc)
			return;

		History.Add(new CChangesTableTableAlign(this, this.Pr.Jc, undefined));
		this.Pr.Jc = undefined;
		this.Recalc_CompiledPr();
	}
	else if (undefined === this.Pr.Jc)
	{
		History.Add(new CChangesTableTableAlign(this, undefined, Align));
		this.Pr.Jc = Align;
		this.Recalc_CompiledPr();
	}
	else if (Align != this.Pr.Jc)
	{
		History.Add(new CChangesTableTableAlign(this, this.Pr.Jc, Align));
		this.Pr.Jc = Align;
		this.Recalc_CompiledPr();
	}
};
CTable.prototype.Get_TableAlign = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.Jc;
};
CTable.prototype.Set_TableInd = function(Ind)
{
	if (undefined === Ind)
	{
		if (undefined === this.Pr.TableInd)
			return;

		History.Add(new CChangesTableTableInd(this, this.Pr.TableInd, undefined));
		this.Pr.TableInd = undefined;
		this.Recalc_CompiledPr();
	}
	else if (undefined === this.Pr.TableInd)
	{
		History.Add(new CChangesTableTableInd(this, undefined, Ind));
		this.Pr.TableInd = Ind;
		this.Recalc_CompiledPr();
	}
	else if (Math.abs(this.Pr.TableInd - Ind) > 0.001)
	{
		History.Add(new CChangesTableTableInd(this, this.Pr.TableInd, Ind));
		this.Pr.TableInd = Ind;
		this.Recalc_CompiledPr();
	}
};
CTable.prototype.Get_TableInd = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableInd;
};
CTable.prototype.Set_TableBorder_Left = function(Border)
{
	if (undefined === this.Pr.TableBorders.Left && undefined === Border)
		return;

	var _Border = Border;
	if (undefined !== _Border)
	{
		_Border = new CDocumentBorder();
		_Border.Set_FromObject(Border);
	}

	History.Add(new CChangesTableTableBorderLeft(this, this.Pr.TableBorders.Left, _Border));
	this.Pr.TableBorders.Left = _Border;
	this.Recalc_CompiledPr();
};
CTable.prototype.Set_TableBorder_Right = function(Border)
{
	if (undefined === this.Pr.TableBorders.Right && undefined === Border)
		return;

	var _Border = Border;
	if (undefined !== _Border)
	{
		_Border = new CDocumentBorder();
		_Border.Set_FromObject(Border);
	}

	History.Add(new CChangesTableTableBorderRight(this, this.Pr.TableBorders.Right, _Border));
	this.Pr.TableBorders.Right = _Border;
	this.Recalc_CompiledPr();
};
CTable.prototype.Set_TableBorder_Top = function(Border)
{
	if (undefined === this.Pr.TableBorders.Top && undefined === Border)
		return;

	var _Border = Border;
	if (undefined !== _Border)
	{
		_Border = new CDocumentBorder();
		_Border.Set_FromObject(Border);
	}

	History.Add(new CChangesTableTableBorderTop(this, this.Pr.TableBorders.Top, _Border));
	this.Pr.TableBorders.Top = _Border;
	this.Recalc_CompiledPr();
};
CTable.prototype.Set_TableBorder_Bottom = function(Border)
{
	if (undefined === this.Pr.TableBorders.Bottom && undefined === Border)
		return;

	var _Border = Border;
	if (undefined !== _Border)
	{
		_Border = new CDocumentBorder();
		_Border.Set_FromObject(Border);
	}

	History.Add(new CChangesTableTableBorderBottom(this, this.Pr.TableBorders.Bottom, _Border));
	this.Pr.TableBorders.Bottom = _Border;
	this.Recalc_CompiledPr();
};
CTable.prototype.Set_TableBorder_InsideH = function(Border)
{
	if (undefined === this.Pr.TableBorders.InsideH && undefined === Border)
		return;

	var _Border = Border;
	if (undefined !== _Border)
	{
		_Border = new CDocumentBorder();
		_Border.Set_FromObject(Border);
	}

	History.Add(new CChangesTableTableBorderInsideH(this, this.Pr.TableBorders.InsideH, _Border));
	this.Pr.TableBorders.InsideH = _Border;
	this.Recalc_CompiledPr();
};
CTable.prototype.Set_TableBorder_InsideV = function(Border)
{
	if (undefined === this.Pr.TableBorders.InsideV && undefined === Border)
		return;

	var _Border = Border;
	if (undefined !== _Border)
	{
		_Border = new CDocumentBorder();
		_Border.Set_FromObject(Border);
	}

	History.Add(new CChangesTableTableBorderInsideV(this, this.Pr.TableBorders.InsideV, _Border));
	this.Pr.TableBorders.InsideV = _Border;
	this.Recalc_CompiledPr();
};
CTable.prototype.Get_TableBorders = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableBorders;
};
CTable.prototype.Set_TableShd = function(Value, r, g, b)
{
	if (undefined === Value && undefined === this.Pr.Shd)
		return;

	var _Shd = undefined;
	if (undefined !== Value)
	{
		_Shd       = new CDocumentShd();
		_Shd.Value = Value;
		_Shd.Color.Set(r, g, b);
	}

	History.Add(new CChangesTableTableShd(this, this.Pr.Shd, _Shd));
	this.Pr.Shd = _Shd;
	this.Recalc_CompiledPr();
};
CTable.prototype.Get_Shd = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.Shd;
};
CTable.prototype.Get_Borders = function()
{
	return this.Get_TableBorders();
};
CTable.prototype.Set_TableDescription = function(sDescription)
{
	History.Add(new CChangesTableTableDescription(this, this.Pr.TableDescription, sDescription));
	this.Pr.TableDescription = sDescription;
	this.Recalc_CompiledPr();
};
CTable.prototype.Get_TableDescription = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableDescription;
};
CTable.prototype.Set_TableCaption = function(sCaption)
{
	History.Add(new CChangesTableTableCaption(this, this.Pr.TableCaption, sCaption));
	this.Pr.TableCaption = sCaption;
	this.Recalc_CompiledPr();
};
CTable.prototype.Get_TableCaption = function()
{
	var Pr = this.Get_CompiledPr(false).TablePr;
	return Pr.TableCaption;
};
//----------------------------------------------------------------------------------------------------------------------
// Работаем с сеткой таблицы
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.Split_Table = function()
{
	// Пока данная функция используется только при добавлении секции. В этом случае мы делим таблицу на 2 части по
	// текущей строке. Если текущая строка первая, тогда не делим таблицу.

	var CurRow = this.CurCell.Row.Index;

	if (0 === CurRow)
		return null;

	var NewTable = new CTable(this.DrawingDocument, this.Parent, this.Inline, 0, 0, this.private_CopyTableGrid());

	var Len = this.Content.length;
	for (var RowIndex = CurRow; RowIndex < Len; RowIndex++)
	{
		NewTable.Internal_Add_Row(RowIndex - CurRow, 0, false, this.Content[CurRow]);
		this.Internal_Remove_Row(CurRow);
	}

	NewTable.ReIndexing(0);
	this.ReIndexing(0);

	NewTable.Set_Pr(this.Pr.Copy());
	NewTable.Set_TableStyle2(this.TableStyle);
	NewTable.Set_TableLook(this.TableLook.Copy());

	// Сбросим селект и текущую позицию в таблицах
	this.MoveCursorToStartPos(false);
	NewTable.MoveCursorToStartPos(false);

	return NewTable;
};
CTable.prototype.Internal_CheckMerge = function()
{
	var bCanMerge = true;

	var Grid_start = -1;
	var Grid_end   = -1;

	var RowsInfo = [];
	var nRowMin  = -1;
	var nRowMax  = -1;

	for (var Index = 0; Index < this.Selection.Data.length; Index++)
	{
		var Pos  = this.Selection.Data[Index];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.Get_Cell(Pos.Cell);

		var StartGridCol = Row.Get_CellInfo(Pos.Cell).StartGridCol;
		var EndGridCol   = StartGridCol + Cell.Get_GridSpan() - 1;

		var VMergeCount = this.Internal_GetVertMergeCount(Pos.Row, Row.Get_CellInfo(Pos.Cell).StartGridCol, Cell.Get_GridSpan());

		for (var RowIndex = Pos.Row; RowIndex <= Pos.Row + VMergeCount - 1; RowIndex++)
		{
			if ("undefined" === typeof(RowsInfo[RowIndex]))
			{
				RowsInfo[RowIndex] =
					{
						Grid_start : StartGridCol,
						Grid_end   : EndGridCol
					};

				if (-1 === nRowMax || RowIndex > nRowMax)
					nRowMax = RowIndex;

				if (-1 === nRowMin || RowIndex < nRowMin)
					nRowMin = RowIndex;
			}
			else
			{
				if (StartGridCol < RowsInfo[RowIndex].Grid_start)
					RowsInfo[RowIndex].Grid_start = StartGridCol;

				if (EndGridCol > RowsInfo[RowIndex].Grid_end)
					RowsInfo[RowIndex].Grid_end = EndGridCol;
			}
		}
	}

	// Проверим, что селект строк идет без пропусков
	for (var nRowIndex = nRowMin; nRowIndex <= nRowMax; ++nRowIndex)
	{
		if (!RowsInfo[nRowIndex])
		{
			bCanMerge = false;
			break;
		}
	}

	for (var Index in RowsInfo)
	{
		if (-1 === Grid_start)
			Grid_start = RowsInfo[Index].Grid_start;
		else if (Grid_start != RowsInfo[Index].Grid_start)
		{
			bCanMerge = false;
			break;
		}

		if (-1 === Grid_end)
			Grid_end = RowsInfo[Index].Grid_end;
		else if (Grid_end != RowsInfo[Index].Grid_end)
		{
			bCanMerge = false;
			break;
		}
	}

	if (true === bCanMerge)
	{
		// Далее, мы должны убедиться, что у выеделенных ячеек верхние и нижние поля также
		// ровные (т.е. без выступов).
		// Для этого для каждой колонки, попавшей в отрезок [Grid_start, Grid_end] находим
		// верхнюю и нижнюю ячейку и смотрим на верхнюю и нижнюю строки данных ячеек,
		// соответственно

		var TopRow = -1;
		var BotRow = -1;

		for (var GridIndex = Grid_start; GridIndex <= Grid_end; GridIndex++)
		{
			var Pos_top = null;
			var Pos_bot = null;
			for (var Index = 0; Index < this.Selection.Data.length; Index++)
			{
				var Pos  = this.Selection.Data[Index];
				var Row  = this.Content[Pos.Row];
				var Cell = Row.Get_Cell(Pos.Cell);

				var StartGridCol = Row.Get_CellInfo(Pos.Cell).StartGridCol;
				var EndGridCol   = StartGridCol + Cell.Get_GridSpan() - 1;

				if (GridIndex >= StartGridCol && GridIndex <= EndGridCol)
				{
					if (null === Pos_top || Pos_top.Row > Pos.Row)
						Pos_top = Pos;

					if (null === Pos_bot || Pos_bot.Row < Pos.Row)
						Pos_bot = Pos;
				}
			}

			if (null === Pos_top || null === Pos_bot)
			{
				bCanMerge = false;
				break;
			}

			if (-1 === TopRow)
				TopRow = Pos_top.Row;
			else if (TopRow != Pos_top.Row)
			{
				bCanMerge = false;
				break;
			}

			var Row  = this.Content[Pos_bot.Row];
			var Cell = Row.Get_Cell(Pos_bot.Cell);

			var VMergeCount = this.Internal_GetVertMergeCount(Pos_bot.Row, Row.Get_CellInfo(Pos_bot.Cell).StartGridCol, Cell.Get_GridSpan());
			var CurBotRow   = Pos_bot.Row + VMergeCount - 1;

			if (-1 === BotRow)
				BotRow = CurBotRow;
			else if (BotRow != CurBotRow)
			{
				bCanMerge = false;
				break;
			}
		}

		// Объединенные ячейки образуют прямоугольник, но возможно в нем есть вырезы,
		// т.е. выделение такое, что в него попала строка с GridBefore или GridAfter > 0
		if (true === bCanMerge)
		{
			for (var RowIndex = TopRow; RowIndex <= BotRow; RowIndex++)
			{
				var Row         = this.Content[RowIndex];
				var Grid_before = Row.Get_Before().GridBefore;
				var Grid_after  = Row.Get_After().GridAfter;

				if (Grid_after <= 0 && Grid_before <= 0)
					continue;

				if (Grid_start < Grid_before)
				{
					bCanMerge = false;
					break;
				}

				var Cell         = Row.Get_Cell(Row.Get_CellsCount() - 1);
				var Row_grid_end = Cell.Get_GridSpan() - 1 + Row.Get_CellInfo(Row.Get_CellsCount() - 1).StartGridCol;
				if (Grid_end > Row_grid_end)
				{
					bCanMerge = false;
					break;
				}
			}
		}
	}

	return {Grid_start : Grid_start, Grid_end : Grid_end, RowsInfo : RowsInfo, bCanMerge : bCanMerge};
};
/**
 * Объединяем выделенные ячейки таблицы.
 * @param isClearMerge - используем или нет рассчетные данные (true - не используем, false - default value)
 */
CTable.prototype.MergeTableCells = function(isClearMerge)
{
	var bApplyToInnerTable = false;
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		bApplyToInnerTable = this.CurCell.Content.MergeTableCells();

	if (true === bApplyToInnerTable)
		return false;

	if (true != this.Selection.Use || table_Selection_Cell != this.Selection.Type || this.Selection.Data.length <= 1)
		return false;

	// В массиве this.Selection.Data идет список ячеек по строкам (без разрывов)
	// Перед объединением мы должны проверить совпадают ли начальная и конечная колонки
	// в сетке TableGrid для каждого ряда.
	var Temp       = this.Internal_CheckMerge();
	var bCanMerge  = Temp.bCanMerge;
	var Grid_start = Temp.Grid_start;
	var Grid_end   = Temp.Grid_end;
	var RowsInfo   = Temp.RowsInfo;

	if (false === bCanMerge)
		return false;

	// Объединяем содержимое всех ячеек в левую верхнюю ячейку. (Все выделенные
	// ячейки идут у нас последовательно, начиная с левой верхней), и объединяем
	// сами ячейки.

	var Pos_tl  = this.Selection.Data[0];
	var Cell_tl = this.Content[Pos_tl.Row].Get_Cell(Pos_tl.Cell);

	for (var Index = 0; Index < this.Selection.Data.length; Index++)
	{
		var Pos  = this.Selection.Data[Index];
		var Row  = this.Content[Pos.Row];
		var Cell = Row.Get_Cell(Pos.Cell);

		// Добавляем содержимое данной ячейки к содержимому левой верхней ячейки
		if (0 != Index)
		{
			Cell_tl.Content_Merge(Cell.Content);
			Cell.Content.Clear_Content();
		}
	}

	if (true !== isClearMerge)
	{
		// Выставим ширину результируещей ячейки
		var SumW = 0;
		for (var CurGridCol = Grid_start; CurGridCol <= Grid_end; CurGridCol++)
		{
			SumW += this.TableGridCalc[CurGridCol];
		}
		Cell_tl.Set_W(new CTableMeasurement(tblwidth_Mm, SumW));
	}

	// Теперь нам надо удалить лишние ячейки и добавить ячейки с
	// вертикальным объединением.
	for (var RowIndex in RowsInfo)
	{
		var Row = this.Content[RowIndex];
		for (var CellIndex = 0; CellIndex < Row.Get_CellsCount(); CellIndex++)
		{
			var Cell_grid_start = Row.Get_CellInfo(CellIndex).StartGridCol;

			if (Grid_start === Cell_grid_start)
			{
				if (RowIndex != Pos_tl.Row)
				{
					var Cell = Row.Get_Cell(CellIndex);
					Cell.Set_GridSpan(Grid_end - Grid_start + 1);
					Cell.Set_VMerge(vmerge_Continue);
				}
				else
				{
					Cell_tl.Set_GridSpan(Grid_end - Grid_start + 1);
				}
			}
			else if (Cell_grid_start > Grid_start && Cell_grid_start <= Grid_end)
			{
				Row.Remove_Cell(CellIndex);
				CellIndex--;
			}
			else if (Cell_grid_start > Grid_end)
				break;
		}
	}

	// Удаляем лишние строки
	this.Internal_Check_TableRows(true !== isClearMerge ? true : false);
	for (var PageNum = 0; PageNum < this.Pages.length - 1; PageNum++)
	{
		if (Pos_tl.Row <= this.Pages[PageNum + 1].FirstRow)
			break;
	}

	// Выделяем полученную ячейку
	this.Selection.Use          = true;
	this.Selection.StartPos.Pos = Pos_tl;
	this.Selection.EndPos.Pos   = Pos_tl;
	this.Selection.Type         = table_Selection_Cell;
	this.Selection.Data         = [Pos_tl];

	this.CurCell = Cell_tl;

	if (true !== isClearMerge)
	{
		// Запускаем пересчет
		this.Internal_Recalculate_1();
	}

	return true;
};
/**
 * Разделяем текущую ячейку
 */
CTable.prototype.SplitTableCells = function(Rows, Cols)
{
	var bApplyToInnerTable = false;
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		bApplyToInnerTable = this.CurCell.Content.SplitTableCells(Cols, Rows);

	if (true === bApplyToInnerTable)
		return true;

	// Разделение ячейки работает, только если выделена ровно одна ячейка.
	if (!( false === this.Selection.Use || ( true === this.Selection.Use && ( table_Selection_Text === this.Selection.Type || ( table_Selection_Cell === this.Selection.Type && 1 === this.Selection.Data.length  ) ) ) ))
		return false;

	var Cell_pos = null;
	var Cell     = null;

	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
	{
		Cell     = this.CurCell;
		Cell_pos =
			{
				Cell : Cell.Index,
				Row  : Cell.Row.Index
			};
	}
	else
	{
		Cell_pos = this.Selection.Data[0];
		Cell     = this.Content[Cell_pos.Row].Get_Cell(Cell_pos.Cell);
	}

	var Row = this.Content[Cell_pos.Row];

	var Grid_start = Row.Get_CellInfo(Cell_pos.Cell).StartGridCol;
	var Grid_span  = Cell.Get_GridSpan();

	var VMerge_count = this.Internal_GetVertMergeCount(Cell_pos.Row, Grid_start, Grid_span);

	// Если данная ячейка имеет вертикальное объединение, тогда по вертикали мы
	// ее разбиваем максимально на VMerge_count частей, если значение Rows превышает
	// заданное максимально допустимое значение или Rows не является делителем
	// числа VMerge_count - выдаем ошибку.
	// Если данная ячейка не учавствует в вертикальном объединении, тогда мы спокойно
	// можем делить ячейку на любое количество строк.
	if (VMerge_count > 1)
	{
		if (Rows > VMerge_count)
		{
			// Сообщение об ошибке : "Value Rows must be between 1 and " + VMerge_count
			var ErrData = new AscCommon.CErrorData();
			ErrData.put_Value(VMerge_count);
			editor.sendEvent("asc_onError", c_oAscError.ID.SplitCellMaxRows, c_oAscError.Level.NoCritical, ErrData);
			return false;
		}
		else if (0 != VMerge_count % Rows)
		{
			// Сообщение об ошибке : "Value must be a divisor of the number " + VMerge_count
			var ErrData = new AscCommon.CErrorData();
			ErrData.put_Value(VMerge_count);
			editor.sendEvent("asc_onError", c_oAscError.ID.SplitCellRowsDivider, c_oAscError.Level.NoCritical, ErrData);
			return false;
		}
	}

	// Сделаем оценку макимального количества колонок
	if (Cols > 1)
	{
		var Sum_before = this.TableSumGrid[Grid_start - 1];
		var Sum_with   = this.TableSumGrid[Grid_start + Grid_span - 1];

		var Span_width = Sum_with - Sum_before;
		var Grid_width = Span_width / Cols;

		var CellSpacing = Row.Get_CellSpacing();
		var CellMar     = Cell.Get_Margins();

		var MinW = CellSpacing + CellMar.Right.W + CellMar.Left.W;

		if (Grid_width < MinW)
		{
			var MaxCols = Math.floor(Span_width / MinW);

			// Сообщение об ошибке : "Value Cols must be a between 1 and " + MaxCols
			var ErrData = new AscCommon.CErrorData();
			ErrData.put_Value(MaxCols);
			editor.sendEvent("asc_onError", c_oAscError.ID.SplitCellMaxCols, c_oAscError.Level.NoCritical, ErrData);
			return false;
		}
	}


	var Cells     = [];
	var Cells_pos = [];
	var Rows_     = [];

	if (Rows <= 1)
	{
		for (var Index = 0; Index < VMerge_count; Index++)
		{
			var TempRow = this.Content[Cell_pos.Row + Index];

			Rows_[Index]     = TempRow;
			Cells[Index]     = null;
			Cells_pos[Index] = null;

			// Ищем ячейку, начинающуюся с Grid_start

			var CellsCount = TempRow.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var StartGridCol = TempRow.Get_CellInfo(CurCell).StartGridCol;
				if (StartGridCol === Grid_start)
				{
					Cells[Index]     = TempRow.Get_Cell(CurCell);
					Cells_pos[Index] = {Row : Cell_pos.Row + Index, Cell : CurCell};
				}
			}
		}
	}
	else
	{
		if (VMerge_count > 1)
		{
			var New_VMerge_Count = VMerge_count / Rows;

			for (var Index = 0; Index < VMerge_count; Index++)
			{
				var TempRow = this.Content[Cell_pos.Row + Index];

				Rows_[Index]     = TempRow;
				Cells[Index]     = null;
				Cells_pos[Index] = null;

				// Ищем ячейку, начинающуюся с Grid_start
				var CellsCount = TempRow.Get_CellsCount();
				for (var CurCell = 0; CurCell < CellsCount; CurCell++)
				{
					var StartGridCol = TempRow.Get_CellInfo(CurCell).StartGridCol;
					if (StartGridCol === Grid_start)
					{
						var TempCell     = TempRow.Get_Cell(CurCell);
						Cells[Index]     = TempCell;
						Cells_pos[Index] = {Row : Cell_pos.Row + Index, Cell : CurCell};

						if (0 === Index % New_VMerge_Count)
							TempCell.Set_VMerge(vmerge_Restart);
						else
							TempCell.Set_VMerge(vmerge_Continue);
					}
				}
			}
		}
		else
		{
			// Делаем разбиение по вертикали

			// Нам нужно добавить несколько точных копий текущей строки, только все ячейки,
			// кроме текущей, должны быть объединены по вертикали.

			Rows_[0]     = Row;
			Cells[0]     = Cell;
			Cells_pos[0] = Cell_pos;

			var CellsCount = Row.Get_CellsCount();
			for (var Index = 1; Index < Rows; Index++)
			{
				var NewRow = this.Internal_Add_Row(Cell_pos.Row + Index, CellsCount);
				NewRow.Copy_Pr(Row.Pr);

				Rows_[Index]     = NewRow;
				Cells[Index]     = null;
				Cells_pos[Index] = null;

				// Копируем настройки всех ячеек исходной строки в новую строку
				for (var CurCell = 0; CurCell < CellsCount; CurCell++)
				{
					var New_Cell = NewRow.Get_Cell(CurCell);
					var Old_Cell = Row.Get_Cell(CurCell);

					New_Cell.Copy_Pr(Old_Cell.Pr);

					if (CurCell === Cell_pos.Cell)
					{
						Cells[Index]     = New_Cell;
						Cells_pos[Index] = {Row : Cell_pos.Row + Index, Cell : CurCell};
					}
					else
					{
						New_Cell.Set_VMerge(vmerge_Continue);
					}
				}
			}
		}
	}

	// Сделаем разбиение по горизонтали
	if (Cols > 1)
	{
		// Найдем позиции новых колонок в сетке
		var Sum_before = this.TableSumGrid[Grid_start - 1];
		var Sum_with   = this.TableSumGrid[Grid_start + Grid_span - 1];

		var Span_width = Sum_with - Sum_before;
		var Grid_width = Span_width / Cols;

		// Данный массив содержит информацию о том сколько новых колонок
		// было добавлено после i-ой колонки
		var Grid_Info = [];
		for (var Index = 0; Index < this.TableGridCalc.length; Index++)
			Grid_Info[Index] = 0;

		// Массив содержит информацию о том сколько промежутков будет в
		// новых ячейках
		var Grid_Info_new = [];
		for (var Index = 0; Index < Cols; Index++)
			Grid_Info_new[Index] = 1;

		var Grid_Info_start = [];
		for (var Index = 0; Index < this.TableGridCalc.length; Index++)
			Grid_Info_start[Index] = this.TableGridCalc[Index];

		var NewCol_Index = 0;

		var CurWidth = Sum_before + Grid_width;
		for (var Grid_index = Grid_start; Grid_index < Grid_start + Grid_span; Grid_index++)
		{
			var bNewCol = true;

			// Если мы попали в уже имеющуюся границу не добавляем новую точку
			if (Math.abs(CurWidth - this.TableSumGrid[Grid_index]) < 0.001)
			{
				NewCol_Index++;
				CurWidth += Grid_width;
				bNewCol = false;
				continue;
			}

			while (CurWidth < this.TableSumGrid[Grid_index])
			{
				if (0 === Grid_Info[Grid_index])
					Grid_Info_start[Grid_index] = CurWidth - this.TableSumGrid[Grid_index - 1];
				Grid_Info[Grid_index] += 1;

				NewCol_Index++
				CurWidth += Grid_width;

				// Если мы попали в уже имеющуюся границу не добавляем новую точку
				if (Math.abs(CurWidth - this.TableSumGrid[Grid_index]) < 0.001)
				{
					NewCol_Index++;
					CurWidth += Grid_width;
					bNewCol = false;
					break;
				}
			}

			if (true === bNewCol)
				Grid_Info_new[NewCol_Index] += 1;
		}

		// Добавим в данной строке (Cols - 1) ячеек, с теми же настроками,
		// что и исходной. Значение GridSpan мы берем из массива Grid_Info_new

		for (var Index2 = 0; Index2 < Rows_.length; Index2++)
		{
			if (null != Cells[Index2] && null != Cells_pos[Index2])
			{
				var TempRow      = Rows_[Index2];
				var TempCell     = Cells[Index2];
				var TempCell_pos = Cells_pos[Index2];

				TempCell.Set_GridSpan(Grid_Info_new[0]);
				TempCell.Set_W(new CTableMeasurement(tblwidth_Mm, Grid_width));

				for (var Index = 1; Index < Cols; Index++)
				{
					var NewCell = TempRow.Add_Cell(TempCell_pos.Cell + Index, TempRow, null, false);
					NewCell.Copy_Pr(TempCell.Pr);
					NewCell.Set_GridSpan(Grid_Info_new[Index]);
					NewCell.Set_W(new CTableMeasurement(tblwidth_Mm, Grid_width));
				}
			}
		}

		var OldTableGridLen = this.TableGridCalc.length;
		var arrNewGrid      = this.private_CopyTableGrid();

		// Добавим новые колонки в TableGrid
		// начинаем с конца, чтобы не пересчитывать номера
		for (var Index = OldTableGridLen - 1; Index >= 0; Index--)
		{
			var Summary = this.TableGridCalc[Index];

			if (Grid_Info[Index] > 0)
			{
				arrNewGrid[Index] = Grid_Info_start[Index];
				Summary -= Grid_Info_start[Index] - Grid_width;

				for (var NewIndex = 0; NewIndex < Grid_Info[Index]; NewIndex++)
				{
					Summary -= Grid_width;

					if (NewIndex != Grid_Info[Index] - 1)
						arrNewGrid.splice(Index + NewIndex + 1, 0, Grid_width);
					else
						arrNewGrid.splice(Index + NewIndex + 1, 0, Summary);
				}
			}
		}
		this.SetTableGrid(arrNewGrid);

		// Проходим по всем строкам и изменяем у ячеек GridSpan, в
		// соответствии со значениями массива Grid_Info
		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			if (CurRow >= Cells_pos[0].Row && CurRow <= Cells_pos[Cells_pos.length - 1].Row)
				continue;

			var TempRow = this.Content[CurRow];

			var GridBefore = TempRow.Get_Before().GridBefore;
			var GridAfter  = TempRow.Get_After().GridAfter;

			if (GridBefore > 0)
			{
				var SummaryGridSpan = GridBefore;
				for (var CurGrid = 0; CurGrid < GridBefore; CurGrid++)
					SummaryGridSpan += Grid_Info[CurGrid];

				TempRow.Set_Before(SummaryGridSpan);
			}

			var LastGrid = 0;

			for (var CurCell = 0; CurCell < TempRow.Get_CellsCount(); CurCell++)
			{
				var TempCell      = TempRow.Get_Cell(CurCell);
				var TempGridSpan  = TempCell.Get_GridSpan();
				var TempStartGrid = TempRow.Get_CellInfo(CurCell).StartGridCol;

				var SummaryGridSpan = TempGridSpan;

				LastGrid = TempStartGrid + TempGridSpan;

				for (var CurGrid = TempStartGrid; CurGrid < TempStartGrid + TempGridSpan; CurGrid++)
					SummaryGridSpan += Grid_Info[CurGrid];

				TempCell.Set_GridSpan(SummaryGridSpan);
			}

			if (GridAfter > 0)
			{
				var SummaryGridSpan = GridAfter;
				for (var CurGrid = LastGrid; CurGrid < OldTableGridLen; CurGrid++)
					SummaryGridSpan += Grid_Info[CurGrid];

				TempRow.Set_After(SummaryGridSpan);
			}
		}
	}

	this.ReIndexing();
	this.Recalc_CompiledPr2();
	this.private_RecalculateGrid();
	this.Internal_Recalculate_1();

	return true;
};
/**
 * Добавление строки.
 * @param bBefore - true - до(сверху) первой выделенной строки, false - после(снизу) последней выделенной строки.
 */
CTable.prototype.AddTableRow = function(bBefore)
{
	if ("undefined" === typeof(bBefore))
		bBefore = true;

	var bApplyToInnerTable = false;
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		bApplyToInnerTable = this.CurCell.Content.AddTableRow(bBefore);

	if (true === bApplyToInnerTable)
		return;

	var Cells_pos = [];

	// Количество, вставляемых строк зависит от того сколько содержится
	// строк в выделении. Если вставляем до, тогда копируем верхнюю строку
	// выделения, а если после, тогда последнюю.
	var Count = 1;
	var RowId = 0;

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		Cells_pos = this.Selection.Data;

		var Prev_row = -1;
		Count        = 0;
		for (var Index = 0; Index < this.Selection.Data.length; Index++)
		{
			if (Prev_row != this.Selection.Data[Index].Row)
			{
				Count++;
				Prev_row = this.Selection.Data[Index].Row;
			}
		}
	}
	else
	{
		Cells_pos[0] = {Row : this.CurCell.Row.Index, Cell : this.CurCell.Index};
		Count        = 1;
	}

	if (Cells_pos.length <= 0)
		return;

	if (true === bBefore)
		RowId = Cells_pos[0].Row;
	else
		RowId = Cells_pos[Cells_pos.length - 1].Row;

	var Row        = this.Content[RowId];
	var CellsCount = Row.Get_CellsCount();

	// Сначала пробежимся по строке, которую мы будем копировать, и получим
	// всю необходимую информацию.
	var Cells_info = [];
	for (var CurCell = 0; CurCell < CellsCount; CurCell++)
	{
		var Cell      = Row.Get_Cell(CurCell);
		var Cell_info = Row.Get_CellInfo(CurCell);

		var Cell_grid_start = Cell_info.StartGridCol;
		var Cell_grid_span  = Cell.Get_GridSpan();

		var VMerge_count_before = this.Internal_GetVertMergeCount2(RowId, Cell_grid_start, Cell_grid_span);
		var VMerge_count_after  = this.Internal_GetVertMergeCount(RowId, Cell_grid_start, Cell_grid_span);

		Cells_info[CurCell] =
			{
				VMerge_count_before : VMerge_count_before,
				VMerge_count_after  : VMerge_count_after
			};
	}

	// TODO: Пока делаем одинаковый CellSpacing
	var CellSpacing = this.Content[0].Get_CellSpacing();

	for (var Index = 0; Index < Count; Index++)
	{
		var New_Row = null;

		if (true === bBefore)
			New_Row = this.Internal_Add_Row(RowId, CellsCount, true);
		else
			New_Row = this.Internal_Add_Row(RowId + 1, CellsCount, true);

		New_Row.Copy_Pr(Row.Pr);
		New_Row.Set_CellSpacing(CellSpacing);

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var New_Cell = New_Row.Get_Cell(CurCell);
			var Old_Cell = Row.Get_Cell(CurCell);

			New_Cell.Copy_Pr(Old_Cell.Pr);

			// Копируем также текстовые настройки и настройки параграфа
			var FirstPara = Old_Cell.Content.Get_FirstParagraph();
			var TextPr    = FirstPara.Get_FirstRunPr();
			New_Cell.Content.Set_ApplyToAll(true);

			// Добавляем стиль во все параграфы
			var PStyleId = FirstPara.Style_Get();
			if (undefined !== PStyleId && null !== this.LogicDocument)
			{
				var Styles = this.LogicDocument.Get_Styles();
				New_Cell.Content.SetParagraphStyle(Styles.Get_Name(PStyleId));
			}

			New_Cell.Content.AddToParagraph(new ParaTextPr(TextPr));
			New_Cell.Content.Set_ApplyToAll(false);

			if (true === bBefore)
			{
				if (Cells_info[CurCell].VMerge_count_before > 1)
					New_Cell.Set_VMerge(vmerge_Continue);
				else
					New_Cell.Set_VMerge(vmerge_Restart);
			}
			else
			{
				if (Cells_info[CurCell].VMerge_count_after > 1)
					New_Cell.Set_VMerge(vmerge_Continue);
				else
					New_Cell.Set_VMerge(vmerge_Restart);
			}
		}
	}

	// Выделим новые строки
	this.Selection.Use = true;

	if (null != this.Selection.Data)
		this.Selection.Data.length = 0;
	else
		this.Selection.Data = [];

	this.Selection.Use  = true;
	this.Selection.Type = table_Selection_Cell;

	var StartRow = ( true === bBefore ? RowId : RowId + 1 );
	for (var Index = 0; Index < Count; Index++)
	{
		var Row        = this.Content[StartRow + Index];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			if (vmerge_Continue === Cell.Get_VMerge())
				continue;

			this.Selection.Data.push({Row : StartRow + Index, Cell : CurCell});
		}
	}

	this.Recalc_CompiledPr2();
	this.Internal_Recalculate_1();
};
/**
 * Удаление строки либо по номеру Ind, либо по выделению Selection, либо по текущей ячейке.
 */
CTable.prototype.RemoveTableRow = function(Ind)
{
	var bApplyToInnerTable = false;
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		bApplyToInnerTable = this.CurCell.Content.RemoveTableRow(Ind);

	if (true === bApplyToInnerTable)
		return true;

	var Rows_to_delete = [];

	if ("undefined" === typeof(Ind) || null === Ind)
	{
		if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		{
			var Counter = 0;
			var PrevRow = -1;
			for (var Index = 0; Index < this.Selection.Data.length; Index++)
			{
				var CurPos = this.Selection.Data[Index];
				if (CurPos.Row != PrevRow)
					Rows_to_delete[Counter++] = CurPos.Row;

				PrevRow = CurPos.Row;
			}
		}
		else
			Rows_to_delete[0] = this.CurCell.Row.Index;
	}
	else
		Rows_to_delete[0] = Ind;

	if (Rows_to_delete.length <= 0)
		return;

	// Строки мы удаляем либо по 1, либо непрервным блоком. При удалении мы
	// смотрим на следующую строку после удаляемого блока и проверяем, если
	// какая-либо из ячеек данной строки учавствует в вертикальном объединении,
	// тогда проверяем где оно началось. Если начало объединения выше
	// строк, тогда ничего не делаем, в противном случае начинаем вертикальное
	// объединение с текущей ячейки.

	var FirstRow_to_delete = Rows_to_delete[0];
	var CurRow             = Rows_to_delete[Rows_to_delete.length - 1] + 1;
	if (CurRow < this.Content.length)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell   = Row.Get_Cell(CurCell);
			var VMerge = Cell.Get_VMerge();

			if (vmerge_Continue != VMerge)
				continue;

			// Данная ячейка продолжает вертикальное объединение ячеек
			// Найдем строку, с которой начинается данное объединение.
			var VMerge_count = this.Internal_GetVertMergeCount2(CurRow, Row.Get_CellInfo(CurCell).StartGridCol, Cell.Get_GridSpan());
			if (CurRow - ( VMerge_count - 1 ) >= FirstRow_to_delete)
				Cell.Set_VMerge(vmerge_Restart);
		}
	}

	this.RemoveSelection();

	// Удаляем строки.
	for (var Index = Rows_to_delete.length - 1; Index >= 0; Index--)
	{
		this.Internal_Remove_Row(Rows_to_delete[Index]);
	}

	// Возвращаем курсор
	this.DrawingDocument.TargetStart();
	this.DrawingDocument.TargetShow();

	this.DrawingDocument.SelectEnabled(false);

	// При удалении последней строки, надо сообщить об этом родительскому классу
	if (this.Content.length <= 0)
		return false;

	// Перемещаем курсор в начало следующей строки
	var CurRow   = Math.min(Rows_to_delete[0], this.Content.length - 1);
	var Row      = this.Content[CurRow];
	this.CurCell = Row.Get_Cell(0);
	this.CurCell.Content.MoveCursorToStartPos();

	var PageNum = 0;
	for (PageNum = 0; PageNum < this.Pages.length - 1; PageNum++)
	{
		if (CurRow <= this.Pages[PageNum + 1].FirstRow)
			break;
	}

	this.Markup.Internal.RowIndex  = CurRow;
	this.Markup.Internal.CellIndex = 0;
	this.Markup.Internal.PageNum   = PageNum;

	this.Recalc_CompiledPr2();

	this.Internal_Recalculate_1();

	return true;
};
/**
 * Специальная функция для удаления строк таблицы, когда выделены одновременно параграф и таблица
 */
CTable.prototype.Row_Remove2 = function()
{
	if (false == this.Selection.Use || table_Selection_Text == this.Selection.Type)
		return true;

	var Rows_to_delete = [];
	for (var Index = 0; Index < this.Content.length; Index++)
		Rows_to_delete[Index] = 0;

	for (var Index = 0; Index < this.Selection.Data.length; Index++)
	{
		var Pos = this.Selection.Data[Index];
		if (0 == Rows_to_delete[Pos.Row]);
		Rows_to_delete[Pos.Row] = 1;
	}

	// Удаляем строки.
	for (var Index = this.Content.length - 1; Index >= 0; Index--)
	{
		if (0 != Rows_to_delete[Index])
			this.Internal_Remove_Row(Index);
	}

	// При удалении последней строки, надо сообщить об этом родительскому классу
	if (this.Content.length <= 0)
		return false;

	// Проверяем текущую ячейку
	if (this.CurCell.Row.Index >= this.Content.length)
		this.CurCell = this.Content[this.Content.length - 1].Get_Cell(0);

	this.RemoveSelection();

	return true;
};
/**
 * Удаление колонки либо по выделению Selection, либо по текущей ячейке.
 */
CTable.prototype.RemoveTableColumn = function()
{
	var bApplyToInnerTable = false;
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		bApplyToInnerTable = this.CurCell.Content.RemoveTableColumn();

	if (true === bApplyToInnerTable)
		return true;

	// Найдем правую и левую границы выделенных ячеек.
	var Cells_pos = [];

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		Cells_pos = this.Selection.Data;
	else
		Cells_pos[0] = {Row : this.CurCell.Row.Index, Cell : this.CurCell.Index};

	if (Cells_pos.length <= 0)
		return;

	var Grid_start = -1;
	var Grid_end   = -1;
	for (var Index = 0; Index < Cells_pos.length; Index++)
	{
		var Row  = this.Content[Cells_pos[Index].Row];
		var Cell = Row.Get_Cell(Cells_pos[Index].Cell);

		var Cur_Grid_start = Row.Get_CellInfo(Cells_pos[Index].Cell).StartGridCol;
		var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

		if (-1 === Grid_start || ( -1 != Grid_start && Grid_start > Cur_Grid_start ))
			Grid_start = Cur_Grid_start;

		if (-1 === Grid_end || ( -1 != Grid_end && Grid_end < Cur_Grid_end ))
			Grid_end = Cur_Grid_end;
	}

	// Пробегаемся по всем строкам и смотрим, если у какой либо ячейки
	// есть пересечение с отрезком [Grid_start, Grid_end], тогда удаляем
	// данную ячейку.

	var Delete_info = [];
	var Rows_info   = [];

	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		Delete_info[CurRow] = [];
		Rows_info[CurRow]   = [];

		var Row = this.Content[CurRow];

		var Before_Info = Row.Get_Before();
		if (Before_Info.GridBefore > 0)
			Rows_info[CurRow].push({W : this.TableSumGrid[Before_Info.GridBefore - 1], Type : -1, GridSpan : 1});

		var CellsCount = Row.Get_CellsCount();
		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell           = Row.Get_Cell(CurCell);
			var Cur_Grid_start = Row.Get_CellInfo(CurCell).StartGridCol;
			var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

			if (Cur_Grid_start <= Grid_end && Cur_Grid_end >= Grid_start)
			{
				Delete_info[CurRow].push(CurCell);
			}
			else
			{
				var W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1];
				Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
			}
		}
	}

	// Удалим все ячейки
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row = this.Content[CurRow];
		for (var Index = Delete_info[CurRow].length - 1; Index >= 0; Index--)
		{
			var CurCell = Delete_info[CurRow][Index];
			Row.Remove_Cell(CurCell);
		}
	}

	// При удалении колонки возможен случай, когда удаляется строка целиком
	for (var CurRow = this.Content.length - 1; CurRow >= 0; CurRow--)
	{
		// Строка удалена целиком, если в RowsInfo нет ни одной записи
		// о ячейках (т.е. с типом равным 0)
		var bRemove = true;
		for (var Index = 0; Index < Rows_info[CurRow].length; Index++)
		{
			if (0 === Rows_info[CurRow][Index].Type)
			{
				bRemove = false;
				break;
			}
		}

		if (true === bRemove)
		{
			this.Internal_Remove_Row(CurRow);
			Rows_info.splice(CurRow, 1);
		}
	}

	// Возвращаем курсор
	this.DrawingDocument.TargetStart();
	this.DrawingDocument.TargetShow();

	this.DrawingDocument.SelectEnabled(false);

	// При удалении последней строки, надо сообщить об этом родительскому классу
	if (this.Content.length <= 0)
		return false;

	// TODO: При удалении колонки надо запоминать информацию об вертикально
	//       объединенных ячейках, и в новой сетке объединять ячейки только
	//       если они были объединены изначально. Сейчас если ячейка была
	//       объединена с какой-либо ячейков, то она может после удаления колонки
	//       объединиться с совсем другой ячейкой.

	this.Internal_CreateNewGrid(Rows_info);

	// Пробегаемся по всем ячейкам и смотрим на их вертикальное объединение, было ли оно нарушено
	this.private_CorrectVerticalMerge();

	// Возможен случай, когда у нас остались строки, полностью состоящие из объединенных вертикально ячеек
	for (var CurRow = this.Content.length - 1; CurRow >= 0; CurRow--)
	{
		var bRemove    = true;
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell = Row.Get_Cell(CurCell);
			if (vmerge_Continue != Cell.Get_VMerge())
			{
				bRemove = false;
				break;
			}
		}

		if (true === bRemove)
		{
			this.Internal_Remove_Row(CurRow);
		}
	}

	// Перемещаем курсор в начало следующей колонки
	var CurRow     = 0;
	var Row        = this.Content[CurRow];
	var CellsCount = Row.Get_CellsCount();
	var CurCell    = Delete_info[0][0] === undefined ? CellsCount - 1 : Math.min(Delete_info[0][0], CellsCount - 1);

	this.CurCell = Row.Get_Cell(CurCell);
	this.CurCell.Content.MoveCursorToStartPos();
	var PageNum = 0;

	this.Markup.Internal.RowIndex  = CurRow;
	this.Markup.Internal.CellIndex = CurCell;
	this.Markup.Internal.PageNum   = PageNum;

	this.Selection.Use          = false;
	this.Selection.Start        = false;
	this.Selection.StartPos.Pos = {Row : CurRow, Cell : CurCell};
	this.Selection.EndPos.Pos   = {Row : CurRow, Cell : CurCell};
	this.Selection.CurRow       = CurRow;

	this.private_RecalculateGrid();
	this.Internal_Recalculate_1();

	return true;
};
/**
 * Добавление колонки.
 * @param bBefore - true - до(слева) первой выделенной колонки, false - после(справа) последней выделенной колонки.
 */
CTable.prototype.AddTableColumn = function(bBefore)
{
	if ("undefined" === typeof(bBefore))
		bBefore = true;

	var bApplyToInnerTable = false;
	if (false === this.Selection.Use || ( true === this.Selection.Use && table_Selection_Text === this.Selection.Type ))
		bApplyToInnerTable = this.CurCell.Content.AddTableColumn(bBefore);

	if (true === bApplyToInnerTable)
		return;

	var Cells_pos = [];

	// Количество, вставляемых столбцов зависит от того сколько содержится
	// ячеек в первой строке выделения. Ширина берется у первой ячейки, если
	// bBefore = true, и у последней, если bBefore = false.
	var Count = 1;
	var Width = 0;

	if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
	{
		Cells_pos = this.Selection.Data;

		var Prev_row = -1;
		Count        = 0;
		for (var Index = 0; Index < this.Selection.Data.length; Index++)
		{
			if (-1 != Prev_row)
			{
				if (Prev_row === this.Selection.Data[Index].Row)
					Count++;
				else
					break;
			}
			else
			{
				Count++;
				Prev_row = this.Selection.Data[Index].Row;
			}
		}
	}
	else
	{
		Cells_pos[0] = {Row : this.CurCell.Row.Index, Cell : this.CurCell.Index};
		Count        = 1;
	}

	if (Cells_pos.length <= 0)
		return;

	if (true === bBefore)
	{
		// Вычислим ширину первой ячейки
		var FirstCell_Grid_start = this.Content[Cells_pos[0].Row].Get_CellInfo(Cells_pos[0].Cell).StartGridCol;
		var FirstCell_Grid_end   = FirstCell_Grid_start + this.Content[Cells_pos[0].Row].Get_Cell(Cells_pos[0].Cell).Get_GridSpan() - 1;
		Width                    = this.TableSumGrid[FirstCell_Grid_end] - this.TableSumGrid[FirstCell_Grid_start - 1];
	}
	else
	{
		// Вычислим ширину последней ячейки
		var LastPos = Cells_pos.length - 1;

		var LastCell_Grid_start = this.Content[Cells_pos[LastPos].Row].Get_CellInfo(Cells_pos[LastPos].Cell).StartGridCol;
		var LastCell_Grid_end   = LastCell_Grid_start + this.Content[Cells_pos[LastPos].Row].Get_Cell(Cells_pos[LastPos].Cell).Get_GridSpan() - 1;
		Width                   = this.TableSumGrid[LastCell_Grid_end] - this.TableSumGrid[LastCell_Grid_start - 1];
	}

	var Rows_info = [];
	var Add_info  = [];
	if (true === bBefore)
	{
		// Ищем левую границу выделенных ячеек
		var Grid_start = -1;
		for (var Index = 0; Index < Cells_pos.length; Index++)
		{
			var Row  = this.Content[Cells_pos[Index].Row];
			var Cell = Row.Get_Cell(Cells_pos[Index].Cell);

			var Cur_Grid_start = Row.Get_CellInfo(Cells_pos[Index].Cell).StartGridCol;

			if (-1 === Grid_start || ( -1 != Grid_start && Grid_start > Cur_Grid_start ))
				Grid_start = Cur_Grid_start;
		}

		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			var Row           = this.Content[CurRow];
			Rows_info[CurRow] = [];
			Add_info[CurRow]  = 0;

			var Before_Info = Row.Get_Before();
			if (Before_Info.GridBefore > 0)
				Rows_info[CurRow].push({W : this.TableSumGrid[Before_Info.GridBefore - 1], Type : -1, GridSpan : 1});

			var CellsCount = Row.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell           = Row.Get_Cell(CurCell);
				var Cur_Grid_start = Row.Get_CellInfo(CurCell).StartGridCol;
				var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

				if (Cur_Grid_start <= Grid_start)
					Add_info[CurRow] = CurCell;

				var W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1];
				Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
			}

			var After_Info = Row.Get_After();
			if (After_Info.GridAfter > 0)
			{
				if (Row.Get_CellInfo(CellsCount - 1).StartGridCol + Row.Get_Cell(CellsCount - 1).Get_GridSpan() <= Grid_start)
					Add_info[CurRow] = CellsCount;
			}
		}

		// Теперь нам надо добавить ячейки в найденные позиции, и в те же позиции
		// добавить элементы в массиве Rows_info
		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			var Row = this.Content[CurRow];

			var bBefore2 = false;
			if (Rows_info.length > 0 && Rows_info[CurRow][0].Type === -1)
				bBefore2 = true;

			for (var Index = 0; Index < Count; Index++)
			{
				var NewCell = Row.Add_Cell(Add_info[CurRow], Row, null, false);

				// Скопируем свойства следующуй ячейки в данной строке, а если мы добавляем в конец, то предыдущей
				var NextCell = ( Add_info[CurRow] >= Row.Get_CellsCount() - 1 ? Row.Get_Cell(Add_info[CurRow] - 1) : Row.Get_Cell(Add_info[CurRow] + 1) );
				NewCell.Copy_Pr(NextCell.Pr, true);

				// Скопируем текстовые настройки
				var FirstPara = NextCell.Content.Get_FirstParagraph();
				var TextPr    = FirstPara.Get_FirstRunPr();
				NewCell.Content.Set_ApplyToAll(true);

				// Добавляем стиль во все параграфы
				var PStyleId = FirstPara.Style_Get();
				if (undefined !== PStyleId && null !== this.LogicDocument)
				{
					var Styles = this.LogicDocument.Get_Styles();
					NewCell.Content.SetParagraphStyle(Styles.Get_Name(PStyleId));
				}

				NewCell.Content.AddToParagraph(new ParaTextPr(TextPr));
				NewCell.Content.Set_ApplyToAll(false);

				if (false === bBefore2)
					Rows_info[CurRow].splice(Add_info[CurRow], 0, {W : Width, Type : 0, GridSpan : 1});
				else
					Rows_info[CurRow].splice(Add_info[CurRow] + 1, 0, {W : Width, Type : 0, GridSpan : 1});
			}
		}
	}
	else
	{
		// Ищем правую границу выделенных ячеек
		var Grid_end = -1;
		for (var Index = 0; Index < Cells_pos.length; Index++)
		{
			var Row  = this.Content[Cells_pos[Index].Row];
			var Cell = Row.Get_Cell(Cells_pos[Index].Cell);

			var Cur_Grid_start = Row.Get_CellInfo(Cells_pos[Index].Cell).StartGridCol;
			var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

			if (-1 === Grid_end || ( -1 != Grid_end && Grid_end < Cur_Grid_end ))
				Grid_end = Cur_Grid_end;
		}

		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			var Row           = this.Content[CurRow];
			Rows_info[CurRow] = [];
			Add_info[CurRow]  = -1;

			var Before_Info = Row.Get_Before();
			if (Before_Info.GridBefore > 0)
				Rows_info[CurRow].push({W : this.TableSumGrid[Before_Info.GridBefore - 1], Type : -1, GridSpan : 1});

			var CellsCount = Row.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell           = Row.Get_Cell(CurCell);
				var Cur_Grid_start = Row.Get_CellInfo(CurCell).StartGridCol;
				var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

				if (Cur_Grid_end <= Grid_end)
					Add_info[CurRow] = CurCell;

				var W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1];
				Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
			}
		}

		// Теперь нам надо добавить ячейки в найденные позиции, и в те же позиции
		// добавить элементы в массиве Rows_info
		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			var Row = this.Content[CurRow];

			var bBefore2 = false;
			if (Rows_info.length > 0 && Rows_info[CurRow][0].Type === -1)
				bBefore2 = true;

			for (var Index = 0; Index < Count; Index++)
			{
				var NewCell = Row.Add_Cell(Add_info[CurRow] + 1, Row, null, false);

				// Скопируем свойства следующуй ячейки в данной строке, а если мы добавляем в конец, то предыдущей
				var NextCell = ( Add_info[CurRow] + 1 >= Row.Get_CellsCount() - 1 ? Row.Get_Cell(Add_info[CurRow]) : Row.Get_Cell(Add_info[CurRow] + 2) );
				NewCell.Copy_Pr(NextCell.Pr, true);

				// Скопируем текстовые настройки
				var FirstPara = NextCell.Content.Get_FirstParagraph();
				var TextPr    = FirstPara.Get_FirstRunPr();
				NewCell.Content.Set_ApplyToAll(true);

				// Добавляем стиль во все параграфы
				var PStyleId = FirstPara.Style_Get();
				if (undefined !== PStyleId && null !== this.LogicDocument)
				{
					var Styles = this.LogicDocument.Get_Styles();
					NewCell.Content.SetParagraphStyle(Styles.Get_Name(PStyleId));
				}

				NewCell.Content.AddToParagraph(new ParaTextPr(TextPr));
				NewCell.Content.Set_ApplyToAll(false);


				if (false === bBefore2)
					Rows_info[CurRow].splice(Add_info[CurRow] + 1, 0, {W : Width, Type : 0, GridSpan : 1});
				else
					Rows_info[CurRow].splice(Add_info[CurRow] + 2, 0, {W : Width, Type : 0, GridSpan : 1});
			}
		}
	}

	this.Internal_CreateNewGrid(Rows_info);

	// Выделим новые строки
	this.Selection.Use = true;

	if (null != this.Selection.Data)
		this.Selection.Data.length = 0;
	else
		this.Selection.Data = [];

	this.Selection.Use  = true;
	this.Selection.Type = table_Selection_Cell;

	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var StartCell = ( true === bBefore ? Add_info[CurRow] : Add_info[CurRow] + 1 );
		for (var Index = 0; Index < Count; Index++)
		{
			this.Selection.Data.push({Row : CurRow, Cell : StartCell + Index});
		}
	}

	this.private_RecalculateGrid();
	this.Internal_Recalculate_1();
};
/**
 * @param NewMarkup - новая разметка таблицы
 * @param bCol      - где произошли изменения (в колонках или строках)
 * @param Index     - номер границы колонок(строк), у которой произошли изменения
 */
CTable.prototype.Update_TableMarkupFromRuler = function(NewMarkup, bCol, Index)
{
	var TablePr = this.Get_CompiledPr(false).TablePr;
	if (true === bCol)
	{
		var RowIndex = NewMarkup.Internal.RowIndex;
		var Row      = this.Content[RowIndex];
		var Col      = 0;

		var Dx = 0;

		// границ на 1 больше, чем самих ячеек в строке
		if (Index === NewMarkup.Cols.length)
		{
			Col = Row.Get_CellInfo(Index - 1).StartGridCol + Row.Get_Cell(Index - 1).Get_GridSpan();

			Dx = NewMarkup.Cols[Index - 1] - this.Markup.Cols[Index - 1];
		}
		else
		{
			Col = Row.Get_CellInfo(Index).StartGridCol;

			if (0 != Index)
				Dx = NewMarkup.Cols[Index - 1] - this.Markup.Cols[Index - 1];
			else
				Dx = NewMarkup.X - this.Markup.X;
		}

		if (0 === Dx)
			return;

		// Пока сделаем так, в будущем надо будет менять ширину таблицы
		if (0 != Index && TablePr.TableW.Type != tblwidth_Auto)
		{
			var TableW   = TablePr.TableW.W;
			var MinWidth = this.Internal_Get_TableMinWidth();

			if (TableW < MinWidth)
				TableW = MinWidth;

			this.Set_TableW(tblwidth_Mm, TableW + Dx);
		}

		if (0 === Col)
		{
			Dx = this.Markup.X - NewMarkup.X;
			this.X -= Dx;

			if (true === this.Is_Inline())
			{
				this.Set_TableAlign(align_Left);
				this.Set_TableInd(TablePr.TableInd - Dx);
				this.private_SetTableLayoutFixedAndUpdateCellsWidth(-1);
				this.SetTableGrid(this.private_CopyTableGridCalc());
			}
			else
			{
				this.Internal_UpdateFlowPosition(this.X, this.Y);
			}
		}
		else
		{
			var GridSpan = 1;
			if (Dx > 0)
			{
				if (Index != NewMarkup.Cols.length)
				{
					var Cell = Row.Get_Cell(Index);
					GridSpan = Cell.Get_GridSpan();
				}
				else
				{
					var GridAfter = Row.Get_After().GridAfter;
					GridSpan      = GridAfter;
				}

				this.TableGridCalc[Col - 1] = this.TableGridCalc[Col - 1] + Dx;
				this.Internal_UpdateCellW(Col - 1);
				this.private_SetTableLayoutFixedAndUpdateCellsWidth(Col - 1);
				this.SetTableGrid(this.private_CopyTableGridCalc());
			}
			else
			{
				if (0 != Index)
				{
					var Cell = Row.Get_Cell(Index - 1);
					GridSpan = Cell.Get_GridSpan();
				}
				else
				{
					var GridBefore = Row.Get_Before().GridBefore;
					// Если GridBefore = 0, тогда мы попадем в случай 0 === Col
					GridSpan       = GridBefore;
				}

				if (1 === GridSpan || -Dx < this.TableSumGrid[Col - 1] - this.TableSumGrid[Col - 2])
				{
					this.TableGridCalc[Col - 1] = this.TableGridCalc[Col - 1] + Dx;
					this.Internal_UpdateCellW(Col - 1);
					this.private_SetTableLayoutFixedAndUpdateCellsWidth(Col - 1);
					this.SetTableGrid(this.private_CopyTableGridCalc());
				}
				else
				{
					var Rows_info = [];

					for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
					{
						Rows_info[CurRow] = [];

						var Row = this.Content[CurRow];

						var Before_Info = Row.Get_Before();


						if (Before_Info.GridBefore > 0)
						{
							if (Before_Info.GridBefore >= Col)
							{
								var W = Math.max(0, this.TableSumGrid[Before_Info.GridBefore - 1] + Dx);
								if (W > 0.001)
									Rows_info[CurRow].push({W : W, Type : -1, GridSpan : 1});
							}
							else
								Rows_info[CurRow].push({
									W        : this.TableSumGrid[Before_Info.GridBefore - 1],
									Type     : -1,
									GridSpan : 1
								});
						}

						var CellsCount = Row.Get_CellsCount();
						for (var CurCell = 0; CurCell < CellsCount; CurCell++)
						{
							var Cell           = Row.Get_Cell(CurCell);
							var CellMargins    = Cell.Get_Margins();
							var Cur_Grid_start = Row.Get_CellInfo(CurCell).StartGridCol;
							var Cur_Grid_end   = Cur_Grid_start + Cell.Get_GridSpan() - 1;

							if (Cur_Grid_start <= Col - 1 && Cur_Grid_end >= Col - 1)
							{
								var W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1] + Dx;

								W = Math.max(1, Math.max(W, CellMargins.Left.W + CellMargins.Right.W));
								Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
							}
							else
							{
								var W = this.TableSumGrid[Cur_Grid_end] - this.TableSumGrid[Cur_Grid_start - 1];

								W = Math.max(1, Math.max(W, CellMargins.Left.W + CellMargins.Right.W));
								Rows_info[CurRow].push({W : W, Type : 0, GridSpan : 1});
							}
						}
					}

					this.Internal_CreateNewGrid(Rows_info);
				}
			}

			this.private_RecalculateGrid();
		}
	}
	else
	{
		var RowIndex = this.Pages[NewMarkup.Internal.PageNum].FirstRow + Index;
		if (0 === RowIndex)
		{
			if (true === this.Is_Inline())
			{
				// ничего не делаем, позиция по Y в инлайновой таблице изменить нельзя таким способом
			}
			else
			{
				var Dy = this.Markup.Rows[0].Y - NewMarkup.Rows[0].Y;
				Page.Y -= Dy;
				this.Internal_UpdateFlowPosition(Page.X, Page.Y);
				var NewH = NewMarkup.Rows[0].H;
				this.Content[0].Set_Height(NewH, linerule_AtLeast);
			}
		}
		else
		{
			if (NewMarkup.Internal.PageNum > 0 && 0 === Index)
			{
				// ничего не делаем
			}
			else
			{
				var NewH = NewMarkup.Rows[Index - 1].H;
				this.Content[RowIndex - 1].Set_Height(NewH, linerule_AtLeast);
			}
		}
	}

	this.Internal_Recalculate_1();
	editor.WordControl.m_oLogicDocument.Document_UpdateSelectionState();
};
//----------------------------------------------------------------------------------------------------------------------
// Внутренние функции
//----------------------------------------------------------------------------------------------------------------------
/**
 * TODO: Удалить данную функцию
 */
CTable.prototype.Internal_Recalculate_1 = function()
{
	return editor.WordControl.m_oLogicDocument.Recalculate();
};
/**
 * TODO: Удалить данную функцию
 * Данная функция вызывается после изменений внутри ячейки, а это означает, что с момента
 * последнего пересчета не изменилась ни сетка, ни границы, и ни расстояние между ячейками в таблицу.
 * Следовательно, нам надо пересчитать высоту ячейки, в которой произошли изменения,  и если
 * это приведет к изменению высоты строки, то пересчитываем все строки дальше.
 */
CTable.prototype.Internal_RecalculateFrom = function(RowIndex, CellIndex, bChange, bForceRecalc)
{
	return editor.WordControl.m_oLogicDocument.Recalculate();
};
CTable.prototype.Internal_GetCellByXY = function(X, Y, PageIndex)
{
	// Сначала определяем колонку в которую мы попали
	var CurGrid = 0;

	var CurPage   = Math.min(this.Pages.length - 1, Math.max(0, PageIndex));
	var Page      = this.Pages[CurPage];
	var ColsCount = this.TableGridCalc.length;
	if (X >= Page.X)
	{
		for (CurGrid = 0; CurGrid < ColsCount; CurGrid++)
		{
			if (X >= Page.X + this.TableSumGrid[CurGrid - 1] && X <= Page.X + this.TableSumGrid[CurGrid])
				break;
		}
	}

	if (CurGrid >= ColsCount)
		CurGrid = ColsCount - 1;

	// Найдем промежуток строк по PageIndex среди которых нам надо искать
	var PNum = PageIndex;

	var Row_start, Row_last;

	if (PNum < 0)
	{
		Row_start = 0;
		Row_last  = 0;
	}
	else if (PNum >= this.Pages.length)
	{
		Row_start = this.Content.length - 1;
		Row_last  = this.Content.length - 1;
	}
	else
	{
		Row_start = this.Pages[PNum].FirstRow;
		Row_last  = this.Pages[PNum].LastRow;
	}

	if (Row_last < Row_start)
		return {Row : 0, Cell : 0};

	for (var CurRow = Row_start; CurRow <= Row_last; CurRow++)
	{
		var Row        = this.Content[CurRow];
		var CellsCount = Row.Get_CellsCount();
		var BeforeInfo = Row.Get_Before();
		var CurGridCol = BeforeInfo.GridBefore;

		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell     = Row.Get_Cell(CurCell);
			var GridSpan = Cell.Get_GridSpan();
			var Vmerge   = Cell.Get_VMerge();

			// Обсчет такик ячеек произошел ранее
			if (vmerge_Continue === Vmerge && Row_start != CurRow)
			{
				CurGridCol += GridSpan;
				continue;
			}

			var VMergeCount = this.private_GetVertMergeCountOnPage(PNum, CurRow, CurGridCol, GridSpan);
			if (VMergeCount <= 0)
			{
				CurGridCol += GridSpan;
				continue;
			}

			// Проверяем по X
			if (CurGrid >= CurGridCol && CurGrid < CurGridCol + GridSpan)
			{
				// Проверяем по Y
				if ("undefined" != typeof(this.RowsInfo[CurRow + VMergeCount - 1].Y[PNum]) && "undefined" != typeof(this.RowsInfo[CurRow + VMergeCount - 1].H[PNum]) && (Y <= (this.RowsInfo[CurRow + VMergeCount - 1].Y[PNum] + this.RowsInfo[CurRow + VMergeCount - 1].H[PNum]) || CurRow + VMergeCount - 1 >= Row_last ))
				{
					if (vmerge_Continue === Vmerge && Row_start === CurRow)
					{
						Cell = this.Internal_Get_StartMergedCell(CurRow, CurGridCol, GridSpan);
						if (null != Cell)
							return {Row : Cell.Row.Index, Cell : Cell.Index};
						else
							return {Row : 0, Cell : 0};
					}
					else
						return {Row : CurRow, Cell : CurCell};
				}
			}

			CurGridCol += GridSpan;
		}
	}

	return {Row : 0, Cell : 0};
};
/**
 * Считаем количество соединенных вертикально ячеек
 */
CTable.prototype.Internal_GetVertMergeCount = function(StartRow, StartGridCol, GridSpan)
{
	// начинаем с 1, потому что предполагается, что соединение начинается с исходной ячейки
	var VmergeCount = 1;
	for (var Index = StartRow + 1; Index < this.Content.length; Index++)
	{
		var Row        = this.Content[Index];
		var BeforeInfo = Row.Get_Before();
		var CurGridCol = BeforeInfo.GridBefore;
		var CurCell    = 0;
		var CellsCount = Row.Get_CellsCount();

		var bWasMerged = false;
		while (CurGridCol <= StartGridCol && CurCell < CellsCount)
		{
			var Cell         = Row.Get_Cell(CurCell);
			var CellGridSpan = Cell.Get_GridSpan();
			var Vmerge       = Cell.Get_VMerge();

			if (CurGridCol === StartGridCol && GridSpan === CellGridSpan && vmerge_Continue === Vmerge)
			{
				bWasMerged = true;
				VmergeCount++;
				break;
			}
			else if (CurGridCol === StartGridCol && GridSpan === CellGridSpan && vmerge_Continue != Vmerge)
			{
				bWasMerged = true;
				return VmergeCount;
			}
			// Если данная ячейка имеет пересечение с заданным промежутком, но польностью с ним не совпадает
			else if (CurGridCol <= StartGridCol + GridSpan - 1 && CurGridCol + CellGridSpan - 1 >= StartGridCol)
				break;

			CurGridCol += CellGridSpan;
			CurCell++;
		}

		if (false === bWasMerged)
			break;
	}

	return VmergeCount;
};
/**
 * Считаем количество соединенных вертикально ячеек, но в обратную сторону (т.е. снизу вверх)
 */
CTable.prototype.Internal_GetVertMergeCount2 = function(StartRow, StartGridCol, GridSpan)
{
	// начинаем с 1, потому что предполагается, что соединение начинается с исходной ячейки
	var VmergeCount = 1;

	// сначала проверим VMerge текущей ячейки
	var Start_Row        = this.Content[StartRow];
	var Start_VMerge     = vmerge_Restart;
	var Start_CellsCount = Start_Row.Get_CellsCount();
	for (var Index = 0; Index < Start_CellsCount; Index++)
	{
		var Temp_Grid_start = Start_Row.Get_CellInfo(Index).StartGridCol;
		if (Temp_Grid_start === StartGridCol)
		{
			Start_VMerge = Start_Row.Get_Cell(Index).Get_VMerge();
			break;
		}
	}

	if (vmerge_Restart === Start_VMerge)
		return VmergeCount;

	for (var Index = StartRow - 1; Index >= 0; Index--)
	{
		var Row        = this.Content[Index];
		var BeforeInfo = Row.Get_Before();
		var CurGridCol = BeforeInfo.GridBefore;
		var CurCell    = 0;
		var CellsCount = Row.Get_CellsCount();

		var bWasMerged = false;
		while (CurGridCol <= StartGridCol && CurCell < CellsCount)
		{
			var Cell         = Row.Get_Cell(CurCell);
			var CellGridSpan = Cell.Get_GridSpan();
			var Vmerge       = Cell.Get_VMerge();

			if (CurGridCol === StartGridCol && GridSpan === CellGridSpan && vmerge_Continue === Vmerge)
			{
				bWasMerged = true;
				VmergeCount++;
				break;
			}
			else if (CurGridCol === StartGridCol && GridSpan === CellGridSpan && vmerge_Continue != Vmerge)
			{
				bWasMerged = true;
				VmergeCount++;
				return VmergeCount;
			}
			// Если данная ячейка имеет пересечение с заданным промежутком, но польностью с ним не совпадает
			else if (CurGridCol <= StartGridCol + GridSpan - 1 && CurGridCol + CellGridSpan - 1 >= StartGridCol)
				break;

			CurGridCol += CellGridSpan;
			CurCell++;
		}

		if (false === bWasMerged)
			break;
	}

	return VmergeCount;
};
/**
 * Проверяем, нужно ли удалить ненужные строки из нашей таблицы.
 * Такое может произойти после объединения ячеек или после изменения сетки
 * таблицы.
 * True  - в таблице произошли изменения
 * False - ничего не изменилось
 */
CTable.prototype.Internal_Check_TableRows = function(bSaveHeight)
{
	// Пробегаемся по всем строкам, если в какой-то строке у всех ячеек стоит
	// вертикальное объединение, тогда такую строку удаляем, а у предыдущей
	// строки выставляем минимальную высоту - сумму высот этих двух строк.
	// Кроме этого нам надо выставить минимальную высоту у строк, в которых
	// все ячейки состоят в вертикальном объединении, а у самой строки
	// параметр WBefore или WAfter ненулевой

	// Сначала пробежимся по строкам и узнаем, какие строки нужно удалить
	var Rows_to_Delete = [];
	var Rows_to_CalcH  = [];
	var Rows_to_CalcH2 = [];
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row = this.Content[CurRow];

		var bVmerge_Restart  = false;
		var bVmerge_Continue = false;
		var bNeedDeleteRow   = true;
		var bNeedCalcHeight  = false;

		if (Row.Get_Before().GridBefore > 0 || Row.Get_After().GridAfter > 0)
			bNeedCalcHeight = true;

		for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
		{
			var Cell   = Row.Get_Cell(CurCell);
			var VMerge = Cell.Get_VMerge();

			if (VMerge != vmerge_Continue)
			{
				var VMergeCount = this.Internal_GetVertMergeCount(CurRow, Row.Get_CellInfo(CurCell).StartGridCol, Cell.Get_GridSpan());
				if (VMergeCount > 1)
					bVmerge_Restart = true;

				bNeedDeleteRow = false;

				if (true === bNeedCalcHeight)
				{
					if (1 === VMergeCount)
						bNeedCalcHeight = false;
				}
			}
			else
				bVmerge_Continue = true;
		}

		if (true === bVmerge_Continue && true === bVmerge_Restart)
			Rows_to_CalcH2.push(CurRow);
		else if (true === bNeedCalcHeight)
			Rows_to_CalcH.push(CurRow);

		if (true === bNeedDeleteRow)
			Rows_to_Delete.push(CurRow);
	}

	// Сначала разберемся со строками, у которых надо проставить минимальную высоту
	for (var Index = 0; Index < Rows_to_CalcH2.length; Index++)
	{
		var RowIndex  = Rows_to_CalcH2[Index];
		var MinHeight = -1;

		var Row        = this.Content[RowIndex];
		var CellsCount = Row.Get_CellsCount()
		for (var CurCell = 0; CurCell < CellsCount; CurCell++)
		{
			var Cell   = Row.Get_Cell(CurCell);
			var VMerge = Cell.Get_VMerge();
			if (vmerge_Restart === VMerge)
			{
				var CurMinHeight = Cell.Content.Get_EmptyHeight();
				if (CurMinHeight < MinHeight || MinHeight === -1)
					MinHeight = CurMinHeight;
			}
		}

		var OldHeight = this.Content[RowIndex].Get_Height();

		if (undefined === OldHeight || Asc.linerule_Auto == OldHeight.HRule || ( MinHeight > OldHeight.Value ))
			this.Content[RowIndex].Set_Height(MinHeight, linerule_AtLeast);
	}

	if (Rows_to_Delete.length <= 0)
		return false;

	if (true === bSaveHeight)
	{
		// Сначала разберемся со строками, у которых надо проставить минимальную высоту
		for (var Index = 0; Index < Rows_to_CalcH.length; Index++)
		{
			var RowIndex = Rows_to_CalcH[Index];
			this.Content[RowIndex].Set_Height(this.RowsInfo[RowIndex].H, linerule_AtLeast);
		}

		// Рассчитаем высоты строк, так чтобы после удаления, общий вид таблицы не менялся
		for (var Counter = 0; Counter < Rows_to_Delete.length;)
		{
			var CurRowSpan = 1;

			var StartRow = Rows_to_Delete[Counter];
			while (Counter + CurRowSpan < Rows_to_Delete.length && Rows_to_Delete[Counter] + CurRowSpan === Rows_to_Delete[Counter + CurRowSpan])
				CurRowSpan++;

			if (this.RowsInfo[StartRow - 1 + CurRowSpan].StartPage === this.RowsInfo[StartRow - 1].StartPage)
			{
				var StartPage      = this.RowsInfo[StartRow - 1 + CurRowSpan].StartPage;
				var Summary_Height = this.RowsInfo[StartRow - 1 + CurRowSpan].H[StartPage] + this.RowsInfo[StartRow - 1 + CurRowSpan].Y[StartPage] - this.RowsInfo[StartRow - 1].Y[StartPage];
				this.Content[StartRow - 1].Set_Height(Summary_Height, linerule_AtLeast);
			}

			Counter += CurRowSpan;
		}
	}

	// Удаляем, начиная с последней строки, чтобы не пересчитывать номера строк
	for (var Index = Rows_to_Delete.length - 1; Index >= 0; Index--)
	{
		var Row_to_Delete = Rows_to_Delete[Index];
		this.Internal_Remove_Row(Row_to_Delete);
	}

	return true;
};
CTable.prototype.Internal_Remove_Row = function(Index)
{
	if (Index >= this.Content.length || Index < 0)
		return;

	this.Content[Index].PreDelete();

	History.Add(new CChangesTableRemoveRow(this, Index, [this.Content[Index]]));

	this.Rows--;
	this.Content.splice(Index, 1);
	this.TableRowsBottom.splice(Index, 1);
	this.RowsInfo.splice(Index, 1);

	this.Internal_ReIndexing(Index);
};
CTable.prototype.Internal_Add_Row = function(Index, CellsCount, bReIndexing, _NewRow)
{
	if (Index < 0)
		Index = 0;

	if (Index >= this.Content.length)
		Index = this.Content.length;

	this.Rows++;

	var NewRow = ( undefined === _NewRow ? new CTableRow(this, CellsCount) : _NewRow );

	History.Add(new CChangesTableAddRow(this, Index, [NewRow]));

	this.Content.splice(Index, 0, NewRow);
	this.TableRowsBottom.splice(Index, 0, {});
	this.RowsInfo.splice(Index, 0, {
		Pages        : 1,
		Y            : [],
		H            : [],
		TopDy        : [],
		MaxTopBorder : [],
		FirstPage    : true,
		StartPage    : 0
	});

	if (true === bReIndexing)
	{
		this.Internal_ReIndexing(Index);
	}
	else
	{
		if (Index > 0)
		{
			this.Content[Index - 1].Next = NewRow;
			NewRow.Prev                  = this.Content[Index - 1];
		}
		else
			NewRow.Prev = null;

		if (Index < this.Content.length - 1)
		{
			this.Content[Index + 1].Prev = NewRow;
			NewRow.Next                  = this.Content[Index + 1];
		}
		else
			NewRow.Next = null;
	}

	NewRow.Table = this;

	return NewRow;
};
CTable.prototype.Clear_ContentChanges = function()
{
	this.m_oContentChanges.Clear();
};
CTable.prototype.Add_ContentChanges = function(Changes)
{
	this.m_oContentChanges.Add(Changes);
};
CTable.prototype.Refresh_ContentChanges = function()
{
	this.m_oContentChanges.Refresh();
};
CTable.prototype.Internal_ReIndexing = function(StartIndex)
{
	if ("undefined" === typeof(StartIndex))
		StartIndex = 0;

	for (var Ind = StartIndex; Ind < this.Content.length; Ind++)
	{
		this.Content[Ind].Set_Index(Ind);
		this.Content[Ind].Prev  = ( Ind > 0 ? this.Content[Ind - 1] : null );
		this.Content[Ind].Next  = ( Ind < this.Content.length - 1 ? this.Content[Ind + 1] : null );
		this.Content[Ind].Table = this;
	}
};
CTable.prototype.ReIndexing = function(StartIndex)
{
	this.Internal_ReIndexing(0);

	var Count = this.Content.length;
	for (var Ind = StartIndex; Ind < Count; Ind++)
	{
		this.Content[Ind].Internal_ReIndexing(0);
	}
};
/**
 * Переделываем сетку таблицы заново, исходя из массива RowsInfo
 * В данном массиве заданы для каждой строки ширины всех ячеек (либо
 * пропусков до или после строк GridBefore/GridAfter).
 * На выходе мы отдаем новую сетку TableGrid и массив RowsInfo, в
 * котором для каждой ячейки(пропуска) указан GridSpan.
 */
CTable.prototype.Internal_CreateNewGrid = function(RowsInfo)
{
	var CurPos = [];
	var CurX   = [];
	for (var Index = 0; Index < RowsInfo.length; Index++)
	{
		CurPos[Index] = 0;
		CurX[Index]   = RowsInfo[Index][0].W;

		for (var Index2 = 0; Index2 < RowsInfo[Index].length; Index2++)
		{
			RowsInfo[Index][Index2].GridSpan = 1;

			// Последние элемент всегда должен означать GridAfter, но с
			// нулевыем начальным значением.
			if (1 != RowsInfo[Index][RowsInfo[Index].length - 1].Type)
			{
				RowsInfo[Index].push({W : 0, Type : 1, GridSpan : 0});
			}
			else
			{
				RowsInfo[Index][RowsInfo[Index].length - 1] = {W : 0, Type : 1, GridSpan : 0};
			}
		}
	}

	var TableGrid = [];
	var bEnd      = false;
	var PrevX     = 0;
	while (true != bEnd)
	{
		var MinX = -1;
		for (var Index = 0; Index < RowsInfo.length; Index++)
		{
			if ((MinX === -1 || CurX[Index] < MinX) && !( RowsInfo[Index].length - 1 === CurPos[Index] && 1 === RowsInfo[Index][CurPos[Index]].Type ))
				MinX = CurX[Index];
		}

		for (var Index = 0; Index < RowsInfo.length; Index++)
		{
			if (RowsInfo[Index].length - 1 === CurPos[Index] && 1 === RowsInfo[Index][CurPos[Index]].Type)
				RowsInfo[Index][CurPos[Index]].GridSpan++;
			else
			{
				if (Math.abs(MinX - CurX[Index]) < 0.001)
				{
					CurPos[Index]++;
					CurX[Index] += RowsInfo[Index][CurPos[Index]].W;
				}
				else
				{
					RowsInfo[Index][CurPos[Index]].GridSpan++;
				}
			}
		}

		TableGrid.push(MinX - PrevX);
		PrevX = MinX;

		bEnd = true;
		for (var Index = 0; Index < RowsInfo.length; Index++)
		{
			if (RowsInfo[Index].length - 1 != CurPos[Index])
			{
				bEnd = false;
				break;
			}
		}
	}

	for (var CurRow = 0; CurRow < RowsInfo.length; CurRow++)
	{
		var RowInfo = RowsInfo[CurRow];
		var Row     = this.Content[CurRow];

		var CurIndex = 0;
		if (-1 === RowInfo[0].Type)
		{
			if (RowInfo[0].GridSpan > 0)
			{
				Row.Set_Before(RowInfo[0].GridSpan);
			}
			CurIndex++;
		}
		else
		{
			Row.Set_Before(0);
		}

		for (var CurCell = 0; CurIndex < RowInfo.length; CurIndex++, CurCell++)
		{
			if (1 === RowInfo[CurIndex].Type)
				break;

			var Cell = Row.Get_Cell(CurCell);
			Cell.Set_GridSpan(RowInfo[CurIndex].GridSpan);
			var WType = Cell.Get_W().Type;
			if (tblwidth_Auto != WType && tblwidth_Nil != WType)
			{
				Cell.Set_W(new CTableMeasurement(tblwidth_Mm, RowInfo[CurIndex].W));
			}
		}

		CurIndex = RowInfo.length - 1;
		if (1 === RowInfo[CurIndex].Type)
		{
			Row.Set_After(RowInfo[CurIndex].GridSpan);
		}
		else
		{
			Row.Set_After(0);
		}
	}
	this.SetTableGrid(TableGrid);
	return TableGrid;
};
CTable.prototype.Internal_UpdateCellW = function(Col)
{
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();
		var CurGridCol  = Row.Get_Before().GridBefore;

		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell     = Row.Get_Cell(CurCell);
			var GridSpan = Cell.Get_GridSpan();

			if (Col >= CurGridCol && Col < CurGridCol + GridSpan)
			{
				var CellWType = Cell.Get_W().Type;
				if (tblwidth_Auto != CellWType && tblwidth_Nil != CellWType)
				{
					var W = 0;
					for (var CurSpan = CurGridCol; CurSpan < CurGridCol + GridSpan; CurSpan++)
						W += this.TableGridCalc[CurSpan];

					Cell.Set_W(new CTableMeasurement(tblwidth_Mm, W));
				}

				break;
			}

			CurGridCol += GridSpan;
		}
	}
};
/**
 * Сравниваем границы двух соседних ячеек.
 * @param Border1
 * @param Border2
 * @param bTableBorder1 - является ли граница границей всей таблицы
 * @param bTableBorder2 - является ли граница границей всей таблицы
 */
CTable.prototype.Internal_CompareBorders = function(Border1, Border2, bTableBorder1, bTableBorder2)
{
	if ("undefined" === typeof(bTableBorder1))
		bTableBorder1 = false;

	if ("undefined" === typeof(bTableBorder2))
		bTableBorder2 = false;

	// Граница ячейки всегда побеждает границу таблицы, если первая задана
	if (true === bTableBorder1)
		return Border2;

	if (true === bTableBorder2)
		return Border1;

	// Всегда побеждает непустая граница
	if (border_None === Border1.Value)
		return Border2;

	if (border_None === Border2.Value)
		return Border1;

	// TODO: Как только мы реализуем рисование не только простых границ,
	//       сделать здесь обработку. W_b = Border.Size * Border_Num,
	//       где Border_Num зависит от Border.Value

	var W_b_1 = Border1.Size;
	var W_b_2 = Border2.Size;
	if (W_b_1 > W_b_2)
		return Border1;
	else if (W_b_2 > W_b_1)
		return Border2;

	var Brightness_1_1 = Border1.Color.r + Border1.Color.b + 2 * Border1.Color.g;
	var Brightness_1_2 = Border2.Color.r + Border2.Color.b + 2 * Border2.Color.g;

	if (Brightness_1_1 < Brightness_1_2)
		return Border1;
	else if (Brightness_1_2 < Brightness_1_1)
		return Border2;

	var Brightness_2_1 = Border1.Color.b + 2 * Border1.Color.g;
	var Brightness_2_2 = Border2.Color.b + 2 * Border2.Color.g;

	if (Brightness_2_1 < Brightness_2_2)
		return Border1;
	else if (Brightness_2_2 < Brightness_2_1)
		return Border2;

	var Brightness_3_1 = Border1.Color.g;
	var Brightness_3_2 = Border2.Color.g;

	if (Brightness_3_1 < Brightness_3_2)
		return Border1;
	else if (Brightness_3_2 < Brightness_3_1)
		return Border2;

	// Две границы функционально идентичны, нам все равно какую рисовать.
	return Border1;
};
/**
 * Получаем левую верхнюю ячейку в текущем объединении
 */
CTable.prototype.Internal_Get_StartMergedCell = function(StartRow, StartGridCol, GridSpan)
{
	var Result = null;
	for (var Index = StartRow; Index >= 0; Index--)
	{
		var Row        = this.Content[Index];
		var BeforeInfo = Row.Get_Before();
		var CurGridCol = BeforeInfo.GridBefore;
		var CurCell    = 0;
		var CellsCount = Row.Get_CellsCount();

		var bWasMerged = false;
		while (CurGridCol <= StartGridCol && CurCell < CellsCount)
		{
			var Cell         = Row.Get_Cell(CurCell);
			var CellGridSpan = Cell.Get_GridSpan();
			var Vmerge       = Cell.Get_VMerge();

			if (CurGridCol === StartGridCol && GridSpan === CellGridSpan && vmerge_Continue === Vmerge)
			{
				bWasMerged = true;
				Result     = Cell;
				break;
			}
			else if (CurGridCol === StartGridCol && GridSpan === CellGridSpan && vmerge_Continue != Vmerge)
			{
				bWasMerged = true;
				Result     = Cell;
				return Result;
			}
			// Если данная ячейка имеет пересечение с заданным промежутком, но польностью с ним не совпадает
			else if (CurGridCol <= StartGridCol + GridSpan - 1 && CurGridCol + CellGridSpan - 1 >= StartGridCol)
				break;

			CurGridCol += CellGridSpan;
			CurCell++;
		}

		if (false === bWasMerged)
			break;
	}

	return Result;
};
/**
 * Получаем левую верхнюю ячейку в текущем объединении
 */
CTable.prototype.Internal_Get_EndMergedCell = function(StartRow, StartGridCol, GridSpan)
{
	var Result = null;
	for (var Index = StartRow, Count = this.Content.length; Index < Count; Index++)
	{
		var Row        = this.Content[Index];
		var BeforeInfo = Row.Get_Before();
		var CurGridCol = BeforeInfo.GridBefore;
		var CurCell    = 0;
		var CellsCount = Row.Get_CellsCount();

		var bWasMerged = false;
		while (CurGridCol <= StartGridCol && CurCell < CellsCount)
		{
			var Cell         = Row.Get_Cell(CurCell);
			var CellGridSpan = Cell.Get_GridSpan();
			var Vmerge       = Cell.Get_VMerge();

			if (CurGridCol === StartGridCol && GridSpan === CellGridSpan)
			{
				if (vmerge_Continue === Vmerge || Index === StartRow)
				{
					bWasMerged = true;
					Result     = Cell;
					break;
				}
				else
					return Result;
			}
			// Если данная ячейка имеет пересечение с заданным промежутком, но польностью с ним не совпадает
			else if (CurGridCol <= StartGridCol + GridSpan - 1 && CurGridCol + CellGridSpan - 1 >= StartGridCol)
				break;

			CurGridCol += CellGridSpan;
			CurCell++;
		}

		if (false === bWasMerged)
			break;
	}

	return Result;
};
/**
 * Получаем массив ячеек попадающих в заданное вертикальное объединение
 */
CTable.prototype.private_GetMergedCells = function(RowIndex, StartGridCol, GridSpan)
{
	// Сначала проверим данну строку
	var Row       = this.Content[RowIndex];
	var CellIndex = this.Internal_Get_Cell_ByStartGridCol(RowIndex, StartGridCol);
	if (-1 === CellIndex)
		return [];

	var Cell = Row.Get_Cell(CellIndex);
	if (GridSpan !== Cell.Get_GridSpan())
		return [];

	var CellsArray = [Cell];

	// Ищем ячейки вверх
	for (var Index = RowIndex - 1; Index >= 0; Index--)
	{
		var CellIndex = this.Internal_Get_Cell_ByStartGridCol(Index, StartGridCol);
		if (-1 === CellIndex)
			break;

		var Cell = this.Content[Index].Get_Cell(CellIndex);
		if (GridSpan !== Cell.Get_GridSpan())
			break;

		var Vmerge = Cell.Get_VMerge();
		if (vmerge_Continue !== Vmerge)
			break;

		CellsArray.splice(0, 0, Cell);
	}

	// Ищем ячейки вниз
	for (var Index = RowIndex + 1, Count = this.Content.length; Index < Count; Index++)
	{
		var CellIndex = this.Internal_Get_Cell_ByStartGridCol(Index, StartGridCol);
		if (-1 === CellIndex)
			break;

		var Cell = this.Content[Index].Get_Cell(CellIndex);
		if (GridSpan !== Cell.Get_GridSpan())
			break;

		var Vmerge = Cell.Get_VMerge();
		if (vmerge_Continue !== Vmerge)
			break;

		CellsArray.push(Cell);
	}

	return CellsArray;
};
CTable.prototype.private_GetCellsPosArrayByCellsArray = function(CellsArray)
{
	var Result = [];
	for (var Index = 0, Count = CellsArray.length; Index < Count; Index++)
	{
		var Cell = CellsArray[Index];
		Result.push({Cell : Cell.Index, Row : Cell.Row.Index});
	}

	return Result;
};
/**
 * Получаем левую верхнюю ячейку в текущем объединении
 */
CTable.prototype.Internal_Get_StartMergedCell2 = function(CellIndex, RowIndex)
{
	var Row      = this.Content[RowIndex];
	var Cell     = Row.Get_Cell(CellIndex);
	var CellInfo = Row.Get_CellInfo(CellIndex);

	return this.Internal_Get_StartMergedCell(RowIndex, CellInfo.StartGridCol, Cell.Get_GridSpan());
};
/**
 * Получаем номер ячейки в заданной строке по заданной колонке.
 */
CTable.prototype.Internal_Get_Cell_ByStartGridCol = function(RowIndex, StartGridCol)
{
	var Row = this.Content[RowIndex];

	var BeforeInfo = Row.Get_Before();
	var CurGridCol = BeforeInfo.GridBefore;
	var CellsCount = Row.Get_CellsCount();

	for (var CurCell = 0; CurCell < CellsCount; CurCell++)
	{
		var Cell     = Row.Get_Cell(CurCell);
		var GridSpan = Cell.Get_GridSpan();

		if (StartGridCol === CurGridCol)
			return CurCell;
		else if (CurGridCol > StartGridCol)
			return -1;

		CurGridCol += GridSpan;
	}

	return -1;
};
CTable.prototype.Internal_Update_TableMarkup = function(RowIndex, CellIndex, PageNum)
{
	this.Markup.Internal =
		{
			RowIndex  : RowIndex,
			CellIndex : CellIndex,
			PageNum   : PageNum
		};

	var Page      = this.Pages[PageNum];
	this.Markup.X = Page.X;

	var Row         = this.Content[RowIndex];
	var CellSpacing = ( null === Row.Get_CellSpacing() ? 0 : Row.Get_CellSpacing() );
	var CellsCount  = Row.Get_CellsCount();

	var GridBefore = Row.Get_Before().GridBefore;
	this.Markup.X += this.TableSumGrid[GridBefore - 1];

	this.Markup.Cols    = [];
	this.Markup.Margins = [];
	for (var CurCell = 0; CurCell < CellsCount; CurCell++)
	{
		var Cell         = Row.Get_Cell(CurCell);
		var StartGridCol = Row.Get_CellInfo(CurCell).StartGridCol;
		var GridSpan     = Cell.Get_GridSpan();
		var CellMargin   = Cell.Get_Margins();

		this.Markup.Cols.push(this.TableSumGrid[StartGridCol + GridSpan - 1] - this.TableSumGrid[StartGridCol - 1]);

		var Margin_left  = CellMargin.Left.W;
		var Margin_right = CellMargin.Right.W;
		if (0 === CurCell)
			Margin_left += CellSpacing;
		else
			Margin_left += CellSpacing / 2;

		if (CellsCount - 1 === CurCell)
			Margin_right += CellSpacing;
		else
			Margin_right += CellSpacing / 2;

		this.Markup.Margins.push({Left : Margin_left, Right : Margin_right});
	}

	// Определим какие строки попадают на данную страницу
	var Row_start = this.Pages[PageNum].FirstRow;
	var Row_last  = Row_start;

	if (PageNum + 1 < this.Pages.length)
	{
		Row_last = this.Pages[PageNum + 1].FirstRow;

		// Возможно, на данной странице строку, с которой началось разбиение на стрнице,
		// не надо рисовать. (Если начальная и конечная строки совпадают, тогда это 2
		// или более страница данной строки)
		if ((Row_start != Row_last || ( 0 === Row_start && 0 === Row_last ) ) && false === this.RowsInfo[Row_last].FirstPage)
			Row_last--;
	}
	else
		Row_last = this.Content.length - 1;

	this.Markup.Rows = [];
	for (var CurRow = Row_start; CurRow <= Row_last; CurRow++)
	{
		if (this.RowsInfo[CurRow] && this.RowsInfo[CurRow].Y[PageNum] && this.RowsInfo[CurRow].H[PageNum])
			this.Markup.Rows.push({Y : this.RowsInfo[CurRow].Y[PageNum], H : this.RowsInfo[CurRow].H[PageNum]});
	}

	this.Markup.CurCol = CellIndex;
	this.Markup.CurRow = RowIndex - Row_start;

	var Transform = this.Get_ParentTextTransform();
	this.DrawingDocument.Set_RulerState_Table(this.Markup, Transform);
};
/**
 * Проверяем попалили мы в какую либо границу.
 *      0
 *    |---|
 *   3|   |1
 *    |---|
 *      2
 */
CTable.prototype.Internal_CheckBorders = function(X, Y, PageNum)
{
	var CurPage = PageNum;
	var Page    = this.Pages[CurPage];

	// Сначала определим ячейку, у которой границы мы будем проверять
	var CellPos = this.Internal_GetCellByXY(X, Y, PageNum);

	var Row      = this.Content[CellPos.Row];
	var Cell     = Row.Get_Cell(CellPos.Cell);
	var CellInfo = Row.Get_CellInfo(CellPos.Cell);

	var VMerge_count_over = this.Internal_GetVertMergeCount(CellPos.Row, CellInfo.StartGridCol, Cell.Get_GridSpan());
	var VMerge_count      = this.private_GetVertMergeCountOnPage(PageNum, CellPos.Row, CellInfo.StartGridCol, Cell.Get_GridSpan());
	if (VMerge_count <= 0)
		return {Pos : CellPos, Border : -1};

	var Row_end      = this.Content[CellPos.Row + VMerge_count - 1];
	var Cell_end     = this.Internal_Get_Cell_ByStartGridCol(CellPos.Row + VMerge_count - 1, CellInfo.StartGridCol);
	var CellInfo_end = Row_end.Get_CellInfo(Cell_end.Index);

	var X_cell_start = Page.X + CellInfo.X_grid_start;
	var X_cell_end   = Page.X + CellInfo.X_grid_end;

	var Y_cell_start = this.RowsInfo[CellPos.Row].Y[PageNum];
	var Y_cell_end   = this.RowsInfo[CellPos.Row + VMerge_count - 1].Y[PageNum] + this.RowsInfo[CellPos.Row + VMerge_count - 1].H[PageNum];

	var Radius = this.DrawingDocument.GetMMPerDot(3); // 3 px

	if (Y <= Y_cell_start + Radius && Y >= Y_cell_start - Radius)
	{
		return {Pos : CellPos, Border : 0};
	}
	else if (Y <= Y_cell_end + Radius && Y >= Y_cell_end - Radius)
	{
		if (VMerge_count != VMerge_count_over)
			return {Pos : CellPos, Border : -1}

		return {Pos : CellPos, Border : 2, Row : CellPos.Row + VMerge_count_over - 1};
	}
	else if (X <= X_cell_start + Radius && X >= X_cell_start - Radius)
	{
		return {Pos : CellPos, Border : 3};
	}
	else if (X <= X_cell_end + Radius && X >= X_cell_end - Radius)
	{
		return {Pos : CellPos, Border : 1};
	}

	return {Pos : CellPos, Border : -1};
};
CTable.prototype.Internal_Selection_UpdateCells = function(bForceSelectByLines)
{
	if ("undefined" == typeof(bForceSelectByLines))
		bForceSelectByLines = false;

	this.Selection.Type = table_Selection_Cell;
	this.Selection.Data = [];

	if (0 === this.Parent.GetSelectDirection() && false == bForceSelectByLines)
	{
		// Определяем ячейки, которые попали в наш селект
		// Алгоритм следующий:
		//  1. Находим максимальную левую и правую границы, у начальной и конечной
		//     ячеек селекта. Границы мы находим по сетке таблицы (TableGrid).
		//  2. Бежим по строкам и добавляем все ячейки, которые имеют непустое пересечение
		//     с нашим диапазоном в сетке.

		var StartRow  = this.Selection.StartPos.Pos.Row;
		var StartCell = this.Selection.StartPos.Pos.Cell;
		var EndRow    = this.Selection.EndPos.Pos.Row;
		var EndCell   = this.Selection.EndPos.Pos.Cell;

		if (EndRow < StartRow)
		{
			var TempRow = StartRow;
			StartRow    = EndRow;
			EndRow      = TempRow;

			var TempCell = StartCell;
			StartCell    = EndCell;
			EndCell      = TempCell;
		}

		if (StartRow === EndRow)
		{
			if (EndCell < StartCell)
			{
				var TempCell = StartCell;
				StartCell    = EndCell;
				EndCell      = TempCell;
			}

			var Row = this.Content[StartRow];
			for (var CurCell = StartCell; CurCell <= EndCell; CurCell++)
			{
				var Cell     = Row.Get_Cell(CurCell);
				var GridSpan = Cell.Get_GridSpan();
				var Vmerge   = Cell.Get_VMerge();

				// Обсчет такик ячеек произошел ранее
				if (vmerge_Continue === Vmerge)
				{
					CurGridCol += GridSpan;
					continue;
				}
				this.Selection.Data.push({Row : StartRow, Cell : CurCell});
			}
		}
		else
		{
			var Cell_s = this.Content[StartRow].Get_Cell(StartCell);
			var Cell_e = this.Content[EndRow].Get_Cell(EndCell);

			var GridCol_cs_start = this.Content[StartRow].Get_StartGridCol(StartCell);
			var GridCol_cs_end   = Cell_s.Get_GridSpan() - 1 + GridCol_cs_start;
			var GridCol_ce_start = this.Content[EndRow].Get_StartGridCol(EndCell);
			var GridCol_ce_end   = Cell_e.Get_GridSpan() - 1 + GridCol_ce_start;

			var GridCol_start = GridCol_cs_start;
			if (GridCol_ce_start < GridCol_start)
				GridCol_start = GridCol_ce_start;

			var GridCol_end = GridCol_cs_end;
			if (GridCol_end < GridCol_ce_end)
				GridCol_end = GridCol_ce_end;

			for (var CurRow = StartRow; CurRow <= EndRow; CurRow++)
			{
				var Row        = this.Content[CurRow];
				var BeforeInfo = Row.Get_Before();
				var CurGridCol = BeforeInfo.GridBefore;
				var CellsCount = Row.Get_CellsCount();
				for (var CurCell = 0; CurCell < CellsCount; CurCell++)
				{
					var Cell     = Row.Get_Cell(CurCell);
					var GridSpan = Cell.Get_GridSpan();
					var Vmerge   = Cell.Get_VMerge();

					// Обсчет такик ячеек произошел ранее
					if (vmerge_Continue === Vmerge)
					{
						CurGridCol += GridSpan;
						continue;
					}

					// У первой строки мы не селектим ячейки до начальной.
					// Аналогично, у последней строки мы не селектим ничего после
					// конечной ячейки.
					if (( StartRow === CurRow /*&& CurCell >= StartCell*/ ) || ( EndRow === CurRow /*&& CurCell <= EndCell*/ ) || ( CurRow > StartRow && CurRow < EndRow ))
					{
						if (( CurGridCol >= GridCol_start && CurGridCol <= GridCol_end ) || ( CurGridCol + GridSpan - 1 >= GridCol_start && CurGridCol + GridSpan - 1 <= GridCol_end ))
							this.Selection.Data.push({Row : CurRow, Cell : CurCell});
					}

					CurGridCol += GridSpan;
				}
			}
		}
	}
	else
	{
		var RowsCount = this.Content.length;

		var StartRow = Math.min(Math.max(0, this.Selection.StartPos.Pos.Row), RowsCount - 1);
		var EndRow   = Math.min(Math.max(0, this.Selection.EndPos.Pos.Row), RowsCount - 1);

		if (EndRow < StartRow)
		{
			var TempRow = StartRow;
			StartRow    = EndRow;
			EndRow      = TempRow;
		}

		for (var CurRow = StartRow; CurRow <= EndRow; CurRow++)
		{
			var Row        = this.Content[CurRow];
			var CellsCount = Row.Get_CellsCount();
			for (var CurCell = 0; CurCell < CellsCount; CurCell++)
			{
				var Cell   = Row.Get_Cell(CurCell);
				var Vmerge = Cell.Get_VMerge();

				if (vmerge_Continue === Vmerge)
					continue;

				this.Selection.Data.push({Row : CurRow, Cell : CurCell});
			}
		}
	}

	if (this.Selection.Data.length > 1)
		this.Selection.CurRow = this.Selection.Data[this.Selection.Data.length - 1].Row;

	// В "flow" таблице обновляем значения настроек для параграфа и текста
	if (true != this.Is_Inline() && true === this.Selection.Use && false === this.Selection.Start)
	{
		var ParaPr = this.GetCalculatedParaPr();
		if (null != ParaPr)
			editor.UpdateParagraphProp(ParaPr);

		var TextPr = this.GetCalculatedTextPr();
		if (null != TextPr)
			editor.UpdateTextPr(TextPr);
	}
};
CTable.prototype.Internal_CompareBorders2 = function(Border1, Border2)
{
	var ResultBorder = new CDocumentBorder();
	if (Border1.Value != Border2.Value)
		ResultBorder.Value = undefined;
	else
		ResultBorder.Value = Border1.Value;

	if (Border1.Size != Border2.Size)
		ResultBorder.Size = undefined;
	else
		ResultBorder.Size = Border1.Size;

	if (undefined === Border1.Color || undefined === Border2.Color || Border1.Color.r != Border2.Color.r || Border1.Color.g != Border2.Color.g || Border1.Color.b != Border2.Color.b)
		ResultBorder.Color = undefined;
	else
		ResultBorder.Color.Set(Border1.Color.r, Border1.Color.g, Border1.Color.b);

	return ResultBorder;
};
CTable.prototype.Internal_CompareBorders3 = function(Border1, Border2)
{
	if (Border1.Value != Border2.Value)
		return false;

	if (Border1.Size != Border2.Size)
		return false;

	if (Border1.Color.r != Border2.Color.r || Border1.Color.g != Border2.Color.g || Border1.Color.b != Border2.Color.b)
		return false;

	return true;
};
CTable.prototype.Internal_CheckNullBorder = function(Border)
{
	if (null === Border || undefined === Border)
		return true;

	if (null != Border.Value)
		return false;

	if (null != Border.Size)
		return false;

	if (null != Border.Color && ( null != Border.Color.r || null != Border.Color.g || null != Border.Color.b ) || Border.Unifill != null)
		return false;

	return true;
};
CTable.prototype.Internal_Get_SelectionArray = function()
{
	var SelectionArray = null;
	if (true === this.ApplyToAll)
	{
		SelectionArray = [];
		for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
		{
			var Row = this.Content[CurRow];
			for (var CurCell = 0; CurCell < Row.Get_CellsCount(); CurCell++)
			{
				var Cell   = Row.Get_Cell(CurCell);
				var Vmerge = Cell.Get_VMerge();

				if (vmerge_Continue === Vmerge)
					continue;

				SelectionArray.push({Cell : CurCell, Row : CurRow});
			}
		}
	}
	else if (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type)
		SelectionArray = this.Selection.Data;
	else
		SelectionArray = [{Cell : this.CurCell.Index, Row : this.CurCell.Row.Index}];

	return SelectionArray;
};
CTable.prototype.Internal_Get_TableMinWidth = function()
{
	var MinWidth = 0;
	// Оценим минимально возможную ширину
	for (var CurRow = 0; CurRow < this.Content.length; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();

		var CellSpacing = Row.Get_CellSpacing();
		if (null === CellSpacing)
			CellSpacing = 0;

		var RowWidth = CellSpacing * ( Cells_Count + 1 );

		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell         = Row.Get_Cell(CurCell);
			var Cell_Margins = Cell.Get_Margins();

			RowWidth += Cell_Margins.Left.W + Cell_Margins.Right.W;
		}

		if (MinWidth < RowWidth)
			MinWidth = RowWidth;
	}

	return MinWidth;
};
CTable.prototype.Internal_Get_MinSumGrid = function()
{
	var ColsCount = this.TableGridCalc.length;
	var SumGrid   = [];
	for (var Index = -1; Index < ColsCount; Index++)
		SumGrid[Index] = 0;

	var RowsCount = this.Content.length;
	for (var CurRow = 0; CurRow < RowsCount; CurRow++)
	{
		var Row         = this.Content[CurRow];
		var Cells_Count = Row.Get_CellsCount();

		var CellSpacing = Row.Get_CellSpacing();
		if (null === CellSpacing)
			CellSpacing = 0;

		var CurGridCol = 0;

		for (var CurCell = 0; CurCell < Cells_Count; CurCell++)
		{
			var Cell         = Row.Get_Cell(CurCell);
			var Cell_Margins = Cell.Get_Margins();
			var GridSpan     = Cell.Get_GridSpan();

			var Cell_MinWidth = Cell_Margins.Left.W + Cell_Margins.Right.W;
			if (0 === CurCell || Cells_Count - 1 === CurCell)
				Cell_MinWidth += CellSpacing * 1.5;
			else
				Cell_MinWidth += CellSpacing;

			if (SumGrid[CurGridCol + GridSpan - 1] < SumGrid[CurGridCol - 1] + Cell_MinWidth)
				SumGrid[CurGridCol + GridSpan - 1] = SumGrid[CurGridCol - 1] + Cell_MinWidth;

			CurGridCol += GridSpan;
		}
	}

	return SumGrid;
};
CTable.prototype.Internal_ScaleTableWidth = function(SumGrid, TableW)
{
	var SumGrid_min = this.Internal_Get_MinSumGrid();

	// Массив означает, какие колонки таблицы нам надо изменить
	var Grids_to_scale = [];
	for (var Index = 0; Index < SumGrid.length; Index++)
		Grids_to_scale[Index] = true;

	var Grids_to_scale_count = Grids_to_scale.length;

	var TableGrid = [];
	TableGrid[0]  = SumGrid[0];
	for (var Index = 1; Index < SumGrid.length; Index++)
		TableGrid[Index] = SumGrid[Index] - SumGrid[Index - 1];

	var TableGrid_min = [];
	TableGrid_min[0]  = SumGrid_min[0];
	for (var Index = 1; Index < SumGrid_min.length; Index++)
		TableGrid_min[Index] = SumGrid_min[Index] - SumGrid_min[Index - 1];

	var CurrentW = SumGrid[SumGrid.length - 1];
	while (Grids_to_scale_count > 0 && CurrentW > 0.001)
	{
		// Пробуем ужать колонки таблицы
		var Koef = TableW / CurrentW;

		var TableGrid_cur = [];
		for (var Index = 0; Index < TableGrid.length; Index++)
			TableGrid_cur[Index] = TableGrid[Index];

		for (var AddIndex = 0; AddIndex <= TableGrid_cur.length - 1; AddIndex++)
		{
			if (true === Grids_to_scale[AddIndex])
				TableGrid_cur[AddIndex] = TableGrid_cur[AddIndex] * Koef;
		}

		var bBreak = true;

		// Проверяем, не стали ли некоторые колонки меньше минимально возможной ширины
		for (var AddIndex = 0; AddIndex <= TableGrid_cur.length - 1; AddIndex++)
		{
			if (true === Grids_to_scale[AddIndex] && TableGrid_cur[AddIndex] - TableGrid_min[AddIndex] < 0.001)
			{
				bBreak                   = false;
				Grids_to_scale[AddIndex] = false;
				Grids_to_scale_count--;

				CurrentW -= TableGrid[AddIndex];
				TableW -= TableGrid_min[AddIndex];

				TableGrid[AddIndex] = TableGrid_min[AddIndex];
			}
		}

		if (true === bBreak)
		{
			for (var AddIndex = 0; AddIndex <= TableGrid_cur.length - 1; AddIndex++)
			{
				if (true === Grids_to_scale[AddIndex])
					TableGrid[AddIndex] = TableGrid_cur[AddIndex];
			}

			break;
		}
	}

	var SumGrid_new = [];
	SumGrid_new[-1] = 0;
	for (var Index = 0; Index < TableGrid.length; Index++)
		SumGrid_new[Index] = TableGrid[Index] + SumGrid_new[Index - 1];

	return SumGrid_new;
};
CTable.prototype.Internal_Get_NextCell = function(Pos)
{
	var Cell_Index = Pos.Cell;
	var Row_Index  = Pos.Row;

	if (Cell_Index < this.Content[Row_Index].Get_CellsCount() - 1)
	{
		Pos.Cell = Cell_Index + 1;
		return this.Content[Pos.Row].Get_Cell(Pos.Cell);
	}
	else if (Row_Index < this.Content.length - 1)
	{
		Pos.Row  = Row_Index + 1;
		Pos.Cell = 0;
		return this.Content[Pos.Row].Get_Cell(Pos.Cell);
	}
	else
		return null;
};
CTable.prototype.Internal_Get_PrevCell = function(Pos)
{
	var Cell_Index = Pos.Cell;
	var Row_Index  = Pos.Row;

	if (Cell_Index > 0)
	{
		Pos.Cell = Cell_Index - 1;
		return this.Content[Pos.Row].Get_Cell(Pos.Cell);
	}
	else if (Row_Index > 0)
	{
		Pos.Row  = Row_Index - 1;
		Pos.Cell = this.Content[Row_Index - 1].Get_CellsCount() - 1;
		return this.Content[Pos.Row].Get_Cell(Pos.Cell);
	}
	else
		return null;
};
CTable.prototype.Internal_Copy_Grid = function(Grid)
{
	if (undefined !== Grid && null !== Grid)
	{
		var Count   = Grid.length;
		var NewGrid = new Array(Count);
		var Index   = 0;
		for (; Index < Count; Index++)
			NewGrid[Index] = Grid[Index];

		return NewGrid;
	}

	return [];
};
CTable.prototype.private_UpdateTableRulerOnBorderMove = function(Pos)
{
	if (null != this.Selection.Data2.Min)
		Pos = Math.max(Pos, this.Selection.Data2.Min);

	if (null != this.Selection.Data2.Max)
		Pos = Math.min(Pos, this.Selection.Data2.Max);

	// Обновляем Markup по ячейке в которой мы двигаем границу. Так делаем, потому что мы можем находится изначально
	// на другой странице данной таблице, а там Markup может быть совершенно другим. В конце движения границы
	// произойдет обновление селекта, и Markup обновится по текущему положению курсора.
	this.Internal_Update_TableMarkup(this.Selection.Data2.Pos.Row, this.Selection.Data2.Pos.Cell, this.Selection.Data2.PageNum);
	this.DrawingDocument.UpdateTableRuler(this.Selection.Data2.bCol, this.Selection.Data2.Index, Pos);

	return Pos;
};
/**
 * Считаем количество соединенных вертикально ячеек на заданной странице
 */
CTable.prototype.private_GetVertMergeCountOnPage = function(CurPage, CurRow, StartGridCol, GridSpan)
{
	var VMergeCount = this.Internal_GetVertMergeCount(CurRow, StartGridCol, GridSpan);

	if (true !== this.Is_EmptyPage(CurPage) && CurRow + VMergeCount - 1 >= this.Pages[CurPage].LastRow)
	{
		VMergeCount = this.Pages[CurPage].LastRow + 1 - CurRow;
		if (false === this.RowsInfo[CurRow + VMergeCount - 1].FirstPage && CurPage === this.RowsInfo[CurRow + VMergeCount - 1].StartPage)
			VMergeCount--;
	}

	return VMergeCount;
};
CTable.prototype.Get_TopElement = function()
{
    if (!this.Parent)
        return null;

    if (true === this.Parent.Is_TopDocument(false))
        return this;

    return this.Parent.Get_TopElement();
};
CTable.prototype.Get_Index = function()
{
    if (!this.Parent)
        return -1;

    this.Parent.Update_ContentIndexing();

    return this.Index;
};
CTable.prototype.Get_RowsCount = function()
{
    return this.Content.length;
};
CTable.prototype.Get_Row = function(Index)
{
    return this.Content[Index];
};
CTable.prototype.Compare_DrawingsLogicPositions = function(CompareObject)
{
    for (var CurRow = 0, RowsCount = this.Get_RowsCount(); CurRow < RowsCount; CurRow++)
    {
        var Row = this.Get_Row(CurRow);
        for (var CurCell = 0, CellsCount = Row.Get_CellsCount(); CurCell < CellsCount; CurCell++)
        {
            var Cell = Row.Get_Cell(CurCell);
            Cell.Content.Compare_DrawingsLogicPositions(CompareObject);

            if (0 !== CompareObject.Result)
                return;
        }
    }
};
CTable.prototype.StartSelectionFromCurPos = function()
{
	this.Selection.Use    = true;
	this.Selection.Type   = table_Selection_Text;
	this.Selection.CurRow = this.CurCell.Row.Index;

	this.Selection.StartPos.Pos = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
	this.Selection.EndPos.Pos   = {Cell : this.CurCell.Index, Row : this.CurCell.Row.Index};
	this.Internal_Selection_UpdateCells();

	this.CurCell.Content.StartSelectionFromCurPos();
};
CTable.prototype.Get_StyleFromFormatting = function()
{
    var SelectionArray = this.Internal_Get_SelectionArray();
    if (SelectionArray.length > 0)
    {
        var Pos = SelectionArray[0];
        var Cell = this.Content[Pos.Row].Get_Cell(Pos.Cell);
        return Cell.Content.Get_StyleFromFormatting();
    }
    return null;
};
CTable.prototype.Set_ReviewType = function(ReviewType)
{

};
CTable.prototype.Get_ReviewType = function()
{
    return reviewtype_Common;
};
CTable.prototype.Get_SectPr = function()
{
    if (this.Parent && this.Parent.Get_SectPr)
    {
        this.Parent.Update_ContentIndexing();
        return this.Parent.Get_SectPr(this.Index);
    }

    return null;
};
CTable.prototype.Is_SelectedAll = function()
{
    if (true !== this.Selection.Use)
        return false;

    var ArrayPos = 0;
    var SelectionArray = this.Selection.Data;
    for (var CurRow = 0, RowsCount = this.Content.length; CurRow < RowsCount; CurRow++)
    {
        var Row = this.Content[CurRow];
        for (var CurCell = 0, CellsCount = Row.Get_CellsCount(); CurCell < CellsCount; CurCell++, ArrayPos++)
        {
            if (ArrayPos >= SelectionArray.length)
                return false;

            var Pos = SelectionArray[ArrayPos];
            if (Pos.Row !== CurRow || Pos.Cell !== CurCell)
                return false;
        }
    }

    return true;
};
CTable.prototype.Accept_RevisionChanges = function(Type, bAll)
{
    if (true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0))
    {
        var Cells_array = this.Internal_Get_SelectionArray();
        for (var Index = 0, Count = Cells_array.length; Index < Count; Index++)
        {
            var Pos = Cells_array[Index];
            var Row = this.Content[Pos.Row];
            var Cell = Row.Get_Cell(Pos.Cell);
            var Cell_Content = Cell.Content;

            Cell.Content.Accept_RevisionChanges(Type, true);
        }
    }
    else
        return this.CurCell.Content.Accept_RevisionChanges(Type, bAll);
};
CTable.prototype.Reject_RevisionChanges = function(Type, bAll)
{
    if (true === this.ApplyToAll || (true === this.Selection.Use && table_Selection_Cell === this.Selection.Type && this.Selection.Data.length > 0))
    {
        var Cells_array = this.Internal_Get_SelectionArray();
        for (var Index = 0, Count = Cells_array.length; Index < Count; Index++)
        {
            var Pos = Cells_array[Index];
            var Row = this.Content[Pos.Row];
            var Cell = Row.Get_Cell(Pos.Cell);
            var Cell_Content = Cell.Content;

            Cell_Content.Reject_RevisionChanges(Type, true);
        }
    }
    else
        return this.CurCell.Content.Reject_RevisionChanges(Type, bAll);
};
CTable.prototype.Get_RevisionsChangeParagraph = function(SearchEngine)
{
    if (true === SearchEngine.Is_Found())
        return;

    var CurCell = 0, CurRow = 0;
    if (true !== SearchEngine.Is_CurrentFound())
    {
        var Cells_array = this.Internal_Get_SelectionArray();
        if (Cells_array.length <= 0)
            return;

        CurRow  = Cells_array[0].Row;
        CurCell = Cells_array[0].Cell;
    }
    else
    {
        if (SearchEngine.Get_Direction() > 0)
        {
            CurRow  = 0;
            CurCell = 0;
        }
        else
        {
            CurRow  = this.Get_RowsCount() - 1;
            CurCell = this.Get_Row(CurRow).Get_CellsCount() - 1;
        }
    }

    var Cell = this.Get_Row(CurRow).Get_Cell(CurCell);

    while (null != Cell && vmerge_Restart != Cell.Get_VMerge())
        Cell = this.private_GetPrevCell(CurRow, CurCell);

    Cell.Content.Get_RevisionsChangeParagraph(SearchEngine);
    while (true !== SearchEngine.Is_Found())
    {
        if (SearchEngine.Get_Direction() > 0)
        {
            Cell = this.private_GetNextCell(Cell.Row.Index, Cell.Index);
            while (null != Cell && vmerge_Restart != Cell.Get_VMerge())
                Cell = this.private_GetNextCell(Cell.Row.Index, Cell.Index);
        }
        else
        {
            Cell = this.private_GetPrevCell(Cell.Row.Index, Cell.Index);
            while (null != Cell && vmerge_Restart != Cell.Get_VMerge())
                Cell = this.private_GetPrevCell(Cell.Row.Index, Cell.Index);
        }

        if (null === Cell)
            break;

        Cell.Content.Get_RevisionsChangeParagraph(SearchEngine);
    }
};
CTable.prototype.private_GetNextCell = function(RowIndex, CellIndex)
{
    return this.Internal_Get_NextCell({Cell : CellIndex, Row : RowIndex});
};
CTable.prototype.private_GetPrevCell = function(RowIndex, CellIndex)
{
    return this.Internal_Get_PrevCell({Cell : CellIndex, Row : RowIndex});
};
CTable.prototype.Check_ChangedTableGrid = function()
{
    var TableGrid_old = this.Internal_Copy_Grid(this.TableGridCalc);
    this.private_RecalculateGrid();
    var TableGrid_new = this.TableGridCalc;
    for (var CurCol = 0, ColsCount = this.TableGridCalc.length; CurCol < ColsCount; CurCol++)
    {
        if (Math.abs(TableGrid_old[CurCol] - TableGrid_new[CurCol]) > 0.001)
        {
            this.RecalcInfo.TableBorders = true;
            return true;
        }
    }

    return false;
};
CTable.prototype.GetContentPosition = function(bSelection, bStart, PosArray)
{
    if (!PosArray)
        PosArray = [];

    var CurRow  = (true === bSelection ? (true === bStart ? this.Selection.StartPos.Pos.Row  : this.Selection.EndPos.Pos.Row)  : this.CurCell.Row.Index);
    var CurCell = (true === bSelection ? (true === bStart ? this.Selection.StartPos.Pos.Cell : this.Selection.EndPos.Pos.Cell) : this.CurCell.Index);

    var Row = this.Get_Row(CurRow);
    PosArray.push({Class : this, Position : CurRow});
    PosArray.push({Class : this.Get_Row(CurRow), Position : CurCell});

    if (Row && CurCell >= 0 && CurCell < Row.Get_CellsCount())
    {
        var Cell = Row.Get_Cell(CurCell);
        Cell.Content.GetContentPosition(bSelection, bStart, PosArray);
    }

    return PosArray;
};
CTable.prototype.Get_Index = function()
{
    if (!this.Parent)
        return -1;

    this.Parent.Update_ContentIndexing();
    return this.Index;
};
CTable.prototype.Get_DocumentPositionFromObject = function(PosArray)
{
    if (!PosArray)
        PosArray = [];

    if (this.Parent)
    {
        PosArray.splice(0, 0, {Class : this.Parent, Position : this.Get_Index()});
        this.Parent.Get_DocumentPositionFromObject(PosArray);
    }

    return PosArray;
};
CTable.prototype.SetContentSelection = function(StartDocPos, EndDocPos, Depth, StartFlag, EndFlag)
{
    if ((0 === StartFlag && (!StartDocPos[Depth] || this !== StartDocPos[Depth].Class)) || (0 === EndFlag && (!EndDocPos[Depth] || this !== EndDocPos[Depth].Class)))
        return;

    var IsOneElement = true;
    var StartRow = 0;
    switch (StartFlag)
    {
        case 0 : StartRow = StartDocPos[Depth].Position; break;
        case 1 : StartRow = 0; IsOneElement = false; break;
        case -1: StartRow = this.Content.length - 1; IsOneElement = false; break;
    }

    var EndRow = 0;
    switch (EndFlag)
    {
        case 0 : EndRow = EndDocPos[Depth].Position; break;
        case 1 : EndRow = 0; IsOneElement = false; break;
        case -1: EndRow = this.Content.length - 1; IsOneElement = false; break;
    }

    var _StartDocPos = StartDocPos, _StartFlag = StartFlag;
    if (null !== StartDocPos && true === StartDocPos[Depth].Deleted)
    {
        if (StartRow < this.Content.length)
        {
            _StartDocPos = null;
            _StartFlag = 1;
        }
        else if (StartRow > 0)
        {
            StartRow--;
            _StartDocPos = null;
            _StartFlag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    var _EndDocPos = EndDocPos, _EndFlag = EndFlag;
    if (null !== EndDocPos && true === EndDocPos[Depth].Deleted)
    {
        if (EndRow < this.Content.length)
        {
            _EndDocPos = null;
            _EndFlag = 1;
        }
        else if (EndRow > 0)
        {
            EndRow--;
            _EndDocPos = null;
            _EndFlag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    var StartCell = 0;
    switch (_StartFlag)
    {
        case 0 : StartCell = _StartDocPos[Depth + 1].Position; break;
        case 1 : StartCell = 0; break;
        case -1: StartCell = this.Content[StartRow].Get_CellsCount() - 1; break;
    }

    var EndCell = 0;
    switch (_EndFlag)
    {
        case 0 : EndCell = _EndDocPos[Depth + 1].Position; break;
        case 1 : EndCell = 0; break;
        case -1: EndCell = this.Content[EndRow].Get_CellsCount() - 1; break;
    }

    var __StartDocPos = _StartDocPos, __StartFlag = _StartFlag;
    if (null !== _StartDocPos && true === _StartDocPos[Depth + 1].Deleted)
    {
        if (StartCell < this.Content[StartRow].Get_CellsCount())
        {
            __StartDocPos = null;
            __StartFlag = 1;
        }
        else if (StartCell > 0)
        {
            StartCell--;
            __StartDocPos = null;
            __StartFlag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    var __EndDocPos = _EndDocPos, __EndFlag = _EndFlag;
    if (null !== _EndDocPos && true === _EndDocPos[Depth + 1].Deleted)
    {
        if (EndCell < this.Content[EndCell].Get_CellsCount())
        {
            __EndDocPos = null;
            __EndFlag   = 1;
        }
        else if (EndCell > 0)
        {
            EndCell--;
            __EndDocPos = null;
            __EndFlag   = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    this.Selection.Use          = true;
    this.Selection.StartPos.Pos = {Row : StartRow, Cell : StartCell};
    this.Selection.EndPos.Pos   = {Row : EndRow, Cell : EndCell};
    this.Selection.CurRow       = EndRow;
    this.Selection.Data         = null;
    this.Selection.Type2        = table_Selection_Common;
    this.Selection.Data2        = null;

    if (StartRow === EndRow && StartCell === EndCell)
    {
        this.CurCell = this.Get_Row(StartRow).Get_Cell(StartCell);
        this.Selection.Type = table_Selection_Text;
        this.CurCell.Content.SetContentSelection(__StartDocPos, __EndDocPos, Depth + 2, __StartFlag, __EndFlag);
    }
    else
    {
        this.Selection.Type = table_Selection_Cell;
        this.Internal_Selection_UpdateCells(IsOneElement ? false : true);
    }
};
CTable.prototype.SetContentPosition = function(DocPos, Depth, Flag)
{
    if (0 === Flag && (!DocPos[Depth] || this !== DocPos[Depth].Class))
        return;

    var CurRow = 0;
    switch (Flag)
    {
        case 0 : CurRow = DocPos[Depth].Position; break;
        case 1 : CurRow = 0; break;
        case -1: CurRow = this.Content.length - 1; break;
    }

    var _DocPos = DocPos, _Flag = Flag;
    if (null !== DocPos && true === DocPos[Depth].Deleted)
    {
        if (CurRow < this.Content.length)
        {
            _DocPos = null;
            _Flag = 1;
        }
        else if (CurRow > 0)
        {
            CurRow--;
            _DocPos = null;
            _Flag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    var CurCell = 0;
    switch (_Flag)
    {
        case 0 : CurCell = _DocPos[Depth + 1].Position; break;
        case 1 : CurCell = 0; break;
        case -1: CurCell = this.Content[CurRow].Get_CellsCount() - 1; break;
    }

    var __DocPos = _DocPos, __Flag = _Flag;
    if (null !== _DocPos && true === _DocPos[Depth + 1].Deleted)
    {
        if (CurCell < this.Content[CurRow].Get_CellsCount())
        {
            __DocPos = null;
            __Flag = 1;
        }
        else if (CurCell > 0)
        {
            CurCell--;
            __DocPos = null;
            __Flag = -1;
        }
        else
        {
            // Такого не должно быть
            return;
        }
    }

    var Row  = this.Get_Row(CurRow);
    if (!Row)
        return;

    var Cell = Row.Get_Cell(CurCell);
    if (!Cell)
        return;

    this.CurCell = Cell;
    this.CurCell.Content.SetContentPosition(__DocPos, Depth + 2, __Flag);
};
CTable.prototype.Set_CurCell = function(Cell)
{
    if (!Cell || this !== Cell.Get_Table())
        return;

    this.CurCell = Cell;
};
CTable.prototype.Is_EmptyPage = function(CurPage)
{
    if (!this.Pages[CurPage]
        || (this.Pages[CurPage].LastRow < this.Pages[CurPage].FirstRow)
        || (0 === CurPage && true !== this.RowsInfo[0].FirstPage))
        return true;

    return false;
};
CTable.prototype.Check_EmptyPages = function(CurPage)
{
    for (var _CurPage = CurPage; _CurPage >= 0; --_CurPage)
    {
        if (true !== this.Is_EmptyPage(_CurPage))
            return false;
    }

    return true;
};
CTable.prototype.private_StartTrackTable = function(CurPage)
{
    if (CurPage < 0 || CurPage >= this.Pages.length)
        return;

    var Bounds     = this.Get_PageBounds(CurPage);
    var NewOutline = new AscCommon.CTableOutline(this, this.Get_AbsolutePage(CurPage), Bounds.Left, Bounds.Top, Bounds.Right - Bounds.Left, Bounds.Bottom - Bounds.Top);

    var Transform = this.Get_ParentTextTransform();
    this.DrawingDocument.StartTrackTable(NewOutline, Transform);
};
CTable.prototype.Correct_BadTable = function()
{
    // TODO: Пока оставим эту заглушку на случай загрузки плохих таблиц. В будущем надо будет
    //       сделать нормальный обсчет для случая, когда у нас есть "пустые" строки (составленные
    //       из вертикально объединенных ячеек).
    this.Internal_Check_TableRows(false);
	this.CorrectBadGrid();
};
CTable.prototype.GetNumberingInfo = function(NumberingEngine)
{
    if (NumberingEngine.Is_Found())
        return;

    for (var CurRow = 0, RowsCount = this.Get_RowsCount(); CurRow < RowsCount; ++CurRow)
    {
        var Row = this.Get_Row(CurRow);
        for (var CurCell = 0, CellsCount = Row.Get_CellsCount(); CurCell < CellsCount; ++CurCell)
        {
            var Cell = Row.Get_Cell(CurCell);
            Cell.Content.GetNumberingInfo(NumberingEngine);

            if (NumberingEngine.Is_Found())
                return;
        }
    }
};
CTable.prototype.Is_TableFirstRowOnNewPage = function(CurRow)
{
    for (var CurPage = 0, PagesCount = this.Pages.length; CurPage < PagesCount; ++CurPage)
    {
        if (CurRow === this.Pages[CurPage].FirstRow && CurRow <= this.Pages[CurPage].LastRow)
        {
            if (0 === CurPage && (null != this.Get_DocumentPrev() || (true === this.Parent.Is_TableCellContent() && true !== this.Parent.Is_TableFirstRowOnNewPage())))
                return false;

            return true;
        }
    }

    return false;
};
CTable.prototype.private_UpdateCellsGrid = function()
{
    for (var nCurRow = 0, nRowsCount = this.Content.length; nCurRow < nRowsCount; ++nCurRow)
    {
        var Row        = this.Content[nCurRow];
        var BeforeInfo = Row.Get_Before();
        var CurGridCol = BeforeInfo.GridBefore;

        for (var nCurCell = 0, nCellsCount = Row.Get_CellsCount(); nCurCell < nCellsCount; ++nCurCell)
        {
            var Cell = Row.Get_Cell(nCurCell);
            var GridSpan = Cell.Get_GridSpan();
            Cell.Set_Metrics(CurGridCol, 0, 0, 0, 0, 0, 0);
            Row.Update_CellInfo(nCurCell);
            CurGridCol += GridSpan;
        }
    }
};
CTable.prototype.SetTableGrid = function(arrGrid)
{
	History.Add(new CChangesTableTableGrid(this, this.TableGrid, arrGrid));
	this.TableGrid = arrGrid;
};
CTable.prototype.private_CopyTableGrid = function()
{
	var arrGrid = [];
	for (var nIndex = 0, nCount = this.TableGrid.length; nIndex < nCount; ++nIndex)
	{
		arrGrid[nIndex] = this.TableGrid[nIndex];
	}
	return arrGrid;
};
CTable.prototype.private_CopyTableGridCalc = function()
{
	var arrGrid = [];
	for (var nIndex = 0, nCount = this.TableGridCalc.length; nIndex < nCount; ++nIndex)
	{
		arrGrid[nIndex] = this.TableGridCalc[nIndex];
	}
	return arrGrid;
};
CTable.prototype.CorrectBadGrid = function()
{
	// HACK: При загрузке мы запрещаем компилировать стили, но нам все-таки это здесь нужно
	var bLoad = AscCommon.g_oIdCounter.m_bLoad;
	var bRead = AscCommon.g_oIdCounter.m_bRead;
	AscCommon.g_oIdCounter.m_bLoad = false;
	AscCommon.g_oIdCounter.m_bRead = false;

	// Сначала пробежимся по всем ячейкам и посмотрим, чтобы у них были корректные GridSpan (т.е. >= 1)
	for (var Index = 0; Index < this.Content.length; Index++)
	{
		var Row        = this.Content[Index];
		var CellsCount = Row.Get_CellsCount();
		for (var CellIndex = 0; CellIndex < CellsCount; CellIndex++)
		{
			var Cell     = Row.Get_Cell(CellIndex);
			var GridSpan = Cell.Get_GridSpan();
			if (GridSpan <= 0)
				Cell.Set_GridSpan(1);
		}
	}

	var RowGrid   = [];
	var GridCount = 0;
	for (var Index = 0; Index < this.Content.length; Index++)
	{
		var Row = this.Content[Index];
		Row.Set_Index(Index);

		// Смотрим на ширину пропущенных колонок сетки в начале строки
		var BeforeInfo = Row.Get_Before();
		var CurGridCol = BeforeInfo.GridBefore;

		var CellsCount = Row.Get_CellsCount();
		for (var CellIndex = 0; CellIndex < CellsCount; CellIndex++)
		{
			var Cell     = Row.Get_Cell(CellIndex);
			var GridSpan = Cell.Get_GridSpan();
			CurGridCol += GridSpan;
		}

		// Смотрим на ширину пропущенных колонок сетки в конце строки
		var AfterInfo = Row.Get_After();
		CurGridCol += AfterInfo.GridAfter;

		if (GridCount < CurGridCol)
			GridCount = CurGridCol;

		RowGrid[Index] = CurGridCol;
	}

	for (var Index = 0; Index < this.Content.length; Index++)
	{
		var Row       = this.Content[Index];
		var AfterInfo = Row.Get_After();

		if (RowGrid[Index] < GridCount)
		{
			Row.Set_After(AfterInfo.GridAfter + GridCount - RowGrid[Index], AfterInfo.WAfter);
		}
	}

	var arrGrid = this.private_CopyTableGrid();
	if (arrGrid.length != GridCount)
	{
		if (arrGrid.length < GridCount)
		{
			for (var nIndex = 0; nIndex < GridCount; ++nIndex)
				arrGrid[nIndex] = 20;
		}
		else
		{
			arrGrid.splice(GridCount, arrGrid.length - GridCount);
		}
		this.SetTableGrid(arrGrid);
	}

	// HACK: Восстанавливаем флаги и выставляем, что стиль всей таблицы нужно пересчитать
	AscCommon.g_oIdCounter.m_bLoad = bLoad;
	AscCommon.g_oIdCounter.m_bRead = bRead;
	this.Recalc_CompiledPr2();
};
CTable.prototype.private_CorrectVerticalMerge = function()
{
	// Пробегаемся по всем ячейкам и смотрим на их вертикальное объединение, было ли оно нарушено
	for (var nCurRow = 0, nRowsCount = this.Content.length; nCurRow < nRowsCount; ++nCurRow)
	{
		var oRow     = this.Content[nCurRow];
		var nGridCol = oRow.Get_Before().GridBefore;
		for (var nCurCell = 0, nCellsCount = oRow.Get_CellsCount(); nCurCell < nCellsCount; ++nCurCell)
		{
			var oCell       = oRow.Get_Cell(nCurCell);
			var nVMergeType = oCell.Get_VMerge();
			var nGridSpan   = oCell.Get_GridSpan();

			if (vmerge_Continue === nVMergeType)
			{
				var bNeedReset = true;
				if (0 !== nCurRow)
				{
					var oPrevRow     = this.Content[nCurRow - 1];
					var nPrevGridCol = oPrevRow.Get_Before().GridBefore;
					for (var nPrevCell = 0, nPrevCellsCount = oPrevRow.Get_CellsCount(); nPrevCell < nPrevCellsCount; ++nPrevCell)
					{
						var oPrevCell     = oPrevRow.Get_Cell(nPrevCell);
						var nPrevGridSpan = oPrevCell.Get_GridSpan();

						if (nPrevGridCol === nGridCol)
						{
							if (nPrevGridSpan === nGridSpan)
								bNeedReset = false;

							break;
						}
						else if (nPrevGridCol > nGridCol)
							break;

						nPrevGridCol += nPrevGridSpan;
					}
				}

				if (true === bNeedReset)
					oCell.Set_VMerge(vmerge_Restart);
			}

			nGridCol += nGridSpan;
		}
	}
};
CTable.prototype.private_SetTableLayoutFixedAndUpdateCellsWidth = function(nExceptColNum)
{
	if (tbllayout_AutoFit === this.Get_CompiledPr(false).TablePr.TableLayout)
	{
		this.Set_TableLayout(tbllayout_Fixed);

		// Обновляем ширины ячеек
		var nColsCount = this.TableGrid.length;
		for (var nColIndex = 0; nColIndex < nColsCount; nColIndex++)
		{
			if (nColIndex != nExceptColNum)
				this.Internal_UpdateCellW(nColIndex);
		}
	}
};
CTable.prototype.GotoFootnoteRef = function(isNext, isCurrent)
{
	var nRow = 0, nCell = 0;
	if (true === isCurrent)
	{
		if (true === this.Selection.Use)
		{
			var nStartRow  = this.Selection.StartPos.Pos.Row;
			var nStartCell = this.Selection.StartPos.Pos.Cell;

			var nEndRow  = this.Selection.EndPos.Pos.Row;
			var nEndCell = this.Selection.EndPos.Pos.Cell;

			if (nStartRow < nEndRow || (nStartRow === nEndRow && nStartCell <= nEndCell))
			{
				nRow  = nStartRow;
				nCell = nStartCell;
			}
			else
			{
				nRow  = nEndRow;
				nCell = nEndCell;
			}
		}
		else
		{
			nCell = this.CurCell.Index;
			nRow  = this.CurCell.Row.Index;
		}
	}
	else
	{
		if (true === isNext)
		{
			nRow = 0;
			nCell = 0;
		}
		else
		{
			nRow  = this.Content.length - 1;
			nCell = this.Content[nRow].Get_CellsCount() - 1;
		}
	}

	if (true === isNext)
	{
		for (var nCurRow = nRow, nRowsCount = this.Content.length; nCurRow < nRowsCount; ++nCurRow)
		{
			var oRow = this.Content[nCurRow];
			var nStartCell = (nCurRow === nRow ? nCell : 0);
			for (var nCurCell = nStartCell, nCellsCount = oRow.Get_CellsCount(); nCurCell < nCellsCount; ++nCurCell)
			{
				var oCell = oRow.Get_Cell(nCurCell);
				if (oCell.Content.GotoFootnoteRef(true, true === isCurrent && nCurRow === nRow && nCurCell === nCell))
					return true;
			}
		}
	}
	else
	{
		for (var nCurRow = nRow; nCurRow >= 0; --nCurRow)
		{
			var oRow = this.Content[nCurRow];
			var nStartCell = (nCurRow === nRow ? nCell : oRow.Get_CellsCount() - 1);
			for (var nCurCell = nStartCell; nCurCell >= 0; --nCurCell)
			{
				var oCell = oRow.Get_Cell(nCurCell);
				if (oCell.Content.GotoFootnoteRef(false, true === isCurrent && nCurRow === nRow && nCurCell === nCell))
					return true;
			}
		}
	}

	return false;
};
CTable.prototype.CanUpdateTarget = function(CurPage)
{
	if (this.Pages.length <= 0)
		return false;

	if (this.Pages.length <= CurPage)
		return true;

	if (!this.Pages[CurPage])
		return false;

	var oRow, oCell;
	if (this.IsSelectionUse())
	{
		oCell = this.CurCell;
		oRow  = this.CurCell.Row;
	}
	else
	{
		var CurCell = this.Selection.EndPos.Pos.Cell;
		var CurRow  = this.Selection.EndPos.Pos.Row;

		oRow  = this.Content[CurRow];
		oCell = oRow.Get_Cell(CurCell);
	}

	if (!oRow || !oCell)
		return false;

	if (this.Pages[CurPage].LastRow > oRow.Index)
		return true;
	else if (this.Pages[CurPage].LastRow < oRow.Index)
		return false;

	return oCell.Content.CanUpdateTarget(CurPage - oCell.Content.Get_StartPage_Relative());
};
CTable.prototype.IsCellSelection = function()
{
	if (true === this.IsSelectionUse() && table_Selection_Cell === this.Selection.Type)
		return true;

	return false;
};
CTable.prototype.SetTableProps = function(oProps)
{
	this.Set_Props(oProps);
};
CTable.prototype.GetTableProps = function()
{
	return this.Get_Props();
};
CTable.prototype.IsInBlockLevelSdt = function(oBlockLevelSdt)
{
	if (true !== this.Selection.Use || table_Selection_Text === this.Selection.Type)
		return this.CurCell.Content.IsInBlockLevelSdt(oBlockLevelSdt);

	return oBlockLevelSdt;
};
//----------------------------------------------------------------------------------------------------------------------
// Класс  CTableLook
//----------------------------------------------------------------------------------------------------------------------
function CTableLook(bFC, bFR, bLC, bLR, bBH, bBV)
{
    this.m_bFirst_Col = ( true === bFC ? true : false );
    this.m_bFirst_Row = ( true === bFR ? true : false );
    this.m_bLast_Col  = ( true === bLC ? true : false );
    this.m_bLast_Row  = ( true === bLR ? true : false );
    this.m_bBand_Hor  = ( true === bBH ? true : false );
    this.m_bBand_Ver  = ( true === bBV ? true : false );
}
CTableLook.prototype =
{

    Set : function(bFC, bFR, bLC, bLR, bBH, bBV)
    {
        this.m_bFirst_Col = ( true === bFC ? true : false );
        this.m_bFirst_Row = ( true === bFR ? true : false );
        this.m_bLast_Col  = ( true === bLC ? true : false );
        this.m_bLast_Row  = ( true === bLR ? true : false );
        this.m_bBand_Hor  = ( true === bBH ? true : false );
        this.m_bBand_Ver  = ( true === bBV ? true : false );
    },

    Copy : function()
    {
        return new CTableLook( this.m_bFirst_Col, this.m_bFirst_Row, this.m_bLast_Col, this.m_bLast_Row, this.m_bBand_Hor, this.m_bBand_Ver );
    },

    Is_FirstCol : function()
    {
        return this.m_bFirst_Col;
    },

    Is_FirstRow : function()
    {
        return this.m_bFirst_Row;
    },

    Is_LastCol : function()
    {
        return this.m_bLast_Col;
    },

    Is_LastRow : function()
    {
        return this.m_bLast_Row;
    },

    Is_BandHor : function()
    {
        return this.m_bBand_Hor;
    },

    Is_BandVer : function()
    {
        return this.m_bBand_Ver;
    },

    Write_ToBinary : function(Writer)
    {
        // Bool : m_bFirst_Col
        // Bool : m_bFirst_Row
        // Bool : m_bLast_Col
        // Bool : m_bLast_Row
        // Bool : m_bBand_Hor
        // Bool : m_bBand_Ver

        Writer.WriteBool( this.m_bFirst_Col );
        Writer.WriteBool( this.m_bFirst_Row );
        Writer.WriteBool( this.m_bLast_Col );
        Writer.WriteBool( this.m_bLast_Row );
        Writer.WriteBool( this.m_bBand_Hor );
        Writer.WriteBool( this.m_bBand_Ver );
    },

    Read_FromBinary : function(Reader)
    {
        // Bool : m_bFirst_Col
        // Bool : m_bFirst_Row
        // Bool : m_bLast_Col
        // Bool : m_bLast_Row
        // Bool : m_bBand_Hor
        // Bool : m_bBand_Ver

        this.m_bFirst_Col = Reader.GetBool();
        this.m_bFirst_Row = Reader.GetBool();
        this.m_bLast_Col  = Reader.GetBool();
        this.m_bLast_Row  = Reader.GetBool();
        this.m_bBand_Hor  = Reader.GetBool();
        this.m_bBand_Ver  = Reader.GetBool();
    }
};
//----------------------------------------------------------------------------------------------------------------------
// Класс  CTableAnchorPosition
//----------------------------------------------------------------------------------------------------------------------
function CTableAnchorPosition()
{
    // Рассчитанные координаты
    this.CalcX         = 0;
    this.CalcY         = 0;

    // Данные для Flow-объектов
    this.W             = 0;
    this.H             = 0;
    this.X             = 0;
    this.Y             = 0;
    this.Left_Margin   = 0;
    this.Right_Margin  = 0;
    this.Top_Margin    = 0;
    this.Bottom_Margin = 0;
    this.Page_W        = 0;
    this.Page_H        = 0;

    this.Page_Top      = 0;
    this.Page_Bottom   = 0;

    this.X_min         = 0;
    this.Y_min         = 0;
    this.X_max         = 0;
    this.Y_max         = 0;
}
CTableAnchorPosition.prototype =
{
    Set_X : function(W, X, Left_Margin, Right_Margin, Page_W, X_min, X_max)
    {
        this.W             = W;
        this.X             = X;
        this.Left_Margin   = Left_Margin;
        this.Right_Margin  = Right_Margin;
        this.Page_W        = Page_W;
        this.X_min         = X_min;
        this.X_max         = X_max;
    },

    Set_Y : function(H, Y, Top_Margin, Bottom_Margin, Page_H, Y_min, Y_max, Page_Top, Page_Bottom)
    {
        this.H             = H;
        this.Y             = Y;
        this.Top_Margin    = Top_Margin;
        this.Bottom_Margin = Bottom_Margin;
        this.Page_H        = Page_H;
        this.Y_min         = Y_min;
        this.Y_max         = Y_max;
        this.Page_Top      = Page_Top;
        this.Page_Bottom   = Page_Bottom;
    },

    Calculate_X : function(RelativeFrom, bAlign, Value)
    {
        // Вычисляем координату по X
        switch(RelativeFrom)
        {
            // TODO: пока нет колонок варианты Text и Margin ничем не отличаются,
            //       когда появятся колонки доделать тут
            case c_oAscHAnchor.Text:
            case c_oAscHAnchor.Margin:
            {
                if ( true === bAlign )
                {
                    switch ( Value )
                    {
                        case c_oAscXAlign.Center:
                        {
                            this.CalcX = (this.Left_Margin + this.Right_Margin - this.W) / 2;
                            break;
                        }

                        case c_oAscXAlign.Inside:
                        case c_oAscXAlign.Outside:
                        case c_oAscXAlign.Left:
                        {
                            this.CalcX = this.Left_Margin;
                            break;
                        }

                        case c_oAscXAlign.Right:
                        {
                            this.CalcX = this.Right_Margin - this.W;
                            break;
                        }
                    }
                }
                else
                    this.CalcX = this.Left_Margin + Value;

                break;
            }

            case c_oAscHAnchor.Page:
            {
                var W = this.X_max - this.X_min;
                if ( true === bAlign )
                {
                    switch ( Value )
                    {
                        case c_oAscXAlign.Center:
                        {
                            this.CalcX = this.X_min + (W - this.W) / 2;
                            break;
                        }

                        case c_oAscXAlign.Inside:
                        case c_oAscXAlign.Outside:
                        case c_oAscXAlign.Left:
                        {
                            this.CalcX = this.X_min;
                            break;
                        }

                        case c_oAscXAlign.Right:
                        {
                            this.CalcX = this.X_max - this.W;
                            break;
                        }
                    }
                }
                else
                    this.CalcX = this.X_min + Value;

                break;
            }

            case c_oAscHAnchor.PageInternal:
            {
                if ( true === bAlign )
                {
                    switch ( Value )
                    {
                        case c_oAscXAlign.Center:
                        {
                            this.CalcX = (this.Page_W - this.W) / 2;
                            break;
                        }

                        case c_oAscXAlign.Inside:
                        case c_oAscXAlign.Outside:
                        case c_oAscXAlign.Left:
                        {
                            this.CalcX = 0;
                            break;
                        }

                        case c_oAscXAlign.Right:
                        {
                            this.CalcX = this.Page_W - this.W;
                            break;
                        }
                    }
                }
                else
                    this.CalcX = Value;

                break;
            }
        }

        return this.CalcX;
    },

    Calculate_Y : function(RelativeFrom, bAlign, Value)
    {
        // Вычисляем координату по Y
        switch(RelativeFrom)
        {
            case c_oAscVAnchor.Margin:
            {
                if ( true === bAlign )
                {
                    switch(Value)
                    {
                        case c_oAscYAlign.Bottom:
                        {
                            this.CalcY = this.Bottom_Margin - this.H;
                            break;
                        }
                        case c_oAscYAlign.Center:
                        {
                            this.CalcY = (this.Bottom_Margin + this.Top_Margin - this.H) / 2;
                            break;
                        }
                        case c_oAscYAlign.Inline:
                        case c_oAscYAlign.Inside:
                        case c_oAscYAlign.Outside:
                        case c_oAscYAlign.Top:
                        {
                            this.CalcY = this.Top_Margin;
                            break;
                        }
                    }
                }
                else
                    this.CalcY = this.Top_Margin + Value;

                break;
            }

            case c_oAscVAnchor.Page:
            {
                if ( true === bAlign )
                {
                    switch(Value)
                    {
                        case c_oAscYAlign.Bottom:
                        {
                            this.CalcY = this.Page_Bottom - this.H;
                            break;
                        }
                        case c_oAscYAlign.Center:
                        {
                            this.CalcY = (this.Page_Bottom - this.H) / 2;
                            break;
                        }
                        case c_oAscYAlign.Inline:
                        case c_oAscYAlign.Inside:
                        case c_oAscYAlign.Outside:
                        case c_oAscYAlign.Top:
                        {
                            this.CalcY = this.Page_Top;
                            break;
                        }
                    }
                }
                else
                    this.CalcY = this.Page_Top + Value;

                break;
            }

            case c_oAscVAnchor.Text:
            {
                if ( true === bAlign )
                {
                    // Word не дает делать прилегания в данном случае
                    this.CalcY = this.Y;
                }
                else
                    this.CalcY = this.Y + Value;

                break;
            }
        }

        return this.CalcY;
    },

    Correct_Values : function(X_min, Y_min, X_max, Y_max, AllowOverlap, OtherFlowTables, CurTable)
    {
        var W = this.W;
        var H = this.H;

        var CurX = this.CalcX;
        var CurY = this.CalcY;

        var bBreak = false;
        while ( true != bBreak )
        {
            bBreak = true;
            for ( var Index = 0; Index < OtherFlowTables.length; Index++ )
            {
                var FlowTable = OtherFlowTables[Index];

                if ( FlowTable.Table != CurTable && ( false === AllowOverlap || false === FlowTable.Table.Get_AllowOverlap() ) && ( CurX <= FlowTable.X + FlowTable.W && CurX + W >= FlowTable.X && CurY <= FlowTable.Y + FlowTable.H && CurY + H >= FlowTable.Y ) )
                {
                    /*
                     // Если убирается справа, размещаем справа от картинки
                     if ( FlowTable.X + FlowTable.W < X_max - W - 0.001 )
                     CurX = FlowTable.X + FlowTable.W + 0.001;
                     else
                     {
                     CurX = this.CalcX;
                     CurY = FlowTable.Y + FlowTable.H + 0.001;
                     }
                     */

                    // TODO: Пока у нас смещение по X плохо работает(смотри CTable.Shift), поэтому смещаем таблицу сразу по Y
                    CurY = FlowTable.Y + FlowTable.H + 0.001;

                    bBreak = false;
                }
            }
        }

        // TODO: Пока у нас смещение по X плохо работает(смотри CTable.Shift), поэтому смещаем таблицу сразу по Y
        /*
         // Скорректируем рассчитанную позицию, так чтобы объект не выходил за заданные пределы
         if ( CurX + W > X_max )
         CurX = X_max - W;

         if ( CurX < X_min )
         CurX = X_min;
         */

        // Скорректируем рассчитанную позицию, так чтобы объект не выходил за заданные пределы
        if ( CurY + H > Y_max )
            CurY = Y_max - H;

        if ( CurY < this.Y_min )
            CurY = this.Y_min;

        this.CalcY = CurY;
        this.CalcX = CurX;
    },

    // По значению CalcX получем Value
    Calculate_X_Value : function(RelativeFrom)
    {
        var Value = 0;

        switch(RelativeFrom)
        {
            case c_oAscHAnchor.Text:
            case c_oAscHAnchor.Margin:
            {
                Value = this.CalcX - this.Left_Margin;

                break;
            }

            case c_oAscHAnchor.Page:
            {
                Value = this.CalcX - this.X_min;

                break;
            }

            case c_oAscHAnchor.PageInternal:
            {
                Value = this.CalcX;
                break;
            }
        }

        return Value;
    },

    // По значению CalcY и заданному RelativeFrom получем Value
    Calculate_Y_Value : function(RelativeFrom)
    {
        var Value = 0;

        switch(RelativeFrom)
        {
            case c_oAscVAnchor.Margin:
            {
                Value = this.CalcY - this.Top_Margin;

                break;
            }

            case c_oAscVAnchor.Page:
            {
                Value = this.CalcY - this.Page_Top;

                break;
            }

            case c_oAscVAnchor.Text:
            {
                Value = this.CalcY - this.Y;

                break;
            }
        }

        return Value;
    }
};

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].CTable = CTable;
window['AscCommonWord'].type_Table = type_Table;