public final class TieConstants {

	/** The Constant COMPONENT_ID. */
	public static final String COMPONENT_ID = "websheettable";

	/** The Constant CONFIGURATION_SHEET. */
	public static final String CONFIGURATION_SHEET = "Configuration";

	/** The Constant ATTRS_WEBSHEETBEAN. */
	public static final String ATTRS_WEBSHEETBEAN = "webSheetBean";

	/** The Constant EXCEL_2003_TYPE. */
	public static final String EXCEL_2003_TYPE = "xls";

	/** The Constant EXCEL_2007_TYPE. */
	public static final String EXCEL_2007_TYPE = "xlsx";

	/** The Constant CONFIGURATION_SCHEMA_VERSION. */
	public static final String CONFIGURATION_SCHEMA_VERSION = "Version";

	/** The Constant CONFIGURATION_SCHEMA_TAB_NAME. */
	public static final String CONFIGURATION_SCHEMA_TAB_NAME = "Tab Name";

	/** The Constant CONFIGURATION_SCHEMA_SHEET_NAME. */
	public static final String CONFIGURATION_SCHEMA_SHEET_NAME = "Sheet Name";

	/** The Constant CONFIGURATION_SCHEMA_FORM_HEADER_RANGE. */
	public static final String CONFIGURATION_SCHEMA_FORM_HEADER_RANGE = "Form Header Range";

	/** The Constant CONFIGURATION_SCHEMA_FORM_BODY_RANGE. */
	public static final String CONFIGURATION_SCHEMA_FORM_BODY_RANGE = "Form Body Range";

	/** The Constant CONFIGURATION_SCHEMA_FORM_FOOTER_RANGE. */
	public static final String CONFIGURATION_SCHEMA_FORM_FOOTER_RANGE = "Form Footer Range";

	/** The Constant CONFIGURATION_SCHEMA_FORM_BODY_TYPE. */
	public static final String CONFIGURATION_SCHEMA_FORM_BODY_TYPE = "Form Body Type";

	/** The Constant CONFIGURATION_SCHEMA_ALLOW_ADD_ROW. */
	public static final String CONFIGURATION_SCHEMA_ALLOW_ADD_ROW = "Allow ADD/DELETE ROW";

	/** The Constant CONFIGURATION_SCHEMA_INIT_ROWS. */
	public static final String CONFIGURATION_SCHEMA_INIT_ROWS = "Initial Rows";

	/** The Constant CONFIGURATION_SCHEMA_FORM_PAGE_TYPE. */
	public static final String CONFIGURATION_SCHEMA_FORM_PAGE_TYPE = "Form Page Type";

	/** The Constant CONFIGURATION_SCHEMA_FORM_WIDTH. */
	public static final String CONFIGURATION_SCHEMA_FORM_WIDTH = "Form Width";

	/** The Constant CONFIGURATION_SCHEMA_MAX_ROWS_PER_PAGE. */
	public static final String CONFIGURATION_SCHEMA_MAX_ROWS_PER_PAGE = "Max Rows Per Page";

	/** The Constant CONFIGURATION_SCHEMA_SAVED_ROWS_BEFORE. */
	public static final String CONFIGURATION_SCHEMA_SAVED_ROWS_BEFORE = "Saved Rows Before Repeat";

	/** The Constant CONFIGURATION_SCHEMA_SAVED_ROWS_AFTER. */
	public static final String CONFIGURATION_SCHEMA_SAVED_ROWS_AFTER = "Saved Rows After Rpeat";

	/** The Constant CONFIGURATION_SCHEMA_TARGET_COLUMN_CELL. */
	public static final String CONFIGURATION_SCHEMA_TARGET_COLUMN_CELL = "Target Column/Cell";

	/** The Constant CONFIGURATION_SCHEMA_ATTRIBUTE_TYPE. */
	public static final String CONFIGURATION_SCHEMA_ATTRIBUTE_TYPE = "Attributes Type";

	/** The Constant CONFIGURATION_SCHEMA_ATTRIBUTE_VALUE. */
	public static final String CONFIGURATION_SCHEMA_ATTRIBUTE_VALUE = "Attributes Value";

	/** The Constant CONFIGURATION_SCHEMA_VALIDATION_ERROR_MSG. */
	public static final String CONFIGURATION_SCHEMA_VALIDATION_ERROR_MSG = "Validation Error Messages";

	/** The Constant CONFIGURATION_ATTR_CONTROL. */
	public static final String CONFIGURATION_ATTR_CONTROL = "Control";

	/** The Constant FORM_TYPE_FREE. */
	public static final String FORM_TYPE_FREE = "Free";

	/** The Constant FORM_TYPE_REPEAT. */
	public static final String FORM_TYPE_REPEAT = "Repeat";

	/** The Constant CELL_INPUT_TYPE_DOUBLE. */
	public static final String CELL_INPUT_TYPE_DOUBLE = "double";

	/** The Constant CELL_INPUT_TYPE_INTEGER. */
	public static final String CELL_INPUT_TYPE_INTEGER = "integer";

	/** The Constant CELL_INPUT_TYPE_PERCENTAGE. */
	public static final String CELL_INPUT_TYPE_PERCENTAGE = "percentage";

	/** The Constant CELL_INPUT_TYPE_DATE. */
	public static final String CELL_INPUT_TYPE_DATE = "date";

	/** The Constant CELL_INPUT_TYPE_TEXT. */
	public static final String CELL_INPUT_TYPE_TEXT = "text";

	/** The Constant CELL_INPUT_TYPE_TEXTAREA. */
	public static final String CELL_INPUT_TYPE_TEXTAREA = "textarea";

	/** The Constant COPY_SHEET_PREFIX. */
	public static final String COPY_SHEET_PREFIX = "cptieTemp_";

	/** The Constant EXCEL_SHEET_NAME_LIMIT. */
	public static final short EXCEL_SHEET_NAME_LIMIT = 31;
	/** method prefix. */
	/** command's prefix. */
	public static final String COMMAND_PREFIX = "tie:";
	/** form command. */
	public static final String COMMAND_FORM = "form";
	/** each command. */
	public static final String COMMAND_EACH = "each";
	/** true string. */
	public static final String TRUE_STRING = "true";
	/** false string. */
	public static final String FALSE_STRING = "false";
	/** attribute prefix. */
	public static final String ATTR_PREFIX = "(";
	/** attribute suffix. */
	public static final String ATTR_SUFFIX = ")";
	/** attribute's regex. */
	public static final String ATTR_REGEX = "\\s*\\w+\\s*=\\s*([\"|'])(?:(?!\\1).)*\\1";
	/** attribute's regex pattern. */
	public static final Pattern ATTR_REGEX_PATTERN = Pattern
			.compile(ATTR_REGEX);

	/** The Constant CELL_DATA_ROW. */
	public static final String CELL_DATA_ROW = "data-row";

	/** The Constant CELL_DATA_COLUMN. */
	public static final String CELL_DATA_COLUMN = "data-column";

	/** The Constant CELL_DATA_SYMBOL. */
	public static final String CELL_DATA_SYMBOL = "data-symbol";

	/** The Constant TIE_WEB_SHEET_MAX_ROWS. */
	public static final int TIE_WEB_SHEET_MAX_ROWS = 99999;

	/** The Constant EL_START. */
	public static final String EL_START = "#{";

	/** The Constant EL_START_BRACKET. */
	public static final char EL_START_BRACKET = '{';

	/** The Constant EL_END. */
	public static final char EL_END = '}';

	/** The Constant TAB_TYPE_NONE. */
	public static final String TAB_TYPE_NONE = "none";

	/** The Constant TAB_STYLE_VISIBLE. */
	public static final String TAB_STYLE_VISIBLE = "height: 530px;";

	/** The Constant TAB_STYLE_INVISIBLE. */
	public static final String TAB_STYLE_INVISIBLE = "height: 30px;";

	/** The Constant defaultMaxRowsPerPage. */
	public static final int DEFAULT_MAX_ROWS_PER_PAGE = 80;

	/** The Constant defaultTableWidthStyle. */
	public static final String DEFAULT_TABLE_WIDTH_STYLE = "width: 100%;";

	/** The Constant defaultLineNumberColumnWidth. */
	public static final int DEFAULT_LINENUMBER_COLUMN_WIDTH = 26;

	/** The Constant excel letter total numbers. */
	public static final int EXCEL_LETTER_NUMBERS = 26;

	/** The Constant defaultAddRowColumnWidth. */
	public static final int DEFAULT_ADDROW_COLUMN_WIDTH = 64;

	/** default basic stroke width. */
	public static final float DEFAULT_BASIC_STROKE = 0.1f;

	/** The Constant defaultLegentItemShapeWidth. */
	public static final int DEFAULT_LEGENT_ITEM_SHAPE_WIDTH = 8;

	/** The Constant defaultLegentItemShapeHeight. */
	public static final int DEFAULT_LEGENT_ITEM_SHAPE_HEIGHT = 8;

	/** The Constant defaultBarStyleItemMargin. */
	public static final float DEFAULT_BAR_STYLE_ITEM_MARGIN = 0.02f;

	/** The Constant defaultBarStyleForegroundAlpha. */
	public static final int DEFAULT_BARSTYLE_FOREGROUND_ALPHA = 1;

	/** The Constant eachCommandInvalidMsg. */
	public static final String EACH_COMMAND_INVALID_MSG = " is not a list collection, cannot support add/delete function.";

	/** The Constant defaultCommandPartLength. */
	public static final int DEFAULT_COMMAND_PART_LENGTH = 3;

	/** The Constant USER_FORMULA_PREFIX. */
	public static final String USER_FORMULA_PREFIX = "$[";

	/** The Constant USER_FORMULA_SUFFIX. */
	public static final String USER_FORMULA_SUFFIX = "]";

	/** The Constant max columns in sheet. = AML */
	public static final int MAX_COLUMNS_IN_SHEET = 1024;

	/** The Constant hiddenOriginRowNumber. = AML */
	public static final int HIDDEN_ORIGIN_ROW_NUMBER_COLUMN = 1025;

	/** The Constant hiddenFullNameColumn. = AMM */
	public static final int HIDDEN_FULL_NAME_COLUMN = 1026;

	/** The Constant hiddenSaveObjectsColumn. = AMN */
	public static final int HIDDEN_SAVE_OBJECTS_COLUMN = 1027;

	/** The Constant cellMapKeyChart. */
	public static final String CELL_MAP_KEY_CHART = "chart";

	/** The Constant cellMapKeyPicture. */
	public static final String CELL_MAP_KEY_PICTURE = "picture";

	/** The Constant cellMapKeyFormat. */
	public static final String CELL_MAP_KEY_FORMAT = "format";

	/** The Constant cellMapKeyPercent. */
	public static final String CELL_MAP_KEY_PERCENT = "percent";

	/** The Constant cellFormatPercentageSymbol. */
	public static final String CELL_FORMAT_PERCENTAGE_SYMBOL = "%";

	/** The Constant cellFormatPercentageValue. */
	public static final int CELL_FORMAT_PERCENTAGE_VALUE = 100;
	/** The Constant cellAddrPrefix. */
	public static final String CELL_ADDR_PRE_FIX = "$";
	/** The Constant rgb max. */
	public static final short RGB_MAX = 256;
	/** select item labels. */
	public static final String SELECT_ITEM_LABELS = "itemlabels";
	/** select item values. */
	public static final String SELECT_ITEM_VALUES = "itemvalues";
	/** default select item label. */
	public static final String DEFAULT_SELECT_ITEM_LABEL = "defaultlabel";
	/** default select item value. */
	public static final String DEFAULT_SELECT_ITEM_VALUE = "defaultvalue";
	/** widget calendar. */
	public static final String WIDGET_CALENDAR = "calendar";
	/** widget attribute pattern. */
	public static final String WIDGET_ATTR_PATTERN = "pattern";
	/** component attributes locale. */
	public static final String COMPONENT_ATTR_LOCALE = "locale";
	/** method regex. */
	public static final String METHOD_REGEX = "\\$+[^{$]+\\{.*\\}";
	/** method prefix. */
	public static final String METHOD_PREFIX = "${";
	/** The expression notation end. */
	public static final String METHOD_END = "}";
	/** method widget prefix. */
	public static final String METHOD_WIDGET_PREFIX = "$widget.";
	/** method validate prefix. */
	public static final String METHOD_VALIDATE_PREFIX = "$validate";
	/** The expression notation pattern. */
	public static final Pattern EXPRESSION_NOTATION_PATTERN = Pattern
			.compile("\\$\\{[^}]*}");
	/** The DEFAULT_HEADER_ROW_HEIGHT. */
	public static final float DEFAULT_HEADER_ROW_HEIGHT = 12;
	/** The NORMAL_COMMENT_KEY_IN_MAP. */
	public static final String NORMAL_COMMENT_KEY_IN_MAP = "$$";
	/** The SAVE_COMMENT_KEY_IN_MAP. */
	public static final String SAVE_COMMENT_KEY_IN_MAP = "$save";
	/** The VALIDATION_RULE_TAG. */
	public static final String VALIDATION_RULE_TAG = "rule";
	/** The VALIDATION_ERROR_MSG_TAG. */
	public static final String VALIDATION_ERROR_MSG_TAG = "error";
	/** SPLIT_SPACE_SEPERATE_ATTRS_REGX. */
	public static final String SPLIT_SPACE_SEPERATE_ATTRS_REGX = "\" (?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)";
	/** The Constant DEFALT_MSG_INVALID_INPUT. */
	public static final String DEFALT_MSG_INVALID_INPUT = "Invalid input";

	/** The Constant EACH_COMMAND_FULL_NAME_PREFIX. */
	public static final String EACH_COMMAND_FULL_NAME_PREFIX = "E.";

	/** The Constant FORM_COMMAND_FULL_NAME_PREFIX. */
	public static final String FORM_COMMAND_FULL_NAME_PREFIX = "F.";
	/** The Constant CELL_INVALID_STYLE. */
	public static final String CELL_INVALID_STYLE = "border-color: red;";
	/** The Constant TEXT_ALIGN_LEFT. */
	public static final String TEXT_ALIGN_LEFT = "text-align: left;";
	/** The Constant TEXT_ALIGN_RIGHT. */
	public static final String TEXT_ALIGN_RIGHT = "text-align: right;";
	/** The Constant TEXT_ALIGN_CENTER. */
	public static final String TEXT_ALIGN_CENTER = "text-align: center;";

	/** The Constant VERTICAL_ALIGN_TOP. */
	public static final String VERTICAL_ALIGN_TOP = "vertical-align: top;";
	/** The Constant VERTICAL_ALIGN_BOTTOM. */
	public static final String VERTICAL_ALIGN_BOTTOM = "vertical-align: bottom;";
	/** The Constant VERTICAL_ALIGN_CENTER. */
	public static final String VERTICAL_ALIGN_CENTER = "vertical-align: middle;";

	/** The Constant submit mode. */
	public static final String SUBMITMODE = "tieWebSheetSubmitMode";
	/** The Constant unSaved state. */
	public static final String UNSAVEDSTATE = "unSaved";
	/**
	 * hide constructor.
	 */
	private TieConstants() {
		// not called
	}

}
 public interface Command {

	/**
	 * Return command type.
	 * 
	 * @return command type name.
	 */
	String getCommandTypeName();

	/**
	 * Set command type.
	 * 
	 * @param pCommandTypeName
	 *            command type name.
	 */
	void setCommandTypeName(String pCommandTypeName);

	/**
	 * Constructor configRange if it's null. Always return an object for
	 * configRange.
	 * 
	 * @return ConfigRange object.
	 */
	ConfigRange getConfigRange();

	/**
	 * Set config range.
	 * 
	 * @param pConfigRange
	 *            config range.
	 */
	void setConfigRange(ConfigRange pConfigRange);

	/**
	 * Return parent command.
	 * 
	 * @return parent command.
	 */
	Boolean isParentFound();

	/**
	 * set parent found.
	 * 
	 * @param parentFound
	 *            true if parent found.
	 */
	void setParentFound(Boolean parentFound);

	/**
	 * command area length.
	 * 
	 * @return length.
	 */
	String getLength();

	/**
	 * Set command area length.
	 * 
	 * @param pLength
	 *            length.
	 */
	void setLength(String pLength);

	/**
	 * Get top row of command range.
	 * 
	 * @return int top row index.
	 */
	int getTopRow();

	/**
	 * Get last row of command range.
	 * 
	 * @return int last row index.
	 */

	int getLastRow();

	/**
	 * get left column index of the command range.
	 * 
	 * @return int left column index.
	 */
	int getLeftCol();

	/**
	 * get right column index of the command range.
	 * 
	 * @return int right column index.
	 */
	int getRightCol();

	/**
	 * the final length of command area.
	 * 
	 * @return final length.
	 */
	int getFinalLength();

	/**
	 * Set the final length.
	 * 
	 * @param populatedLength
	 *            final length.
	 */
	void setFinalLength(int populatedLength);

	/**
	 * Builds the at.
	 *
	 * @param fullName
	 *            full name.
	 * @param configBuildRef
	 *            configbuild reference.
	 * @param atRow
	 *            populate at the row.
	 * @param context
	 *            context map.
	 * @param currentRowsMappingList
	 *            rowsMapping for formula.
	 * @return build area length.
	 */
	int buildAt(String fullName, ConfigBuildRef configBuildRef, int atRow,
			Map<String, Object> context,
			List<RowsMapping> currentRowsMappingList);
	/**
	 * get command name.
	 * @return command name.
	 */
	String getCommandName();
	
	/**
	 * Recover.
	 *
	 * @param sheet
	 *            the sheet
	 */
	void recover(Sheet sheet);

} public class ConfigBuildRef {

	/** workbook wrapper. */
	private XSSFEvaluationWorkbook wbWrapper;
	/** sheet. */
	private Sheet sheet;
	/** list of row need watched. */
	private List<Integer> watchList;
	/** expression engine. */
	private ExpressionEngine engine;
	/** cell helper. */
	private CellHelper cellHelper;
	/** cell attributes map. */
	private CellAttributesMap cellAttributesMap;
	/** final comment map. */
	private Map<Cell, String> finalCommentMap;
	/** body allow add. */
	private boolean bodyAllowAdd = false;
	/** true if in addMOde. */
	private boolean addMode = false;
	/** insert position. */
	private int insertPosition = -1;

	/**
	 * Saved configRange attributes for each full name. String : full name.
	 * ConfigRangeAttrs : include range (top, bottom) and rows mapping.
	 */
	private NavigableMap<String, ConfigRangeAttrs> shiftMap;

	/**
	 * Saved formula cells. include original formula and rows mapping for this
	 * cell.
	 */
	private Map<Cell, String> cachedCells;

	/**
	 * used for cache origin config range tree.
	 */
	private ConfigRange originConfigRange;

	/**
	 * used for originConfigRange to finding command through full name. key
	 * (String) - command name. i.e. F.deparments or E.department value
	 * (Command) - configuration command.
	 */
	private Map<String, Command> commandIndexMap = new HashMap<>();
	/**
	 * used for save the object for create new one. key (String) - var name.
	 * value (String) - object class name.
	 */
	private Map<String, String> collectionObjNameMap = new HashMap<>();

	/**
	 * constructor.
	 * 
	 * @param pWbWrapper
	 *            workbook wrapper.
	 * @param pSheet
	 *            sheet.
	 * @param pEngine
	 *            expression engine.
	 * @param pCellHelper
	 *            cellhelper.
	 * @param pCachedCells
	 *            cached cells.
	 * @param pCellAttributesMap
	 *            cell attributes map.
	 * @param pFinalCommentMap
	 *            final comment map.
	 */
	public ConfigBuildRef(final XSSFEvaluationWorkbook pWbWrapper,
			final Sheet pSheet, final ExpressionEngine pEngine,
			final CellHelper pCellHelper,
			final Map<Cell, String> pCachedCells,
			final CellAttributesMap pCellAttributesMap,
			final Map<Cell, String> pFinalCommentMap) {
		super();
		this.wbWrapper = pWbWrapper;
		this.sheet = pSheet;
		this.engine = pEngine;
		this.cellHelper = pCellHelper;
		this.cachedCells = pCachedCells;
		this.cellAttributesMap = pCellAttributesMap;
		this.finalCommentMap = pFinalCommentMap;
		this.shiftMap = new TreeMap<>();
	}

	/**
	 * Gets the watch list.
	 *
	 * @return the watch list
	 */
	public final List<Integer> getWatchList() {
		return watchList;
	}

	/**
	 * Sets the watch list.
	 *
	 * @param pwatchList
	 *            the new watch list
	 */
	public final void setWatchList(final List<Integer> pwatchList) {
		this.watchList = pwatchList;
	}

	/**
	 * Gets the wb wrapper.
	 *
	 * @return the wb wrapper
	 */
	public final XSSFEvaluationWorkbook getWbWrapper() {
		return wbWrapper;
	}

	/**
	 * Gets the sheet.
	 *
	 * @return the sheet
	 */
	public final Sheet getSheet() {
		return sheet;
	}

	/**
	 * Gets the engine.
	 *
	 * @return the engine
	 */
	public final ExpressionEngine getEngine() {
		return engine;
	}

	/**
	 * Gets the cell helper.
	 *
	 * @return the cell helper
	 */
	public final CellHelper getCellHelper() {
		return cellHelper;
	}

	/**
	 * Gets the cached cells.
	 *
	 * @return the cached cells
	 */
	public final Map<Cell, String> getCachedCells() {
		return cachedCells;
	}

	/**
	 * Put shift attrs.
	 *
	 * @param fullName
	 *            the full name
	 * @param attrs
	 *            the attrs
	 * @param unitRowsMapping
	 *            the unit rows mapping
	 */
	public final void putShiftAttrs(final String fullName,
			final ConfigRangeAttrs attrs,
			final RowsMapping unitRowsMapping) {
		attrs.setUnitRowsMapping(unitRowsMapping);
		this.shiftMap.put(fullName, attrs);
	}

	/**
	 * Gets the shift map.
	 *
	 * @return the shift map
	 */
	public final NavigableMap<String, ConfigRangeAttrs> getShiftMap() {
		return shiftMap;
	}

	/**
	 * Sets the shift map.
	 *
	 * @param pshiftMap
	 *            the shift map
	 */
	public final void setShiftMap(
			final NavigableMap<String, ConfigRangeAttrs> pshiftMap) {
		this.shiftMap = pshiftMap;
	}

	/**
	 * Checks if is body allow add.
	 *
	 * @return true, if is body allow add
	 */
	public final boolean isBodyAllowAdd() {
		return bodyAllowAdd;
	}

	/**
	 * Sets the body allow add.
	 *
	 * @param pbodyAllowAdd
	 *            the new body allow add
	 */
	public final void setBodyAllowAdd(final boolean pbodyAllowAdd) {
		this.bodyAllowAdd = pbodyAllowAdd;
	}

	/**
	 * Gets the origin config range.
	 *
	 * @return the origin config range
	 */
	public final ConfigRange getOriginConfigRange() {
		return originConfigRange;
	}

	/**
	 * Sets the origin config range.
	 *
	 * @param poriginConfigRange
	 *            the new origin config range
	 */
	public final void setOriginConfigRange(
			final ConfigRange poriginConfigRange) {
		this.originConfigRange = poriginConfigRange;
	}

	/**
	 * Gets the command index map.
	 *
	 * @return the command index map
	 */
	public final Map<String, Command> getCommandIndexMap() {
		return commandIndexMap;
	}

	/**
	 * Sets the command index map.
	 *
	 * @param pcommandIndexMap
	 *            the command index map
	 */
	public final void setCommandIndexMap(
			final Map<String, Command> pcommandIndexMap) {
		this.commandIndexMap = pcommandIndexMap;
	}

	/**
	 * Checks if is adds the mode.
	 *
	 * @return true, if is adds the mode
	 */
	public final boolean isAddMode() {
		return addMode;
	}

	/**
	 * Sets the adds the mode.
	 *
	 * @param paddMode
	 *            the new adds the mode
	 */
	public final void setAddMode(final boolean paddMode) {
		this.addMode = paddMode;
	}

	/**
	 * Gets the collection obj name map.
	 *
	 * @return the collection obj name map
	 */
	public final Map<String, String> getCollectionObjNameMap() {
		return collectionObjNameMap;
	}

	/**
	 * Sets the collection obj name map.
	 *
	 * @param pcollectionObjNameMap
	 *            the collection obj name map
	 */
	public final void setCollectionObjNameMap(
			final Map<String, String> pcollectionObjNameMap) {
		this.collectionObjNameMap = pcollectionObjNameMap;
	}

	/**
	 * Gets the insert position.
	 *
	 * @return the insert position
	 */
	public final int getInsertPosition() {
		return insertPosition;
	}

	/**
	 * Sets the insert position.
	 *
	 * @param pinsertPosition
	 *            the new insert position
	 */
	public final void setInsertPosition(final int pinsertPosition) {
		this.insertPosition = pinsertPosition;
	}

	/**
	 * Gets the cell attributes map.
	 *
	 * @return the cell attributes map
	 */
	public final CellAttributesMap getCellAttributesMap() {
		return cellAttributesMap;
	}

	/**
	 * Gets the final comment map.
	 *
	 * @return the final comment map
	 */
	public final Map<Cell, String> getFinalCommentMap() {
		return finalCommentMap;
	}

}
 public class ConfigRange implements Serializable {

	/**
	 * serialid.
	 */
	private static final long serialVersionUID = 1L;

	/** logger. */
	private static final Logger LOG = Logger
			.getLogger(ConfigRange.class.getName());

	/** The attrs. */
	private ConfigRangeAttrs attrs = new ConfigRangeAttrs(false);

	/** command list. */
	private List<ConfigCommand> commandList;

	/**
	 * Instantiates a new config range.
	 */
	public ConfigRange() {
		super();
	}

	/**
	 * Copy constructor.
	 *
	 * @param source
	 *            the source
	 */
	public ConfigRange(final ConfigRange source) {
		this.attrs.setFirstRowRef(source.attrs.getFirstRowRef());
		this.attrs.setFirstRowAddr(source.attrs.getFirstRowAddr());
		this.attrs.setLastRowPlusRef(source.attrs.getLastRowPlusRef());
		this.attrs.setLastRowPlusAddr(source.attrs.getLastRowPlusAddr());
		this.attrs.setLastCellCreated(source.attrs.isLastCellCreated());

		if (source.commandList != null) {
			this.commandList = this.getCommandList();
			for (ConfigCommand sourceCommand : source.commandList) {
				Object newCommand = null;
				if (sourceCommand instanceof FormCommand) {
					newCommand = new FormCommand(
							(FormCommand) sourceCommand);
				} else {
					newCommand = new EachCommand(
							(EachCommand) sourceCommand);
				}
				this.commandList.add((ConfigCommand) newCommand);
			}
		}

	}

	/**
	 * Gets the attrs.
	 *
	 * @return the attrs
	 */
	public final ConfigRangeAttrs getAttrs() {
		return attrs;
	}

	/**
	 * Shift row ref.
	 *
	 * @param sheet
	 *            the sheet
	 * @param shiftnum
	 *            the shiftnum
	 */
	public final void shiftRowRef(final Sheet sheet, final int shiftnum) {
		try {
			this.setFirstRowRef(sheet
					.getRow(attrs.getFirstRowAddr().getRow() + shiftnum)
					.getCell(attrs.getFirstRowAddr().getColumn(),
							MissingCellPolicy.CREATE_NULL_AS_BLANK),
					false);
			this.setLastRowPlusRef(sheet,
					attrs.getLastRowPlusAddr().getColumn(),
					attrs.getLastRowPlusAddr().getRow() + shiftnum - 1,
					false);

			if (commandList != null) {
				for (ConfigCommand command : commandList) {
					command.shiftRowRef(sheet, shiftnum);
				}
			}

		} catch (Exception ex) {
			LOG.log(Level.SEVERE,
					"shiftRowRef error =" + ex.getLocalizedMessage(), ex);
		}
	}

	/**
	 * Gets the first row ref.
	 *
	 * @return the first row ref
	 */
	public final Cell getFirstRowRef() {
		return attrs.getFirstRowRef();
	}

	/**
	 * set first cell also set static relative address firstCellAddress.
	 * 
	 * @param pFirstRowRef
	 *            first cell.
	 * @param alsoCreateAddr
	 *            whether need create cell address.
	 */
	public final void setFirstRowRef(final Cell pFirstRowRef,
			final boolean alsoCreateAddr) {
		this.attrs.setFirstRowRef(pFirstRowRef);
		if (alsoCreateAddr) {
			this.setFirstRowAddr(new SerialCellAddress(pFirstRowRef));
		}
	}

	/**
	 * Gets the last row plus ref.
	 *
	 * @return the last row plus ref
	 */
	public final Cell getLastRowPlusRef() {
		return attrs.getLastRowPlusRef();
	}

	/**
	 * set last cell also set static relative address lastCellAddress.
	 * 
	 * @param sheet
	 *            sheet.
	 * @param rightCol
	 *            rightColumn.
	 * @param lastRow
	 *            lastRow.
	 * @param alsoSetAddr
	 *            whether need create cell address.
	 */
	public final void setLastRowPlusRef(final Sheet sheet,
			final int rightCol, final int lastRow,
			final boolean alsoSetAddr) {

		if ((lastRow >= 0) && (sheet != null) && (rightCol >= 0)) {
			Row row = sheet.getRow(lastRow + 1);
			if (row == null) {
				row = sheet.createRow(lastRow + 1);
			}
			Cell cell = row.getCell(rightCol);
			if (cell == null) {
				cell = row.getCell(rightCol,
						MissingCellPolicy.CREATE_NULL_AS_BLANK);
				this.attrs.setLastCellCreated(true);
			} else {
				this.attrs.setLastCellCreated(false);
			}
			this.attrs.setLastRowPlusRef(cell);
			if (alsoSetAddr) {
				this.setLastRowPlusAddr(new SerialCellAddress(cell));
			}
		} else {
			this.attrs.setLastRowPlusRef(null);
			if (alsoSetAddr) {
				this.attrs.setLastRowPlusAddr(null);
			}
		}
	}

	/**
	 * Gets the first row addr.
	 *
	 * @return the first row addr
	 */
	public final SerialCellAddress getFirstRowAddr() {
		return attrs.getFirstRowAddr();
	}

	/**
	 * Sets the first row addr.
	 *
	 * @param pFirstRowAddr
	 *            the new first row addr
	 */
	public final void setFirstRowAddr(
			final SerialCellAddress pFirstRowAddr) {
		this.attrs.setFirstRowAddr(pFirstRowAddr);
	}

	/**
	 * Gets the last row plus addr.
	 *
	 * @return the last row plus addr
	 */
	public final SerialCellAddress getLastRowPlusAddr() {
		return attrs.getLastRowPlusAddr();
	}

	/**
	 * Sets the last row plus addr.
	 *
	 * @param pLastRowPlusAddr
	 *            the new last row plus addr
	 */
	public final void setLastRowPlusAddr(
			final SerialCellAddress pLastRowPlusAddr) {
		this.attrs.setLastRowPlusAddr(pLastRowPlusAddr);
	}

	/**
	 * command list.
	 * 
	 * @return command list.
	 */
	public final List<ConfigCommand> getCommandList() {
		if (this.commandList == null) {
			this.commandList = new ArrayList<>();
		}
		return this.commandList;
	}

	/**
	 * Sets the command list.
	 *
	 * @param pCommandList
	 *            the new command list
	 */
	public final void setCommandList(
			final List<ConfigCommand> pCommandList) {
		this.commandList = pCommandList;
	}

	/**
	 * Checks if is last cell created.
	 *
	 * @return true, if is last cell created
	 */
	public final boolean isLastCellCreated() {
		return attrs.isLastCellCreated();
	}

	/**
	 * add command to the list.
	 * 
	 * @param configCommand
	 *            .
	 * @return command list.
	 */
	public final List<ConfigCommand> addCommand(
			final ConfigCommand configCommand) {
		this.getCommandList().add(configCommand);
		return this.getCommandList();
	}

	/**
	 * build the config range at specified point (start row). context include
	 * the data objects for evaluation. build sequence is inside-out. e.g. first
	 * build all the command area the range included. each command will hold the
	 * final length after data populated. then buildCells build all cells in the
	 * range except those commands. and update the formulas.
	 *
	 * @param fullName
	 *            the full name
	 * @param configBuildRef
	 *            the config build ref
	 * @param atRow
	 *            the at row
	 * @param context
	 *            context map.
	 * @param currentRowsMappingList
	 *            the current rows mapping list
	 * @return final length.
	 */
	public final int buildAt(final String fullName,
			final ConfigBuildRef configBuildRef, final int atRow,
			final Map<String, Object> context,
			final List<RowsMapping> currentRowsMappingList) {

		if (commandList != null) {
			for (int i = 0; i < commandList.size(); i++) {
				Command command = commandList.get(i);
				command.setFinalLength(0);
				int populatedLength = command.buildAt(fullName,
						configBuildRef,
						command.getConfigRange().getFirstRowRef()
								.getRowIndex(),
						context, currentRowsMappingList);
				command.setFinalLength(populatedLength);
			}
		}

		buildCells(fullName, configBuildRef, atRow, context,
				currentRowsMappingList);

		return this.getLastRowPlusRef().getRowIndex()
				- this.getFirstRowRef().getRowIndex();

	}

	/**
	 * Index command range.
	 *
	 * @param indexMap
	 *            the index map
	 */
	public final void indexCommandRange(
			final Map<String, Command> indexMap) {
		CommandUtility.indexCommandRange(this, indexMap);
	}

	/**
	 * Build all the static cells in the range (exclude command areas).
	 *
	 * @param fullName
	 *            the full name
	 * @param configBuildRef
	 *            the config build ref
	 * @param atRow
	 *            start row.
	 * @param context
	 *            context.
	 * @param rowsMappingList
	 *            the rows mapping list
	 */
	private void buildCells(final String fullName,
			final ConfigBuildRef configBuildRef, final int atRow,
			final Map<String, Object> context,
			final List<RowsMapping> rowsMappingList) {

		if ((context == null) || context.isEmpty()) {
			// no need to evaluate as there's no data object.
			return;
		}

		// keep rowsMappingList as current as no change
		// allRowsMappingList = child + current

		List<RowsMapping> allRowsMappingList = ConfigurationUtility
				.findChildRowsMappingFromShiftMap(fullName,
						configBuildRef.getShiftMap());
		allRowsMappingList.addAll(rowsMappingList);

		int lastRowPlus = this.getLastRowPlusRef().getRowIndex();
		ShiftFormulaRef shiftFormulaRef = new ShiftFormulaRef(
				configBuildRef.getWatchList(), allRowsMappingList);
		for (int i = atRow; i < lastRowPlus; i++) {
			buildCellsForRow(configBuildRef.getSheet().getRow(i), fullName,
					context, configBuildRef, shiftFormulaRef);
		}
	}

	/**
	 * Builds the cells for row.
	 *
	 * @param row
	 *            the row
	 * @param fullName
	 *            the full name
	 * @param context
	 *            the context
	 * @param configBuildRef
	 *            the config build ref
	 * @param shiftFormulaRef
	 *            the shift formula ref
	 */
	private void buildCellsForRow(final Row row, final String fullName,
			final Map<String, Object> context,
			final ConfigBuildRef configBuildRef,
			ShiftFormulaRef shiftFormulaRef) {
		if ((row == null)
				|| !ConfigurationUtility.isStaticRowRef(this, row)) {
			return;
		}
		for (Cell cell : row) {
			buildSingleCell(cell, context, configBuildRef, shiftFormulaRef);
		}
		ConfigurationUtility.setFullNameInHiddenColumn(row, fullName);
	}

	/**
	 * Builds the single cell.
	 *
	 * @param cell
	 *            the cell
	 * @param context
	 *            the context
	 * @param configBuildRef
	 *            the config build ref
	 * @param shiftFormulaRef
	 *            the shift formula ref
	 */
	private void buildSingleCell(final Cell cell,
			final Map<String, Object> context,
			final ConfigBuildRef configBuildRef,
			final ShiftFormulaRef shiftFormulaRef) {
		try {
			CommandUtility.evaluate(context, cell,
					configBuildRef.getEngine());
			if (cell.getCellTypeEnum() == CellType.FORMULA) {
				// rebuild formula if necessary for dynamic row
				String originFormula = cell.getCellFormula();
				shiftFormulaRef.setFormulaChanged(0);
				ConfigurationUtility.buildCellFormulaForShiftedRows(
						configBuildRef.getSheet(),
						configBuildRef.getWbWrapper(), shiftFormulaRef,
						cell, cell.getCellFormula());
				if (shiftFormulaRef.getFormulaChanged() > 0) {
					configBuildRef.getCachedCells().put(cell,
							originFormula);
				}
			}

		} catch (Exception ex) {
			LOG.log(Level.SEVERE,
					"build cell ( row = " + cell.getRowIndex()
							+ " column = " + cell.getColumnIndex()
							+ " error = " + ex.getLocalizedMessage(),
					ex);
		}
	}

	/**
	 * recover by using it's address.
	 * 
	 * @param sheet
	 *            sheet.
	 */
	public final void recover(final Sheet sheet) {

		this.getAttrs().recover(sheet);
		if (this.commandList != null) {
			for (ConfigCommand command : this.commandList) {
				command.recover(sheet);
			}
		}

	}

	/**
	 * Obtain a human readable representation.
	 * 
	 * @return String Human readable label
	 */
	@Override
	public final String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("{");
		sb.append("FirstRowRef = " + this.getFirstRowRef());
		sb.append(",");
		sb.append("FirstRowAddr = " + this.getFirstRowAddr());
		sb.append(",");
		sb.append("LastRowPlusRef = " + this.getLastRowPlusRef());
		sb.append(",");
		sb.append("LastRowPlusAddr = " + this.getLastRowPlusAddr());
		sb.append(",");
		sb.append("LastCellCreated = " + this.isLastCellCreated());
		if (this.commandList != null) {
			sb.append("[");
			for (ConfigCommand command : this.commandList) {
				sb.append("command = " + command);
				sb.append(",");
			}
			sb.append("]");
		}
		sb.append("}");
		return sb.toString();
	}

}
 public class ConfigRangeAttrs implements Serializable {
	/**
	 * serialVersionUID.
	 */
	private static final long serialVersionUID = 1L;

	/** first cell. */
	private SerialCell serialFirstRowRef;
	/** last cell. */
	private SerialCell serialLastRowPlusRef;
	/** first cell address. This used to calculate relative address. */
	private SerialCellAddress firstRowAddr;
	/** last cell address. This used to calculate relative address. */
	private SerialCellAddress lastRowPlusAddr;
	/** if true then the lastCell is created instead of exist cell. */
	private boolean lastCellCreated;

	/** The final length. */
	private int finalLength = 0;

	/** The allow add. */
	private boolean allowAdd = false;

	/** The unit rows mapping. */
	private RowsMapping unitRowsMapping = null;

	/**
	 * Instantiates a new config range attrs.
	 *
	 * @param plastCellCreated
	 *            the last cell created
	 */
	public ConfigRangeAttrs(final boolean plastCellCreated) {
		this.lastCellCreated = plastCellCreated;
	}

	/**
	 * Gets the first row ref.
	 *
	 * @return the first row ref
	 */
	public final Cell getFirstRowRef() {
		return serialFirstRowRef.getCell();
	}

	/**
	 * Gets the serial first row ref.
	 *
	 * @return the serialFirstRowRef
	 */
	public final SerialCell getSerialFirstRowRef() {
		if (this.serialFirstRowRef == null) {
			this.serialFirstRowRef = new SerialCell();
		}
		return serialFirstRowRef;
	}

	/**
	 * Sets the first row ref.
	 *
	 * @param pfirstRowRef
	 *            the new first row ref
	 */
	public final void setFirstRowRef(final Cell pfirstRowRef) {
		this.getSerialFirstRowRef().setCell(pfirstRowRef);
	}

	/**
	 * Gets the last row plus ref.
	 *
	 * @return the last row plus ref
	 */
	public final Cell getLastRowPlusRef() {
		return serialLastRowPlusRef.getCell();
	}

	/**
	 * Gets the serial last row plus ref.
	 *
	 * @return the serialLastRowPlusRef
	 */
	public final SerialCell getSerialLastRowPlusRef() {
		if (this.serialLastRowPlusRef == null) {
			this.serialLastRowPlusRef = new SerialCell();
		}
		return serialLastRowPlusRef;
	}

	/**
	 * Sets the last row plus ref.
	 *
	 * @param plastRowPlusRef
	 *            the new last row plus ref
	 */
	public final void setLastRowPlusRef(final Cell plastRowPlusRef) {
		this.getSerialLastRowPlusRef().setCell(plastRowPlusRef);
	}

	/**
	 * Gets the first row addr.
	 *
	 * @return the first row addr
	 */
	public final SerialCellAddress getFirstRowAddr() {
		return firstRowAddr;
	}

	/**
	 * Sets the first row addr.
	 *
	 * @param pfirstRowAddr
	 *            the new first row addr
	 */
	public final void setFirstRowAddr(
			final SerialCellAddress pfirstRowAddr) {
		this.firstRowAddr = pfirstRowAddr;
	}

	/**
	 * Gets the last row plus addr.
	 *
	 * @return the last row plus addr
	 */
	public final SerialCellAddress getLastRowPlusAddr() {
		return lastRowPlusAddr;
	}

	/**
	 * Sets the last row plus addr.
	 *
	 * @param plastRowPlusAddr
	 *            the new last row plus addr
	 */
	public final void setLastRowPlusAddr(
			final SerialCellAddress plastRowPlusAddr) {
		this.lastRowPlusAddr = plastRowPlusAddr;
	}

	/**
	 * Checks if is last cell created.
	 *
	 * @return true, if is last cell created
	 */
	public final boolean isLastCellCreated() {
		return lastCellCreated;
	}

	/**
	 * Sets the last cell created.
	 *
	 * @param plastCellCreated
	 *            the new last cell created
	 */
	public final void setLastCellCreated(final boolean plastCellCreated) {
		this.lastCellCreated = plastCellCreated;
	}

	/**
	 * Gets the final length.
	 *
	 * @return the final length
	 */
	public final int getFinalLength() {
		return finalLength;
	}

	/**
	 * Sets the final length.
	 *
	 * @param pfinalLength
	 *            the new final length
	 */
	public final void setFinalLength(final int pfinalLength) {
		this.finalLength = pfinalLength;
	}

	/**
	 * Checks if is allow add.
	 *
	 * @return true, if is allow add
	 */
	public final boolean isAllowAdd() {
		return allowAdd;
	}

	/**
	 * Sets the allow add.
	 *
	 * @param pallowAdd
	 *            the new allow add
	 */
	public final void setAllowAdd(final boolean pallowAdd) {
		this.allowAdd = pallowAdd;
	}

	/**
	 * Gets the unit rows mapping.
	 *
	 * @return the unit rows mapping
	 */
	public final RowsMapping getUnitRowsMapping() {
		return unitRowsMapping;
	}

	/**
	 * Sets the unit rows mapping.
	 *
	 * @param punitRowsMapping
	 *            the new unit rows mapping
	 */
	public final void setUnitRowsMapping(
			final RowsMapping punitRowsMapping) {
		this.unitRowsMapping = punitRowsMapping;
	}

	/**
	 * recover by using it's address.
	 * 
	 * @param sheet
	 *            sheet.
	 */
	public final void recover(final Sheet sheet) {

		this.getSerialFirstRowRef().recover(sheet);
		this.getSerialLastRowPlusRef().recover(sheet);
		if (this.getUnitRowsMapping() != null) {
			this.getUnitRowsMapping().recover(sheet);
		}
	}

	/**
	 * Gets the first row index.
	 *
	 * @return the first row index
	 */
	public final int getFirstRowIndex() {

		Cell cell = this.getFirstRowRef();
		if (cell != null) {
			return cell.getRowIndex();
		}
		return -1;
	}

	/**
	 * Gets the last row index.
	 *
	 * @return the last row index
	 */
	public final int getLastRowIndex() {

		Cell cell = this.getLastRowPlusRef();
		if (cell != null) {
			return cell.getRowIndex() - 1;
		}
		return -1;
	}

} public class ExpressionEngine {
	/** expression. */
	private Expression jExpression;

	/**
	 * context. private JexlContext jContext;
	 */
	/** jexlEngine local map. */
	private static final ThreadLocal<JexlEngine> 
	JEXL_LOCAL = new ThreadLocal<JexlEngine>() {
		@Override
		protected JexlEngine initialValue() {
			return new JexlEngine();
		}
	};
	/** jexpmap local map. */
	private static final ThreadLocal<Map<String, Expression>> 
	JEXL_MAP_LOCAL = new ThreadLocal<Map<String, Expression>>() {
		@Override
		protected Map<String, Expression> initialValue() {
			return new HashMap<>();
		}
	};

	/**
	 * empty context used for evaluate single script.
	 */
	private static final Map<String, Object> 
	EMPTY_CONTEXT = new HashMap<>();

	/**
	 * constructor.
	 * 
	 * @param pExpression
	 *            expression.
	 */
	public ExpressionEngine(final String pExpression) {
		JexlEngine jexl = JEXL_LOCAL.get();
		jExpression = jexl.createExpression(pExpression);
	}



	/**
	 * constructor.
	 */
	public ExpressionEngine() {
		super();
	}

	/**
	 * Evaluate the expression.
	 *
	 * @param expression
	 *            string input expression.
	 * @return evaluated object.
	 */
	public final Object evaluate(final String expression) {
		return evaluate(expression, EMPTY_CONTEXT);
	}

	/**
	 * Evaluate the expression.
	 * 
	 * @param expression
	 *            string input expression.
	 * @param context
	 *            context map.
	 * @return evaluated object.
	 */
	public final Object evaluate(final String expression,
			final Map<String, Object> context) {
		JexlContext jexlContext = new MapContext(context);
		try {
			JexlEngine jexl = JEXL_LOCAL.get();
			Map<String, Expression> expMap = JEXL_MAP_LOCAL.get();
			Expression jexlExpression = expMap.get(expression);
			if (jexlExpression == null) {
				jexlExpression = jexl.createExpression(expression);
				expMap.put(expression, jexlExpression);
			}
			return jexlExpression.evaluate(jexlContext);
		} catch (Exception e) {
			throw new EvaluationException(e);
		}
	}

	/**
	 * evaluate from giving context.
	 * 
	 * @param context
	 *            context.
	 * @return object evaluated.
	 */
	public final Object evaluate(final Map<String, Object> context) {
		JexlContext jexlContext = new MapContext(context);
		try {
			return jExpression.evaluate(jexlContext);
		} catch (Exception e) {
			throw new EvaluationException(
					"An error occurred when evaluating expression "
							+ jExpression.getExpression(), e);
		}
	}

	/**
	 * get jexpression.
	 * 
	 * @return jexlexpression.
	 */

	public final Expression getJexlExpression() {
		return jExpression;
	}

	/**
	 * get local exl engine.
	 * 
	 * @return jexlengine.
	 */
	public final JexlEngine getJexlEngine() {
		return JEXL_LOCAL.get();
	}

}
 public class RowsMapping implements Serializable {

	/**
	 * serialVersionUID.
	 */
	private static final long serialVersionUID = 1L;
	/** The rows map. */
	private Map<Integer, List<SerialRow>> rowsMap = new HashMap<>();

	/**
	 * Instantiates a new rows mapping.
	 */
	public RowsMapping() {
		super();
	}

	/**
	 * Copy constructor.
	 *
	 * @param source
	 *            the source
	 */
	public RowsMapping(final RowsMapping source) {
		this.rowsMap.putAll(source.getRowsMap());
	}

	/**
	 * Gets the rows map.
	 *
	 * @return the rows map
	 */
	public final Map<Integer, List<SerialRow>> getRowsMap() {
		return rowsMap;
	}

	/**
	 * Adds the row.
	 *
	 * @param sourceRowNum
	 *            the source row num
	 * @param targetRow
	 *            the target row
	 */
	public final void addRow(final Integer sourceRowNum,
			final Row targetRow) {
		List<SerialRow> mapRowList = rowsMap.get(sourceRowNum);
		if (mapRowList == null) {
			mapRowList = new ArrayList<>();
		}
		SerialRow serialTarget = new SerialRow(targetRow, -1);
		if (!mapRowList.contains(serialTarget)) {
			mapRowList.add(serialTarget);
			rowsMap.put(sourceRowNum, mapRowList);
		}
	}

	/**
	 * Removes the row.
	 *
	 * @param sourceRowNum
	 *            the source row num
	 * @param targetRow
	 *            the target row
	 */
	public final void removeRow(final Integer sourceRowNum,
			final Row targetRow) {
		List<SerialRow> mapRowList = rowsMap.get(sourceRowNum);
		if (mapRowList != null) {
			mapRowList.remove(new SerialRow(targetRow, -1));
			rowsMap.put(sourceRowNum, mapRowList);
		}
	}

	/**
	 * Gets the.
	 *
	 * @param sourceRowNum
	 *            the source row num
	 * @return the list
	 */
	public final List<SerialRow> get(final Integer sourceRowNum) {
		return rowsMap.get(sourceRowNum);
	}

	/**
	 * Merge map.
	 *
	 * @param addMap
	 *            the add map
	 */
	public final void mergeMap(final RowsMapping addMap) {
		Map<Integer, List<SerialRow>> map = addMap.getRowsMap();
		for (Map.Entry<Integer, List<SerialRow>> entry : map.entrySet()) {
			List<SerialRow> entryRowList = entry.getValue();
			if ((entryRowList != null) && (!entryRowList.isEmpty())) {
				for (SerialRow row : entryRowList) {
					this.addRow(entry.getKey(), row.getRow());
				}
			}
		}
	}

	
	/**
	 * recover rows mapping by using it's address.
	 * 
	 * @param sheet
	 *            sheet.
	 */
	public final void recover(final Sheet sheet) {

		for (Map.Entry<Integer, List<SerialRow>> entry : this.getRowsMap()
				.entrySet()) {
			List<SerialRow> listRow = entry.getValue();
			for (SerialRow serialRow : listRow) {
				serialRow.recover(sheet);
			}
		}	

	}
	
	
	/**
	 * Obtain a human readable representation.
	 * 
	 * @return String Human readable label
	 */
	@Override
	public final String toString() {

		StringBuilder sb = new StringBuilder();
		sb.append("{");
		for (Map.Entry<Integer, List<SerialRow>> entry : this.getRowsMap()
				.entrySet()) {
			sb.append(entry.getKey() + "=[");
			for (SerialRow row : entry.getValue()) {
				sb.append(row.getRow().getRowNum() + ",");
			}
			sb.append("], ");
		}
		sb.append("}");
		return sb.toString();
	}

}
 public class ShiftFormulaRef {

	/** The watch list. */
	private List<Integer> watchList;

	/** The current rows mapping list. */
	private List<RowsMapping> currentRowsMappingList;

	/** The formula changed. */
	private int formulaChanged = 0;
	
	/**
	 * Instantiates a new shift formula ref.
	 *
	 * @param pwatchList
	 *            the watch list
	 * @param pcurrentRowsMappingList
	 *            the current rows mapping list
	 */
	public ShiftFormulaRef(final List<Integer> pwatchList,
			final List<RowsMapping> pcurrentRowsMappingList) {
		super();
		this.watchList = pwatchList;
		this.currentRowsMappingList = pcurrentRowsMappingList;
	}
	
	
	

	/**
	 * Gets the watch list.
	 *
	 * @return the watch list
	 */
	public final List<Integer> getWatchList() {
		return watchList;
	}

	/**
	 * Sets the watch list.
	 *
	 * @param pwatchList
	 *            the new watch list
	 */
	public final void setWatchList(final List<Integer> pwatchList) {
		this.watchList = pwatchList;
	}

	/**
	 * Gets the current rows mapping list.
	 *
	 * @return the current rows mapping list
	 */
	public final List<RowsMapping> getCurrentRowsMappingList() {
		return currentRowsMappingList;
	}

	/**
	 * Sets the current rows mapping list.
	 *
	 * @param pcurrentRowsMappingList
	 *            the new current rows mapping list
	 */
	public final void setCurrentRowsMappingList(
			final List<RowsMapping> pcurrentRowsMappingList) {
		this.currentRowsMappingList = pcurrentRowsMappingList;
	}

	/**
	 * Gets the formula changed.
	 *
	 * @return the formula changed
	 */
	public final int getFormulaChanged() {
		return formulaChanged;
	}

	/**
	 * Sets the formula changed.
	 *
	 * @param pformulaChanged
	 *            the new formula changed
	 */
	public final void setFormulaChanged(final int pformulaChanged) {
		this.formulaChanged = pformulaChanged;
	}


	/**
	 * Obtain a human readable representation.
	 * 
	 * @return String Human readable label
	 */
	@Override
	public final String toString() {

		StringBuilder sb = new StringBuilder();
		sb.append("{ watchList = " + watchList);
		sb.append(",");
		sb.append("currentRowsMappingList = " + currentRowsMappingList);
		sb.append("}");
		return sb.toString();
	}
}
 public class TieCommandAlias {
	
/** The alias. */
private String alias = null;

/** The command. */
private String command = null;

/** The remove. */
private boolean remove = false;

/** The pattern. */
private Pattern pattern = null;


/**
 * Instantiates a new tie command alias.
 *
 * @param alias the alias
 * @param command the command
 */
public TieCommandAlias(String alias, String command) {
	this.alias = alias;
	this.command = command;
}


/**
 * Instantiates a new tie command alias.
 *
 * @param alias the alias
 * @param command the command
 * @param remove the remove
 */
public TieCommandAlias(String alias, String command, boolean remove) {
	this.alias = alias;
	this.command = command;
	this.remove = remove;
}

/**
 * Gets the alias.
 *
 * @return the alias
 */
public String getAlias() {
	return alias;
}

/**
 * Sets the alias.
 *
 * @param alias the new alias
 */
public void setAlias(String alias) {
	this.alias = alias;
}

/**
 * Gets the command.
 *
 * @return the command
 */
public String getCommand() {
	return command;
}

/**
 * Sets the command.
 *
 * @param command the new command
 */
public void setCommand(String command) {
	this.command = command;
}

/**
 * Checks if is removes the.
 *
 * @return true, if is removes the
 */
public boolean isRemove() {
	return remove;
}

/**
 * Sets the removes the.
 *
 * @param remove the new removes the
 */
public void setRemove(boolean remove) {
	this.remove = remove;
}



/**
 * Gets the pattern.
 *
 * @return the pattern
 */
public Pattern getPattern() {
	if ((this.pattern == null) && (alias != null)) {
		this.pattern = Pattern.compile("\\s*" + ParserUtility.wildcardToRegex(alias));
	}	
	return pattern;
}




}
 public class EvaluationException extends RuntimeException {

	/** The Constant serialVersionUID. */
	private static final long serialVersionUID = 1L;

	/**
	 * Instantiates a new evaluation exception.
	 */
	public EvaluationException() {
		super();
	}

	/**
	 * Instantiates a new evaluation exception.
	 *
	 * @param message
	 *            the message
	 * @param cause
	 *            the cause
	 * @param enableSuppression
	 *            the enable suppression
	 * @param writableStackTrace
	 *            the writable stack trace
	 */
	public EvaluationException(final String message, final Throwable cause,
			final boolean enableSuppression,
			final boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}

	/**
	 * Instantiates a new evaluation exception.
	 *
	 * @param message
	 *            the message
	 * @param cause
	 *            the cause
	 */
	public EvaluationException(final String message,
			final Throwable cause) {
		super(message, cause);
	}

	/**
	 * Instantiates a new evaluation exception.
	 *
	 * @param message
	 *            the message
	 */
	public EvaluationException(final String message) {
		super("Evaluation exception = " + message);
	}

	/**
	 * Instantiates a new evaluation exception.
	 *
	 * @param cause
	 *            the cause
	 */
	public EvaluationException(final Throwable cause) {
		super("Evaluation exception = " + cause.getLocalizedMessage(),
				cause);
	}

}

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import org.apache.poi.ss.formula.FormulaParser;
import org.apache.poi.ss.formula.FormulaRenderer;
import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook;
import org.tiefaces.common.TieConstants;
import org.tiefaces.components.websheet.configuration.Command;
import org.tiefaces.components.websheet.configuration.ConfigBuildRef;
import org.tiefaces.components.websheet.configuration.ConfigRange;
import org.tiefaces.components.websheet.configuration.ConfigRangeAttrs;
import org.tiefaces.components.websheet.configuration.ExpressionEngine;
import org.tiefaces.components.websheet.configuration.RowsMapping;
import org.tiefaces.components.websheet.configuration.ShiftFormulaRef;
import org.tiefaces.components.websheet.dataobjects.TieCommandAlias;
import org.tiefaces.exception.EvaluationException;

	 *            the row index
	 * @param sheet
	 *            the sheet
	 * @return the string
	 */
	// 100 >= 80
	public static String replaceExpressionWithCellValue(
			final String attrValue, final int rowIndex, final Sheet sheet) {

		int ibegin = 0;
		int ifind;
		int inameEnd;
		String tempStr;
		String findStr;
		String replaceStr;
		String returnStr = attrValue;
		while ((ifind = attrValue.indexOf(TieConstants.CELL_ADDR_PRE_FIX,
				ibegin)) > 0) {
			inameEnd = ParserUtility.findFirstNonCellNamePosition(attrValue, ifind);
			if (inameEnd > 0) {
				findStr = attrValue.substring(ifind, inameEnd);
			} else {
				findStr = attrValue.substring(ifind);
			}
			if (findStr.indexOf(TieConstants.CELL_ADDR_PRE_FIX, 1) < 0) {
				// only $A
				tempStr = findStr + TieConstants.CELL_ADDR_PRE_FIX
						+ (rowIndex + 1);
			} else {
				tempStr = findStr;
			}
			replaceStr = CellUtility.getCellValueWithoutFormat(
					WebSheetUtility.getCellByReference(tempStr, sheet));
			if (replaceStr == null) {
				replaceStr = "";
			}
			returnStr = attrValue.replace(findStr, replaceStr);

			ibegin = ifind + 1;

		}
		return returnStr;
	}

	/**
	 * Index merged region.
	 *
	 * @param sheet1
	 *            the sheet 1
	 * @return the map
	 */
	public static Map<String, CellRangeAddress> indexMergedRegion(
			final Sheet sheet1) {

		int numRegions = sheet1.getNumMergedRegions();
		Map<String, CellRangeAddress> cellRangeMap = new HashMap<>();
		for (int i = 0; i < numRegions; i++) {

			CellRangeAddress caddress = sheet1.getMergedRegion(i);
			if (caddress != null) {
				cellRangeMap.put(CellUtility.getCellIndexNumberKey(
						caddress.getFirstColumn(), caddress.getFirstRow()),
						caddress);
			}
		}
		return cellRangeMap;
	}

	/**
	 * Skipped region cells.
	 *
	 * @param sheet1
	 *            the sheet 1
	 * @return the list
	 */
	public static List<String> skippedRegionCells(final Sheet sheet1) {
		int numRegions = sheet1.getNumMergedRegions();
		List<String> skipCellList = new ArrayList<>();
		for (int i = 0; i < numRegions; i++) {

			CellRangeAddress caddress = sheet1.getMergedRegion(i);
			if (caddress != null) {
				addSkipCellToListInTheRegion(skipCellList, caddress);
			}
		}
		return skipCellList;
	}

	/**
	 * Add skipped cell into the list of a region.
	 * 
	 * @param skipCellList
	 *            list.
	 * @param caddress
	 *            region.
	 */
	private static void addSkipCellToListInTheRegion(
			final List<String> skipCellList,
			final CellRangeAddress caddress) {
		for (int col = caddress.getFirstColumn(); col <= caddress
				.getLastColumn(); col++) {
			for (int row = caddress.getFirstRow(); row <= caddress
					.getLastRow(); row++) {
				if ((col == caddress.getFirstColumn())
						&& (row == caddress.getFirstRow())) {
					continue;
				}
				skipCellList
						.add(CellUtility.getCellIndexNumberKey(col, row));
			}
		}
	}

	
	/**
	 * Build Sheet Comment From command alias.
	 *
	 * @param sheet sheet.
	 * @param tieCommandAliasList 			list of ommand alias
	 */

	public static void buildSheetCommentFromAlias(Sheet sheet, List<TieCommandAlias> tieCommandAliasList) {
