/*
 * Copyright 2017 TieFaces.
 * Licensed under MIT
 */

package org.tiefaces.components.websheet.utility;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.tiefaces.common.FacesUtility;
import org.tiefaces.common.TieConstants;
import org.tiefaces.components.websheet.dataobjects.FacesCell;

/**
 * The Class PicturesHelper.
 */
/**
 * @author JASON
 *
 */
public final class CellStyleUtility {

	/**
	 * hide constructor.
	 */
	private CellStyleUtility() {
		// not called
	}

	/**
	 * Gets the row style.
	 *
	 * @param wb
	 *            the wb
	 * @param poiCell
	 *            the poi cell
	 * @param inputType
	 *            the input type
	 * @param rowHeight
	 *            the row height
	 * @param rowspan
	 *            the rowspan
	 * @return the row style
	 */
	public static String getRowStyle(final Workbook wb, final Cell poiCell,
			final String inputType, final float rowHeight,
			final int rowspan) {

		CellStyle cellStyle = poiCell.getCellStyle();
		if ((cellStyle != null) && (rowspan == 1)) {
			short fontIdx = cellStyle.getFontIndex();
			Font font = wb.getFontAt(fontIdx);
			float maxHeight = rowHeight;
			if (!inputType.isEmpty()) {
				maxHeight = Math.min(font.getFontHeightInPoints() + 8f,
						rowHeight);
			}
			return "height:" + WebSheetUtility.pointsToPixels(maxHeight)
					+ "px;";
		}
		return "";
	}

	/**
	 * Gets the cell font style.
	 *
	 * @param wb
	 *            the wb
	 * @param poiCell
	 *            the poi cell
	 * @return the cell font style
	 */
	public static String getCellFontStyle(final Workbook wb,
			final Cell poiCell) {

		CellStyle cellStyle = poiCell.getCellStyle();
		StringBuilder webStyle = new StringBuilder();
		if (cellStyle != null) {
			short fontIdx = cellStyle.getFontIndex();
			Font font = wb.getFontAt(fontIdx);
			if (font.getItalic()) {
				webStyle.append("font-style: italic;");
			}
			if (font.getBold()) {
				webStyle.append("font-weight: bold;");
			}
			webStyle.append(
					"font-size: " + font.getFontHeightInPoints() + "pt;");
			String decoration = getCellFontDecoration(font);
			if (decoration.length() > 0) {
				webStyle.append("text-decoration:" + decoration + ";");
			}
			webStyle.append(getCellFontColor(font));

		}
		return webStyle.toString();

	}

	/**
	 * get cell font color.
	 *
	 * @param font
	 *            font.
	 * @return String font color.
	 */
	private static String getCellFontColor(final Font font) {
		short[] rgbfix = { TieConstants.RGB_MAX, TieConstants.RGB_MAX,
				TieConstants.RGB_MAX };
		if (font instanceof XSSFFont) {
			XSSFColor color = ((XSSFFont) font).getXSSFColor();
			if (color != null) {
				rgbfix = ColorUtility.getTripletFromXSSFColor(color);
			}
		}
		if (rgbfix[0] != TieConstants.RGB_MAX) {
			return "color:rgb(" + FacesUtility.strJoin(rgbfix, ",") + ");";
		}
		return "";
	}

	/**
	 * Get font decoration.
	 *
	 * @param font
	 *            font.
	 * @return font decoration.
	 */
	private static String getCellFontDecoration(final Font font) {
		StringBuilder decoration = new StringBuilder();
		if (font.getUnderline() != 0) {
			decoration.append(" underline");
		}
		if (font.getStrikeout()) {
			decoration.append(" line-through");
		}
		return decoration.toString();
	}

	/**
	 * Gets the cell style.
	 *
	 * @param wb
	 *            the wb
	 * @param poiCell
	 *            the poi cell
	 * @param inputType
	 *            the input type
	 * @return the cell style
	 */
	public static String getCellStyle(final Workbook wb, final Cell poiCell,
			final String inputType) {

		CellStyle cellStyle = poiCell.getCellStyle();
		StringBuilder webStyle = new StringBuilder();
		if (cellStyle != null) {
			if (!inputType.isEmpty()) {
				webStyle.append(getAlignmentFromCell(poiCell, cellStyle));
				webStyle.append(getVerticalAlignmentFromCell(cellStyle));
			}

			webStyle.append(ColorUtility.getBgColorFromCell(wb, poiCell,
					cellStyle));
		}
		return webStyle.toString();

	}

	/**
	 * Gets the column style.
	 *
	 * @param wb
	 *            the wb
	 * @param fcell
	 *            the fcell
	 * @param poiCell
	 *            the poi cell
	 * @param rowHeight
	 *            the row height
	 * @return the column style
	 */
	public static String getColumnStyle(final Workbook wb,
			final FacesCell fcell, final Cell poiCell,
			final float rowHeight) {

		String inputType = fcell.getInputType();
		CellStyle cellStyle = poiCell.getCellStyle();
		StringBuilder webStyle = new StringBuilder();
		if (cellStyle != null) {
			if (fcell.isContainPic() || fcell.isContainChart()) {
				webStyle.append("vertical-align: top;");
			} else {
				webStyle.append(getAlignmentFromCell(poiCell, cellStyle));
				webStyle.append(getVerticalAlignmentFromCell(cellStyle));
			}
			webStyle.append(ColorUtility.getBgColorFromCell(wb, poiCell,
					cellStyle));
			webStyle.append(getRowStyle(wb, poiCell, inputType, rowHeight,
					fcell.getRowspan()));
		} else {
			webStyle.append(getAlignmentFromCellType(poiCell));
		}
		return webStyle.toString();

	}

	/**
	 * Gets the alignment from cell.
	 *
	 * @param poiCell
	 *            the poi cell
	 * @param cellStyle
	 *            the cell style
	 * @return the alignment from cell
	 */
	private static String getAlignmentFromCell(final Cell poiCell,
			final CellStyle cellStyle) {

		String style = "";
		switch (cellStyle.getAlignmentEnum()) {
		case LEFT:
			style = TieConstants.TEXT_ALIGN_LEFT;
			break;
		case RIGHT:
			style = TieConstants.TEXT_ALIGN_RIGHT;
			break;
		case CENTER:
			style = TieConstants.TEXT_ALIGN_CENTER;
			break;
		case GENERAL:
			style = getAlignmentFromCellType(poiCell);
			break;
		default:
			break;
		}
		return style;
	}

	/**
	 * Gets the vertical alignment from cell.
	 *
	 * @param cellStyle
	 *            the cell style
	 *
	 * @return the vertical alignment from cell
	 */
	private static String getVerticalAlignmentFromCell(
			final CellStyle cellStyle) {

		String style = "";
		switch (cellStyle.getVerticalAlignmentEnum()) {
		case TOP:
			style = TieConstants.VERTICAL_ALIGN_TOP;
			break;
		case CENTER:
			style = TieConstants.VERTICAL_ALIGN_CENTER;
			break;
		case BOTTOM:
			style = TieConstants.VERTICAL_ALIGN_BOTTOM;
			break;
		default:
			break;
		}
		return style;
	}

	// additionalWidth is to calculate extra width outside spreadsheet for
	// layout purpose
	/**
	 * Calc total width.
	 *
	 * @param sheet1
	 *            the sheet 1
	 * @param firstCol
	 *            the first col
	 * @param lastCol
	 *            the last col
	 * @param additionalWidth
	 *            the additional width
	 * @return the int
	 */
	// e.g. lineNumberColumnWidth and addRowColumnWidth
	public static int calcTotalWidth(final Sheet sheet1, final int firstCol,
			final int lastCol, final int additionalWidth) {

		int totalWidth = additionalWidth;
		for (int i = firstCol; i <= lastCol; i++) {
			totalWidth += sheet1.getColumnWidth(i);
		}
		return totalWidth;
	}

	/**
	 * Calc total height.
	 *
	 * @param sheet1
	 *            the sheet 1
	 * @param firstRow
	 *            the first row
	 * @param lastRow
	 *            the last row
	 * @param additionalHeight
	 *            the additional height
	 * @return the int
	 */
	public static int calcTotalHeight(final Sheet sheet1,
			final int firstRow, final int lastRow,
			final int additionalHeight) {

		int totalHeight = additionalHeight;
		for (int i = firstRow; i <= lastRow; i++) {

			totalHeight += sheet1.getRow(i).getHeight();
		}
		return totalHeight;
	}

	/**
	 * Setup cell style.
	 *
	 * @param wb
	 *            the wb
	 * @param fcell
	 *            the fcell
	 * @param poiCell
	 *            the poi cell
	 * @param rowHeight
	 *            the row height
	 */
	public static void setupCellStyle(final Workbook wb,
			final FacesCell fcell, final Cell poiCell,
			final float rowHeight) {

		CellStyle cellStyle = poiCell.getCellStyle();
		if ((cellStyle != null) && (!cellStyle.getLocked())) {
			// not locked
			if (fcell.getInputType().isEmpty()) {
				fcell.setInputType(
						CellStyleUtility.getInputTypeFromCellType(poiCell));
			}
			if (fcell.getControl().isEmpty()
					&& (!fcell.getInputType().isEmpty())) {
				fcell.setControl("text");
			}
			setInputStyleBaseOnInputType(fcell, poiCell);

		}
		String webStyle = getCellStyle(wb, poiCell, fcell.getInputType())
				+ getCellFontStyle(wb, poiCell)
				+ getRowStyle(wb, poiCell, fcell.getInputType(), rowHeight,
						fcell.getRowspan());
		fcell.setStyle(webStyle);
		fcell.setColumnStyle(getColumnStyle(wb, fcell, poiCell, rowHeight));
	}

	/**
	 * set up Input Style parameter for input number component which need those
	 * parameters to make it work. e.g. symbol, symbol position, decimal places.
	 *
	 * @param fcell
	 *            faces cell
	 * @param poiCell
	 *            poi cell
	 */
	static void setInputStyleBaseOnInputType(final FacesCell fcell,
			final Cell poiCell) {

		if ((fcell == null) || fcell.getInputType().isEmpty()) {
			return;
		}

		switch (fcell.getInputType()) {
		case TieConstants.CELL_INPUT_TYPE_PERCENTAGE:
			fcell.setSymbol("%");
			fcell.setSymbolPosition("p");
			fcell.setDecimalPlaces(
					CellStyleUtility.getDecimalPlacesFromFormat(poiCell));
			break;

		case TieConstants.CELL_INPUT_TYPE_INTEGER:
			fcell.setDecimalPlaces((short) 0);
			break;

		case TieConstants.CELL_INPUT_TYPE_DOUBLE:
			fcell.setDecimalPlaces(
					CellStyleUtility.getDecimalPlacesFromFormat(poiCell));
			fcell.setSymbol(CellStyleUtility.getSymbolFromFormat(poiCell));
			fcell.setSymbolPosition(
					CellStyleUtility.getSymbolPositionFromFormat(poiCell));
			break;
		default:
			break;
		}

	}

	/**
	 * Gets the alignment from cell type.
	 *
	 * @param poiCell
	 *            the poi cell
	 * @return the alignment from cell type
	 */
	@SuppressWarnings("deprecation")
	private static String getAlignmentFromCellType(final Cell poiCell) {

		switch (poiCell.getCellTypeEnum()) {
		case FORMULA:
		case NUMERIC:
			return "text-align: right;";
		default:
			return "";
		}

	}

	/**
	 * Gets the input type from cell type.
	 *
	 * @param cell
	 *            the cell
	 * @return the input type from cell type
	 */
	@SuppressWarnings("deprecation")
	private static String getInputTypeFromCellType(final Cell cell) {

		String inputType = TieConstants.CELL_INPUT_TYPE_TEXT;
		if (cell.getCellTypeEnum() == CellType.NUMERIC) {
			inputType = TieConstants.CELL_INPUT_TYPE_DOUBLE;
		}
		CellStyle style = cell.getCellStyle();
		if (style != null) {
			int formatIndex = style.getDataFormat();
			String formatString = style.getDataFormatString();
			if (DateUtil.isADateFormat(formatIndex, formatString)) {
				inputType = TieConstants.CELL_INPUT_TYPE_DATE;
			} else {
				if (isAPercentageCell(formatString)) {
					inputType = TieConstants.CELL_INPUT_TYPE_PERCENTAGE;
				}
			}
		}
		return inputType;
	}

	/**
	 * get decimal places from format string e.g. 0.00 will return 2
	 *
	 * @param cell
	 *            the cell
	 * @return decimal places of the formatted string
	 */
	private static short getDecimalPlacesFromFormat(final Cell cell) {
		CellStyle style = cell.getCellStyle();
		if (style == null) {
			return 0;
		}
		String formatString = style.getDataFormatString();
		if (formatString == null) {
			return 0;
		}
		int ipos = formatString.indexOf('.');
		if (ipos < 0) {
			return 0;
		}
		short counter = 0;
		for (int i = ipos + 1; i < formatString.length(); i++) {
			if (formatString.charAt(i) == '0') {
				counter++;
			} else {
				break;
			}
		}
		return counter;
	}

	/**
	 * get symbol from format string e.g. [$CAD] #,##0.00 will return CAD. While
	 * $#,##0.00 will return $
	 *
	 * @param cell
	 *            the cell
	 * @return symbol of the formatted string
	 */
	private static String getSymbolFromFormat(final Cell cell) {
		CellStyle style = cell.getCellStyle();
		if (style == null) {
			return null;
		}
		String formatString = style.getDataFormatString();
		if (formatString == null) {
			return null;
		}
		if (formatString.indexOf(TieConstants.CELL_ADDR_PRE_FIX) < 0) {
			return null;
		}
		int ipos = formatString.indexOf("[$");
		if (ipos < 0) {
			// only $ found, then return default dollar symbol
			return "$";
		}
		// return specified dollar symbol
		return formatString.substring(ipos + 2,
				formatString.indexOf(']', ipos));
	}

	/**
	 * get symbol position from format string e.g. [$CAD] #,##0.00 will return
	 * p. While #,##0.00 $ will return s
	 *
	 * @param cell
	 *            the cell
	 * @return symbol position of the formatted string
	 */
	private static String getSymbolPositionFromFormat(final Cell cell) {
		CellStyle style = cell.getCellStyle();
		if (style == null) {
			return "p";
		}
		String formatString = style.getDataFormatString();
		if (formatString == null) {
			return "p";
		}
		int symbolpos = formatString.indexOf('$');
		int numberpos = formatString.indexOf('#');
		if (numberpos < 0) {
			numberpos = formatString.indexOf('0');
		}
		if (symbolpos < numberpos) {
			return "p";
		} else {
			return "s";
		}
	}

	/**
	 * Check weather the cell is percentage formatted.
	 *
	 * @param formatString
	 *            the format string
	 * @return true if it's percentage formatted
	 */
	private static boolean isAPercentageCell(final String formatString) {

		if (formatString == null) {
			return false;
		}
		return formatString.indexOf('%') >= 0;

	}

}


/*
 * Copyright 2017 TieFaces.
 * Licensed under MIT
 */

package org.tiefaces.common;

import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

import javax.faces.context.FacesContext;

/**
 * FacesContext related common utility classes.
 *
 * @author Jason Jiang
 *
 */
public final class FacesUtility {

	/**
	 * hide constructor.
	 */
	private FacesUtility() {
		// not called
	}

	/**
	 * return faces context resource paths.
	 *
	 * @param path
	 *            path.
	 * @return a set of path.
	 */
	public static Set<String> getResourcePaths(final String path) {
		return getResourcePaths(getContext(), path);
	}

	/**
	 * return faces context resource path.
	 *
	 * @param context
	 *            face context.
	 * @param path
	 *            path.
	 * @return a set of path.
	 */
	public static Set<String> getResourcePaths(final FacesContext context,
			final String path) {
		return context.getExternalContext().getResourcePaths(path);
	}

	/**
	 * get resource file as stream.
	 *
	 * @param path
	 *            resource file path.
	 * @return stream.
	 */
	public static InputStream getResourceAsStream(final String path) {
		return getResourceAsStream(getContext(), path);
	}

	/**
	 * get resource file as stream.
	 *
	 * @param context
	 *            faces context.
	 * @param path
	 *            resource file path.
	 * @return stream.
	 */
	public static InputStream getResourceAsStream(
			final FacesContext context, final String path) {
		return context.getExternalContext().getResourceAsStream(path);
	}

	/**
	 * get metadata attributes.
	 *
	 * @return map of metadata attributes.
	 */
	public static Map<String, Object> getMetadataAttributes() {
		return getMetadataAttributes(getContext());
	}

	/**
	 * get metadata attributes.
	 *
	 * @param context
	 *            faces context.
	 * @return map of metadata attributes.
	 */
	public static Map<String, Object> getMetadataAttributes(
			final FacesContext context) {
		return context.getViewRoot().getAttributes();
	}

	/**
	 * evaluate expression.
	 *
	 * @param <T>
	 *            This is the type parameter.
	 * @param expression
	 *            expression.
	 * @return evaluated object.
	 */
	public static <T> T evaluateExpressionGet(final String expression) {
		return evaluateExpressionGet(getContext(), expression);
	}

	/**
	 * evaluate expression.
	 *
	 * @param <T>
	 *            This is the type parameter
	 * @param context
	 *            faces context.
	 * @param expression
	 *            expression.
	 * @return evaluated object.
	 */
	@SuppressWarnings("unchecked")
	public static <T> T evaluateExpressionGet(final FacesContext context,
			final String expression) {
		if (expression == null) {
			return null;
		}

		return (T) context.getApplication().evaluateExpressionGet(context,
				expression, Object.class);
	}

	/**
	 * return faces context.
	 *
	 * @return faces context.
	 */
	public static FacesContext getContext() {
		return FacesContext.getCurrentInstance();
	}

	/**
	 * remove prefix path of the full path.
	 *
	 * @param prefix
	 *            prefix string.
	 * @param resource
	 *            normal resource.
	 * @return removed path.
	 */
	public static String removePrefixPath(final String prefix,
			final String resource) {
		String normalizedResource = resource;
		if (normalizedResource.startsWith(prefix)) {
			normalizedResource = normalizedResource
					.substring(prefix.length() - 1);
		}

		return normalizedResource;
	}

	/**
	 * evaluate input type.
	 *
	 * @param input
	 *            input string.
	 * @param type
	 *            input type.
	 * @return true if input meet type, otherwise false.
	 */
	public static boolean evalInputType(final String input,
			final String type) {

		Scanner scanner = new Scanner(input);
		boolean ireturn = false;
		if ("Integer".equalsIgnoreCase(type)) {
			ireturn = scanner.hasNextInt();
		} else if ("Double".equalsIgnoreCase(type)) {
			ireturn = scanner.hasNextDouble();
		} else if ("Boolean".equalsIgnoreCase(type)) {
			ireturn = scanner.hasNextBoolean();
		} else if ("Byte".equalsIgnoreCase(type)) {
			ireturn = scanner.hasNextByte();
		} else if (type.toLowerCase().startsWith("text")) {
			ireturn = true;
		}
		scanner.close();
		return ireturn;
	}

	/**
	 * Find bean in context.
	 *
	 * @param <T>
	 *            This is the type parameter.
	 * @param beanName
	 *            bean name.
	 * @return bean object.
	 */
	@SuppressWarnings("unchecked")
	public static <T> T findBean(final String beanName) {
		FacesContext context = FacesContext.getCurrentInstance();
		return (T) context.getApplication().evaluateExpressionGet(context,
				TieConstants.EL_START + beanName + TieConstants.EL_END,
				Object.class);
	}

	/**
	 * evaluate expression.
	 *
	 * @param <T>
	 *            This is the type parameter.
	 * @param expression
	 *            expression.
	 * @param expected
	 *            exprected type.
	 * @return evaluated object.
	 */
	public static <T> T evaluateExpression(final String expression,
			final Class<? extends T> expected) {
		return evaluateExpression(FacesContext.getCurrentInstance(),
				expression, expected);
	}

	/**
	 * evaluate expression.
	 *
	 * @param <T>
	 *            This is the type parameter.
	 * @param context
	 *            faces context.
	 * @param expression
	 *            expression.
	 * @param expected
	 *            expected type.
	 * @return evaluated object.
	 */

	public static <T> T evaluateExpression(final FacesContext context,
			final String expression, final Class<? extends T> expected) {
		return context.getApplication().evaluateExpressionGet(context,
				expression, expected);
	}

	/**
	 * join string.
	 *
	 * @param aArr
	 *            attribute list.
	 * @param sSep
	 *            seperator string.
	 * @return joined string.
	 */
	public static String strJoin(final short[] aArr, final String sSep) {
		StringBuilder sbStr = new StringBuilder();
		for (int i = 0, il = aArr.length; i < il; i++) {
			if (i > 0) {
				sbStr.append(sSep);
			}
			sbStr.append(aArr[i]);
		}
		return sbStr.toString();
	}
	/**
	 * join string
	 * @param aArr attr list.
	 * @param sSep seperator string.
	 * @return joined string.
	 */
	public static String strJoin(final String[] aArr, final String sSep) {
		StringBuilder sbStr = new StringBuilder();
		for (int i = 0, il = aArr.length; i < il; i++) {
			if (i > 0) {
				sbStr.append(sSep);
			}
			sbStr.append(aArr[i]);
		}
		return sbStr.toString();
	}

	/**
	 * round number according to decimal places.
	 *
	 * @param value
	 *            double value.
	 * @param places
	 *            decimal places.
	 * @return rounded number.
	 */
	public static double round(final double value, final int places) {
		if (places < 0) {
			throw new IllegalArgumentException();
		}

		BigDecimal bd = BigDecimal.valueOf(value);
		bd = bd.setScale(places, RoundingMode.HALF_UP);
		return bd.doubleValue();
	}
}


/*
 * Copyright 2017 TieFaces.
 * Licensed under MIT
 */

package org.tiefaces.components.websheet;

import java.io.Serializable;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.primefaces.component.tabview.TabView;
import org.tiefaces.common.TieConstants;
import org.tiefaces.components.websheet.configuration.ConfigAdvancedContext;
import org.tiefaces.components.websheet.dataobjects.TieCommandAlias;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

/**
 * sheet view class.
 *
 * @author Jason Jiang.
 *
 */
public class TieWebSheetView {

	/**
	 * tab type.
	 */
	private String tabType;

	/**
	 * tabs.
	 */
	private List<TabModel> tabs;

	/**
	 * web form tab view.
	 */
	private TabView webFormTabView = null;

	/** maxrowsperpage. */
	private Integer maxRowsPerPage = TieConstants.DEFAULT_MAX_ROWS_PER_PAGE;

	/**
	 * tabwidth style.
	 */
	private String tableWidthStyle = TieConstants.DEFAULT_TABLE_WIDTH_STYLE;

	/** line number column width. */
	private int lineNumberColumnWidth = TieConstants.DEFAULT_LINENUMBER_COLUMN_WIDTH;
	/** add row column width. */
	private int addRowColumnWidth = TieConstants.DEFAULT_ADDROW_COLUMN_WIDTH;
	/** line number column width style. */
	private String lineNumberColumnWidthStyle = "";
	/** add row column width style. */
	private String addRowColumnWidthStyle = "";
	/** allow add row in body. */
	private boolean bodyAllowAddRows;
	/** show line number in web gui. */
	private boolean showLineNumber = false;
	/** The hide single sheet tab title. */
	private boolean hideSingleSheetTabTitle = true;

	/**  active tab index. */
	private int activeTabIndex = 0;

	/**
	 * Client id for whole websheet component. This is the top level client id.
	 * There're tabs and web forms under this top level.
	 */
	private String clientId = null;
	/** Client id for web forms. */
	private String webFormClientId = null;

	/** skip configuration. show the excel form as is. */
	private boolean skipConfiguration = false;

	/**
	 * workaround for rendered attributes. True -- work sheet will be rendered.
	 * False -- work sheet not rendered.
	 */
	private boolean rendered = true;

	/** The default locale. */
	private Locale defaultLocale = null;

	/** The default date pattern. */
	private String defaultDatePattern = null;

	/** The export file name. */
	private String exportFileName = "WebSheetTemplate" + "." + TieConstants.EXCEL_2007_TYPE;

	/** The is advanced context. */
	private boolean isAdvancedContext = false;

	/** The config advanced context. */
	private ConfigAdvancedContext configAdvancedContext;

	/** The tie web sheet validation bean. */
	private TieWebSheetValidation tieWebSheetValidationBean;

	/**  If true then validationBean only work in submitMode. */
	private boolean onlyValidateInSubmitMode = false;

	/** The tie command alias list. */
	private List<TieCommandAlias> tieCommandAliasList;

	/**
	 * empty constructor.
	 */
	public TieWebSheetView() {
		super();
	}

	/**
	 * assign web form client id.
	 *
	 * @param pWebFormClientId
	 *            String client id name.
	 */
	public void setWebFormClientId(final String pWebFormClientId) {
		this.webFormClientId = pWebFormClientId;
	}

	/**
	 * Gets the web form client id.
	 *
	 * @return web form client Id.
	 */
	public String getWebFormClientId() {
		return webFormClientId;
	}

	/**
	 * Gets the client id.
	 *
	 * @return client id.
	 */
	public String getClientId() {
		return clientId;
	}

	/**
	 * Sets the client id.
	 *
	 * @param pClientId
	 *            client Id.
	 */
	public void setClientId(final String pClientId) {
		this.clientId = pClientId;
	}

	/**
	 * get tabs.
	 *
	 * @return list of tabs.
	 */
	public List<TabModel> getTabs() {
		return tabs;
	}

	/**
	 * set tabs.
	 *
	 * @param ptabs
	 *            list of tabs.
	 */
	public void setTabs(final List<TabModel> ptabs) {
		this.tabs = ptabs;
	}

	/**
	 * tab model class.
	 *
	 * @author Jason Jiang
	 *
	 */
	public static class TabModel implements Serializable {

		/** serialid. */
		private static final long serialVersionUID = 1L;
		/** tab id. */
		private String id;
		/** tab title. */
		private String title;
		/** tab type. */
		private String type;

		/**
		 * constructor.
		 *
		 * @param pid
		 *            id.
		 * @param ptitle
		 *            title.
		 * @param ptype
		 *            type.
		 */
		public TabModel(final String pid, final String ptitle, final String ptype) {
			this.id = pid;
			if (this.id != null) {
				this.id = this.id.replaceAll(" ", "_");
			}
			this.title = ptitle;
			this.type = ptype;
		}

		/**
		 * get id.
		 *
		 * @return id.
		 */
		public String getId() {
			return id;
		}

		/**
		 * set id.
		 *
		 * @param pid
		 *            id.
		 */
		public void setId(final String pid) {
			this.id = pid;
		}

		/**
		 * get title.
		 *
		 * @return title.
		 */
		public String getTitle() {
			return title;
		}

		/**
		 * get type.
		 *
		 * @return type.
		 */
		public String getType() {
			return type;
		}
	}

	/**
	 * get web form tab view.
	 *
	 * @return webformtabview.
	 */
	public TabView getWebFormTabView() {
		return webFormTabView;
	}

	/**
	 * set pwebform tab view.
	 *
	 * @param pwebFormTabView
	 *            webformtabview.
	 */
	public void setWebFormTabView(final TabView pwebFormTabView) {
		this.webFormTabView = pwebFormTabView;
	}

	/**
	 * get tab type.
	 *
	 * @return tab type.
	 */
	public String getTabType() {

		int sheetId = webFormTabView.getActiveIndex();
		if ((sheetId >= 0) && (tabs != null)) {
			if (sheetId >= tabs.size()) {
				sheetId = 0;
			}
			tabType = tabs.get(sheetId).type.toLowerCase();
		} else {
			tabType = TieConstants.TAB_TYPE_NONE;
		}
		return tabType;
	}

	/**
	 * get tab style.
	 *
	 * @return string.
	 */
	public String getTabStyle() {

		String tabStyle = TieConstants.TAB_STYLE_VISIBLE;
		int sheetId = webFormTabView.getActiveIndex();
		if ((sheetId >= 0) && (sheetId < tabs.size())) {
			tabStyle = TieConstants.TAB_STYLE_INVISIBLE;

		}

		return tabStyle;
	}

	/**
	 * set tab type.
	 *
	 * @param ptabType
	 *            tab type.
	 */
	public void setTabType(final String ptabType) {
		this.tabType = ptabType;
	}

	/**
	 * get maxrowsperpage.
	 *
	 * @return maxrowsperpage.
	 */
	public Integer getMaxRowsPerPage() {
		return maxRowsPerPage;
	}

	/**
	 * set maxrowsperpage.
	 *
	 * @param pmaxRowsPerPage
	 *            maxrowsperpage.
	 */
	public void setMaxRowsPerPage(final Integer pmaxRowsPerPage) {
		this.maxRowsPerPage = pmaxRowsPerPage;
	}

	/**
	 * get table width style.
	 *
	 * @return tablewidthstyle.
	 */
	public String getTableWidthStyle() {
		return tableWidthStyle;
	}

	/**
	 * set tablewidthstyle.
	 *
	 * @param ptableWidthStyle
	 *            tablewidth style.
	 */
	public void setTableWidthStyle(final String ptableWidthStyle) {
		this.tableWidthStyle = ptableWidthStyle;
	}

	/**
	 * get line number column width.
	 *
	 * @return linenumbercolumnwidth.
	 */
	public int getLineNumberColumnWidth() {
		return lineNumberColumnWidth;
	}

	/**
	 * set line number column width .
	 *
	 * @param plineNumberColumnWidth
	 *            column width.
	 */
	public void setLineNumberColumnWidth(final int plineNumberColumnWidth) {
		this.lineNumberColumnWidth = plineNumberColumnWidth;
	}

	/**
	 * get add row column width.
	 *
	 * @return add row column width.
	 */
	public int getAddRowColumnWidth() {
		return addRowColumnWidth;
	}

	/**
	 * set add row column width.
	 *
	 * @param addWidth
	 *            add row column width.
	 */
	public void setAddRowColumnWidth(final int addWidth) {
		this.addRowColumnWidth = addWidth;
	}

	/**
	 * get line number column width style.
	 *
	 * @return column width style.
	 */
	public String getLineNumberColumnWidthStyle() {
		return lineNumberColumnWidthStyle;
	}

	/**
	 * set line number column width style.
	 *
	 * @param lineNumberCoumnWidthStyle
	 *            style.
	 */
	public void setLineNumberColumnWidthStyle(final String lineNumberCoumnWidthStyle) {
		this.lineNumberColumnWidthStyle = lineNumberCoumnWidthStyle;
	}

	/**
	 * get add row column width style.
	 *
	 * @return style.
	 */
	public String getAddRowColumnWidthStyle() {
		return addRowColumnWidthStyle;
	}

	/**
	 * set add row column style.
	 *
	 * @param addWidthStyle
	 *            style.
	 */
	public void setAddRowColumnWidthStyle(final String addWidthStyle) {
		this.addRowColumnWidthStyle = addWidthStyle;
	}

	/**
	 * is allow add row.
	 *
	 * @return true if allowed.
	 */
	public boolean isBodyAllowAddRows() {
		return bodyAllowAddRows;
	}

	/**
	 * set body allow add rows.
	 *
	 * @param pbodyAllowAddRows
	 *            true if allowed.
	 */
	public void setBodyAllowAddRows(final boolean pbodyAllowAddRows) {
		this.bodyAllowAddRows = pbodyAllowAddRows;
	}

	/**
	 * is show line number.
	 *
	 * @return true if show.
	 */
	public boolean isShowLineNumber() {
		return showLineNumber;
	}

	/**
	 * set show line number.
	 *
	 * @param pshowLineNumber
	 *            true if show.
	 */
	public void setShowLineNumber(final boolean pshowLineNumber) {
		this.showLineNumber = pshowLineNumber;
	}

	/**
	 * Checks if is hide single sheet tab title.
	 *
	 * @return the hideSingleSheetTabTitle
	 */
	public boolean isHideSingleSheetTabTitle() {
		return hideSingleSheetTabTitle;
	}

	/**
	 * Sets the hide single sheet tab title.
	 *
	 * @param phideSingleSheetTabTitle
	 *            the hideSingleSheetTabTitle to set
	 */
	public void setHideSingleSheetTabTitle(final boolean phideSingleSheetTabTitle) {
		this.hideSingleSheetTabTitle = phideSingleSheetTabTitle;
	}

	/**
	 * Checks if is show tab view.
	 *
	 * @return true, if is show tab view
	 */
	public boolean isShowTabView() {
		if (this.getTabs() == null) {
			return false;
		}
		return !this.isHideSingleSheetTabTitle() || (this.getTabs().size() > 1);

	}

	/**
	 * Checks if is skip configuration.
	 *
	 * @return the skipConfiguration
	 */
	public boolean isSkipConfiguration() {
		return skipConfiguration;
	}

	/**
	 * Sets the skip configuration.
	 *
	 * @param pskipConfiguration
	 *            the skipConfiguration to set
	 */
	public void setSkipConfiguration(final boolean pskipConfiguration) {
		this.skipConfiguration = pskipConfiguration;
	}

	/**
	 * Gets the active tab index.
	 *
	 * @return the active tab index
	 */
	public int getActiveTabIndex() {
		return activeTabIndex;
	}

	/**
	 * Sets the active tab index.
	 *
	 * @param activeTabIndex the new active tab index
	 */
	public void setActiveTabIndex(int activeTabIndex) {
		this.activeTabIndex = activeTabIndex;
	}

	/**
	 * Checks if is rendered.
	 *
	 * @return the rendered
	 */
	public boolean isRendered() {
		return rendered;
	}

	/**
	 * Sets the rendered.
	 *
	 * @param rendered            the rendered to set
	 */
	public void setRendered(boolean rendered) {
		this.rendered = rendered;
	}

	/**
	 * Gets the default locale.
	 *
	 * @return the default locale
	 */
	public Locale getDefaultLocale() {
		if (defaultLocale == null) {
			defaultLocale = Locale.getDefault();
		}
		return defaultLocale;
	}

	/**
	 * Sets the default locale.
	 *
	 * @param defaultLocale the new default locale
	 */
	public void setDefaultLocale(Locale defaultLocale) {
		this.defaultLocale = defaultLocale;
	}

	/**
	 * Gets the default date pattern.
	 *
	 * @return the default date pattern
	 */
	public String getDefaultDatePattern() {
		if (defaultDatePattern == null) {
			DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
			defaultDatePattern = ((SimpleDateFormat) formatter).toLocalizedPattern();
		}
		return defaultDatePattern;
	}

	/**
	 * Sets the default date pattern.
	 *
	 * @param defaultDatePattern the new default date pattern
	 */
	public void setDefaultDatePattern(String defaultDatePattern) {
		this.defaultDatePattern = defaultDatePattern;
	}

	/**
	 * Gets the decimal separator by default locale.
	 *
	 * @return the decimal separator by default locale
	 */
	public String getDecimalSeparatorByDefaultLocale() {
		final DecimalFormat nf = (DecimalFormat) DecimalFormat.getInstance(getDefaultLocale());
		return "" + nf.getDecimalFormatSymbols().getDecimalSeparator();
	}

	/**
	 * Gets the thousand separator by default locale.
	 *
	 * @return the thousand separator by default locale
	 */
	public String getThousandSeparatorByDefaultLocale() {
		final DecimalFormat nf = (DecimalFormat) DecimalFormat.getInstance(getDefaultLocale());
		return "" + nf.getDecimalFormatSymbols().getGroupingSeparator();
	}

	/**
	 * Gets the export file name.
	 *
	 * @return the export file name
	 */
	public String getExportFileName() {
		return this.exportFileName;
	}

	/**
	 * Sets the export file name.
	 *
	 * @param pExportFileName the new export file name
	 */
	public void setExportFileName(String pExportFileName) {
		this.exportFileName = pExportFileName;
	}

	/**
	 * Checks if is advanced context.
	 *
	 * @return true, if is advanced context
	 */
	public boolean isAdvancedContext() {
		return isAdvancedContext;
	}

	/**
	 * Sets the advanced context.
	 *
	 * @param isAdvancedContext the new advanced context
	 */
	public void setAdvancedContext(boolean isAdvancedContext) {
		this.isAdvancedContext = isAdvancedContext;
	}

	/**
	 * Gets the config advanced context.
	 *
	 * @return the config advanced context
	 */
	public ConfigAdvancedContext getConfigAdvancedContext() {
		return configAdvancedContext;
	}

	/**
	 * Sets the config advanced context.
	 *
	 * @param configAdvancedContext the new config advanced context
	 */
	public void setConfigAdvancedContext(ConfigAdvancedContext configAdvancedContext) {
		this.configAdvancedContext = configAdvancedContext;
	}

	/**
	 * Gets the tie web sheet validation bean.
	 *
	 * @return the tie web sheet validation bean
	 */
	public TieWebSheetValidation getTieWebSheetValidationBean() {
		return tieWebSheetValidationBean;
	}

	/**
	 * Sets the tie web sheet validation bean.
	 *
	 * @param tieWebSheetValidationBean the new tie web sheet validation bean
	 * @param onlyValidationInSubmitMode the only validation in submit mode
	 */
	public void setTieWebSheetValidationBean(TieWebSheetValidation tieWebSheetValidationBean, boolean onlyValidationInSubmitMode) {
		this.tieWebSheetValidationBean = tieWebSheetValidationBean;
		this.onlyValidateInSubmitMode = onlyValidationInSubmitMode;
	}

	/**
	 * Checks if is only validate in submit mode.
	 *
	 * @return true, if is only validate in submit mode
	 */
	public boolean isOnlyValidateInSubmitMode() {
		return onlyValidateInSubmitMode;
	}

	/**
	 * Gets the tie command alias list.
	 *
	 * @return the tie command alias list
	 */
	public List<TieCommandAlias> getTieCommandAliasList() {
		return tieCommandAliasList;
	}

	/**
	 * Sets the tie command alias list.
	 *
	 * @param tieCommandAliasList the new tie command alias list
	 */
	public void setTieCommandAliasList(List<TieCommandAlias> tieCommandAliasList) {
		this.tieCommandAliasList = tieCommandAliasList;
	}

	/**
	 * Sets the tie command alias list.
	 *
	 * @param aliasListJson the new tie command alias list
	 */
	public void setTieCommandAliasList(String aliasListJson) {

		Gson gson = new Gson();

		Type aliasListType = new TypeToken<ArrayList<TieCommandAlias>>(){}.getType();

		this.tieCommandAliasList = gson.fromJson(aliasListJson, aliasListType);
	}

}


/*
 * Copyright 2017 TieFaces.
 * Licensed under MIT
 */
package org.tiefaces.components.websheet.configuration;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.poi.ss.formula.FormulaParser;
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.xssf.usermodel.XSSFEvaluationWorkbook;
import org.tiefaces.common.TieConstants;
import org.tiefaces.components.websheet.utility.ConfigurationUtility;
import org.tiefaces.components.websheet.utility.ShiftFormulaUtility;

/**
 * Form command. i.e. tie:form(name="departments" length="9" header="0"
 * footer="0")
 *
 * @author Jason Jiang
 *
 */

public class FormCommand extends ConfigCommand implements Serializable {

	/**
	 * serialVersionUID.
	 */
	private static final long serialVersionUID = -6612626038249384415L;
	/** name holder. */
	private String name;
	/** header holder. */
	private String headerLength;
	/** footer holder. */
	private String footerLength;
	/** hidden holder. */
	private String hidden;
	/** readonly holder. */
	private String readOnly;
	/** fixedWidthStyle holder. */
	private String fixedWidthStyle;

	/**
	 * Instantiates a new form command.
	 */
	public FormCommand() {
		super();
	}

	/**
	 * Instantiates a new form command.
	 *
	 * @param sourceCommand
	 *            the source command
	 */
	public FormCommand(final FormCommand sourceCommand) {
		super((ConfigCommand) sourceCommand);
		this.name = sourceCommand.name;
		this.headerLength = sourceCommand.headerLength;
		this.footerLength = sourceCommand.footerLength;
		this.hidden = sourceCommand.hidden;
		this.readOnly = sourceCommand.readOnly;
		this.fixedWidthStyle = sourceCommand.fixedWidthStyle;
	}

	/**
	 * Gets the name.
	 *
	 * @return the name
	 */
	public final String getName() {
		return name;
	}

	/**
	 * Sets the name.
	 *
	 * @param pName
	 *            the new name
	 */
	public final void setName(final String pName) {
		this.name = pName;
	}

	/**
	 * Gets the header length.
	 *
	 * @return the header length
	 */
	public final String getHeaderLength() {
		return headerLength;
	}

	/**
	 * Sets the header length.
	 *
	 * @param pheaderLength
	 *            the new header length
	 */
	public final void setHeaderLength(final String pheaderLength) {
		this.headerLength = pheaderLength;
	}

	/**
	 * Gets the footer length.
	 *
	 * @return the footer length
	 */
	public final String getFooterLength() {
		return footerLength;
	}

	/**
	 * Sets the footer length.
	 *
	 * @param pfooterLength
	 *            the new footer length
	 */
	public final void setFooterLength(final String pfooterLength) {
		this.footerLength = pfooterLength;
	}

	/**
	 * Gets the hidden.
	 *
	 * @return the hidden
	 */
	public final String getHidden() {
		return hidden;
	}

	/**
	 * Sets the hidden.
	 *
	 * @param pHidden
	 *            the new hidden
	 */
	public final void setHidden(final String pHidden) {
		this.hidden = pHidden;
	}

	/**
	 * calc header length.
	 *
	 * @return int header length.
	 */
	public final int calcHeaderLength() {
		return calcLength(this.getHeaderLength());
	}

	/**
	 * calc body length.
	 *
	 * @return int body length.
	 */
	public final int calcBodyLength() {
		return calcLength(this.getLength()) - calcHeaderLength()
				- calcFooterLength();
	}

	/**
	 * calc footer length.
	 *
	 * @return int footer length.
	 */
	public final int calcFooterLength() {
		return calcLength(this.getFooterLength());
	}

	/**
	 * @return the readOnly
	 */
	public final String getReadOnly() {
		return readOnly;
	}

	/**
	 * @param preadOnly
	 *            the readOnly to set
	 */
	public final void setReadOnly(final String preadOnly) {
		this.readOnly = preadOnly;
	}

	/**
	 * @return the fixedWidthStyle
	 */
	public final String getFixedWidthStyle() {
		return fixedWidthStyle;
	}

	/**
	 * @param pfixedWidthStyle
	 *            the fixedWidthStyle to set
	 */
	public final void setFixedWidthStyle(final String pfixedWidthStyle) {
		this.fixedWidthStyle = pfixedWidthStyle;
	}

	/**
	 * Obtain a human readable representation.
	 *
	 * @return String Human readable label
	 */
	@Override
	public final String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("{");
		sb.append("commandName = " + this.getCommandTypeName());
		sb.append(",");
		sb.append("form Name = " + this.getName());
		sb.append(",");
		sb.append("length = " + this.getLength());
		sb.append(",");
		sb.append("header length = " + this.getHeaderLength());
		sb.append(",");
		sb.append("footer length = " + this.getFooterLength());
		sb.append(",");
		sb.append("readOnly = " + this.getReadOnly());
		sb.append(",");
		sb.append("fixedWidthStyle = " + this.getFixedWidthStyle());
		sb.append(",");
		sb.append("ConfigRange = " + this.getConfigRange());
		sb.append("}");
		return sb.toString();

	}

	// Form is top level, Form cannot include another Form
	/**
	 * Watch list serve for formula changes. Basically all the rows appeared in
	 * the formula in the current sheet will be watched. Note if the cell
	 * reference is from other sheet or workbooks, it will be ignored.
	 *
	 * @param wbWrapper
	 *            XSSFEvaluationWorkbook used for formula parse.
	 * @param sheet
	 *            current sheet.
	 * @return List row number for monitoring.
	 */
	private List<Integer> buildFormWatchList(
			final XSSFEvaluationWorkbook wbWrapper, final Sheet sheet) {

		List<Integer> watchList = new ArrayList<>();

		ConfigRange cRange = this.getConfigRange();
		List<ConfigCommand> commandList = cRange.getCommandList();
		if (commandList.isEmpty()) {
			// if no command then no dynamic changes. then no need formula
			// shifts.
			return watchList;
		}
		int lastStaticRow = commandList.get(0).getTopRow() - 1;
		if (lastStaticRow < 0) {
			lastStaticRow = this.getTopRow();
		}

		int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet);

		for (int i = this.getTopRow(); i <= this.getLastRow(); i++) {
			Row row = sheet.getRow(i);
			for (Cell cell : row) {
				if (cell.getCellTypeEnum() == CellType.FORMULA) {

					buildWatchListForCell(wbWrapper, sheetIndex, cell,
							watchList, lastStaticRow);

				}
			}
		}

		return watchList;

	}

	/**
	 * Builds the watch list for cell.
	 *
	 * @param wbWrapper
	 *            the wb wrapper
	 * @param sheetIndex
	 *            the sheet index
	 * @param cell
	 *            the cell
	 * @param watchList
	 *            the watch list
	 * @param lastStaticRow
	 *            the last static row
	 */
	private void buildWatchListForCell(
			final XSSFEvaluationWorkbook wbWrapper, final int sheetIndex,
			final Cell cell, final List<Integer> watchList, final int lastStaticRow) {
		String formula = cell.getCellFormula();

		Ptg[] ptgs = FormulaParser.parse(formula, wbWrapper,
				FormulaType.CELL, sheetIndex);

		for (int k = 0; k < ptgs.length; k++) {
			Object ptg = ptgs[k];
			// For area formula, only first row is watched.
			// Reason is the lastRow must shift same rows with
			// firstRow.
			// Otherwise it's difficult to calculate.
			// In case some situation cannot fit, then should make
			// change to the formula.
			int areaInt = ShiftFormulaUtility
					.getFirstSupportedRowNumFromPtg(ptg);
			if (areaInt >= 0) {
				addToWatchList(areaInt, lastStaticRow, watchList);
			}
		}

		// when insert row, the formula may changed. so here is the
		// workaround.
		// change formula to user formula to preserve the row
		// changes.
		cell.setCellType(CellType.STRING);
		cell.setCellValue(TieConstants.USER_FORMULA_PREFIX + formula
				+ TieConstants.USER_FORMULA_SUFFIX);
	}

	/**
	 * Only rows in dynamic area will be added to watch list.
	 *
	 * @param addRow
	 *            row want to add.
	 * @param lastStaticRow
	 *            last static row.
	 * @param watchList
	 *            watch list.
	 */
	private void addToWatchList(final int addRow, final int lastStaticRow,
			final List<Integer> watchList) {
		if ((addRow > lastStaticRow) && !(watchList.contains(addRow))) {
			watchList.add(addRow);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.tiefaces.components.websheet.configuration.Command#buildAt(java.lang.
	 * String, org.tiefaces.components.websheet.configuration.ConfigBuildRef,
	 * int, java.util.Map, java.util.List)
	 */
	@Override
	/**
	 * build the command area at the row.
	 */
	public final int buildAt(String fullName,
			final ConfigBuildRef configBuildRef, final int atRow,
			final Map<String, Object> context,
			List<RowsMapping> currentRowsMappingList) {

		configBuildRef.setWatchList(buildFormWatchList(
				configBuildRef.getWbWrapper(), configBuildRef.getSheet()));
		fullName = this.getCommandName();

		RowsMapping unitRowsMapping = new RowsMapping();
		for (Integer index : configBuildRef.getWatchList()) {
			if (ConfigurationUtility.isStaticRow(this.getConfigRange(),
					index)) {
				unitRowsMapping.addRow(index,
						configBuildRef.getSheet().getRow(index));
			}
		}
		currentRowsMappingList = new ArrayList<>();
		currentRowsMappingList.add(unitRowsMapping);
		this.getConfigRange().getAttrs().setAllowAdd(false);
		configBuildRef.putShiftAttrs(fullName,
				this.getConfigRange().getAttrs(),
				new RowsMapping(unitRowsMapping));
		configBuildRef.setOriginConfigRange(
				new ConfigRange(this.getConfigRange()));
		configBuildRef.getOriginConfigRange()
				.indexCommandRange(configBuildRef.getCommandIndexMap());
		int length = this.getConfigRange().buildAt(fullName, configBuildRef,
				atRow, context, currentRowsMappingList);
		this.getConfigRange().getAttrs().setFinalLength(length);
		this.setFinalLength(length);
		configBuildRef.getSheet().setColumnHidden(
				TieConstants.HIDDEN_FULL_NAME_COLUMN, true);
		configBuildRef.getSheet().setColumnHidden(
				TieConstants.HIDDEN_SAVE_OBJECTS_COLUMN, true);
		configBuildRef.getSheet().setColumnHidden(
				TieConstants.HIDDEN_ORIGIN_ROW_NUMBER_COLUMN, true);

		return length;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.tiefaces.components.websheet.configuration.Command#getCommandName()
	 */
	/*
	 *
	 * @see
	 * org.tiefaces.components.websheet.configuration.Command#getCommandName()
	 */
	@Override
	public final String getCommandName() {
		return this.getCommandTypeName().substring(0, 1).toUpperCase() + "."
				+ this.getName().trim();
	}

}


/*
 * Copyright 2017 TieFaces.
 * Licensed under MIT
 */
package org.tiefaces.components.websheet.chart.objects;

import java.util.ArrayList;
import java.util.List;

import org.openxmlformats.schemas.drawingml.x2006.chart.CTAxDataSource;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTDPt;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTLineChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTLineSer;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumDataSource;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;

/**
 * Line Chart.
 *
 * @author JASON JIANG
 *
 */
public class LineChart implements ChartObject {

	/** empty list. */
	private List<CTDPt> emptyDptlist = new ArrayList<>();

	/** empty list. */
	private List<CTLineSer> emptyLinelist = new ArrayList<>();

	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getChartListFromCtChart
	 * (org.openxmlformats.schemas.drawingml.x2006.chart.CTChart)
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public final List getChartListFromCtChart(final CTChart ctChart) {
		return ctChart.getPlotArea().getLineChartList();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getSerListFromCtObjChart(java.lang.Object)
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public final List getSerListFromCtObjChart(final Object ctObjChart) {

		if (ctObjChart instanceof CTLineChart) {
			return ((CTLineChart) ctObjChart).getSerList();
		}
		return emptyLinelist;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getCtAxDataSourceFromSerList(java.util.List)
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public final CTAxDataSource getCtAxDataSourceFromSerList(
			final List serList) {

		if ((serList != null) && (!serList.isEmpty())
				&& (serList.get(0) instanceof CTLineSer)) {
			return ((CTLineSer) serList.get(0)).getCat();
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getSeriesLabelFromCTSer(java.lang.Object)
	 */
	@Override
	public final String getSeriesLabelFromCTSer(final Object ctObjSer) {
		if (ctObjSer instanceof CTLineSer) {
			return ((CTLineSer) ctObjSer).getTx().getStrRef().getF();
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getShapePropertiesFromCTSer(java.lang.Object)
	 */
	@Override
	public final CTShapeProperties getShapePropertiesFromCTSer(
			final Object ctObjSer) {
		if (ctObjSer instanceof CTLineSer) {
			return ((CTLineSer) ctObjSer).getSpPr();
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getCTNumDataSourceFromCTSer(java.lang.Object)
	 */
	@Override
	public final CTNumDataSource getCTNumDataSourceFromCTSer(
			final Object ctObjSer) {
		if (ctObjSer instanceof CTLineSer) {
			return ((CTLineSer) ctObjSer).getVal();
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getDPtListFromCTSer(java.lang.Object)
	 */
	@Override
	public final List<CTDPt> getDPtListFromCTSer(final Object ctObjSer) {
		return emptyDptlist;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.tiefaces.components.websheet.chart.objects.ChartObject#isLineColor()
	 */
	@Override
	public final boolean isLineColor() {
		return true;
	}

}


/*
 * Copyright 2017 TieFaces.
 * Licensed under MIT
 */

package org.tiefaces.components.websheet.utility;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;

import org.apache.poi.ss.usermodel.Cell;
import org.tiefaces.common.TieConstants;
import org.tiefaces.components.websheet.dataobjects.CellAttributesMap;
import org.tiefaces.components.websheet.dataobjects.CellFormAttributes;

/**
 * Helper class for web sheet cells.
 *
 * @author Jason Jiang
 *
 */
public final class ParserUtility {

	/**
	 * Instantiates a new cell helper.
	 */
	private ParserUtility() {
		// not called.
	}

	/**
	 * check it's a command comment.
	 *
	 * @param str
	 *            comment string.
	 * @return ture if it's command.
	 */
	public static boolean isCommandString(final String str) {
		if (str == null) {
			return false;
		}
		return str.startsWith(TieConstants.COMMAND_PREFIX);
	}

	/**
	 * method string is start as $ follow by method name then with { and }. i.e.
	 * $init{department.name}
	 *
	 * @param str
	 *            the str
	 * @return true, if is method string
	 */
	public static boolean isMethodString(final String str) {
		if (str == null) {
			return false;
		}
		return str.matches(TieConstants.METHOD_REGEX);
	}

	/**
	 * empty method string is start as $ follow with { and }. i.e.
	 * ${department.name}
	 *
	 * @param str
	 *            the str
	 * @return true, if is empty method string
	 */
	public static boolean isEmptyMethodString(final String str) {
		if (str == null) {
			return false;
		}
		return str.startsWith(TieConstants.METHOD_PREFIX);
	}

	/**
	 * widget method start with $widget. e.g. $widget.calendar{....
	 *
	 * @param str
	 *            the str
	 * @return true, if is widget method string
	 */
	public static boolean isWidgetMethodString(final String str) {
		if (str == null) {
			return false;
		}
		return str.startsWith(TieConstants.METHOD_WIDGET_PREFIX);
	}

	/**
	 * validate method start with $validate{ rule="..." error="..."}.
	 *
	 * @param str
	 *            the str.
	 * @return true, if is validate method string.
	 */
	public static boolean isValidateMethodString(final String str) {
		if (str == null) {
			return false;
		}
		return str.startsWith(TieConstants.METHOD_VALIDATE_PREFIX);
	}

	/**
	 * Parses the widget attributes.
	 *
	 * @param cell
	 *            the cell
	 * @param newComment
	 *            the new comment
	 * @param cellAttributesMap
	 *            the cell attributes map
	 */
	public static void parseWidgetAttributes(final Cell cell,
			final String newComment,
			final CellAttributesMap cellAttributesMap) {

		if ((newComment == null) || (newComment.isEmpty())) {
			return;
		}
		int widgetStart = newComment
				.indexOf(TieConstants.METHOD_WIDGET_PREFIX);
		int elStart = newComment.indexOf(TieConstants.EL_START_BRACKET);
		if ((widgetStart < 0) || (widgetStart >= elStart)) {
			return;
		}

		String type = newComment.substring(
				widgetStart + TieConstants.METHOD_WIDGET_PREFIX.length(),
				elStart);

		String values = getStringBetweenBracket(newComment);
		if (values == null) {
			return;
		}
		// map's key is sheetName!$columnIndex$rowIndex
		String key = getAttributeKeyInMapByCell(cell);
		// one cell only has one control widget
		cellAttributesMap.getCellInputType().put(key, type);
		List<CellFormAttributes> inputs = cellAttributesMap
				.getCellInputAttributes().get(key);
		if (inputs == null) {
			inputs = new ArrayList<>();
			cellAttributesMap.getCellInputAttributes().put(key, inputs);
		}
		parseInputAttributes(inputs, values);

		parseSpecialAttributes(key, type, inputs, cellAttributesMap);

	}

	/**
	 * get attribute key in map by cell.
	 *
	 * @param cell
	 *            input cell.
	 * @return key.
	 */

	public static String getAttributeKeyInMapByCell(final Cell cell) {
		if (cell == null) {
			return null;
		}
		// map's key is sheetName!$columnIndex$rowIndex
		return cell.getSheet().getSheetName() + "!"
				+ CellUtility.getCellIndexNumberKey(cell);

	}

	/**
	 * Parses the validate attributes.
	 *
	 * @param cell
	 *            the cell
	 * @param newComment
	 *            the new comment
	 * @param cellAttributesMap
	 *            the cell attributes map
	 */
	public static void parseValidateAttributes(final Cell cell,
			final String newComment,
			final CellAttributesMap cellAttributesMap) {

		if ((newComment == null) || (newComment.isEmpty())) {
			return;
		}
		if (!newComment.startsWith(TieConstants.METHOD_VALIDATE_PREFIX)) {
			return;
		}

		String values = getStringBetweenBracket(newComment);
		if (values == null) {
			return;
		}
		// map's key is sheetName!$columnIndex$rowIndex
		String key = getAttributeKeyInMapByCell(cell);
		List<CellFormAttributes> attrs = cellAttributesMap
				.getCellValidateAttributes().get(key);
		if (attrs == null) {
			attrs = new ArrayList<>();
			cellAttributesMap.getCellValidateAttributes().put(key, attrs);
		}
		parseValidateAttributes(attrs, values);

	}

	/**
	 * get the string between two bracket. .e.g. $save{employee.name} return
	 * employee.name.
	 *
	 * @param newComment the new comment
	 * @return return string.
	 */

	public static String getStringBetweenBracket(final String newComment) {

		if (newComment == null) {
			return null;
		}
		int elStart = newComment.indexOf(TieConstants.EL_START_BRACKET);
		int elEnd = findPairBracketPosition(newComment, elStart);
		if (elStart >= elEnd) {
			return null;
		}

		return newComment.substring(elStart + 1, elEnd);

	}

	/**
	 * Find pair bracket position.
	 *
	 * @param str the str
	 * @param startPos the start pos
	 * @return the int
	 */
	private static int findPairBracketPosition(final String str, final int startPos) {

		int bracketNum = 0;
	    for (int i = startPos; i < str.length(); i++)
	    {
	        char current = str.charAt(i);
	        if (current == TieConstants.EL_START_BRACKET)
	        {
	            bracketNum++;
	        } else if (current == TieConstants.EL_END )
	        {
	        	bracketNum--;
	        	if (bracketNum <=0 ) {
	                return i;
	        	}
	        }
	    }
	    return -1;
	}

	/**
	 * Parse the attributes from string.
	 *
	 * @param attrString
	 *            command string.
	 * @return attributes map.
	 */
	public static Map<String, String> parseCommandAttributes(
			final String attrString) {
		Map<String, String> attrMap = new LinkedHashMap<>();
		Matcher attrMatcher = TieConstants.ATTR_REGEX_PATTERN
				.matcher(attrString);
		while (attrMatcher.find()) {
			String attrData = attrMatcher.group();
			int attrNameEndIndex = attrData.indexOf('=');
			String attrName = attrData.substring(0, attrNameEndIndex)
					.trim();
			String attrValuePart = attrData.substring(attrNameEndIndex + 1)
					.trim();
			String attrValue = attrValuePart.substring(1,
					attrValuePart.length() - 1);
			attrMap.put(attrName, attrValue);
		}
		return attrMap;
	}

	/**
	 * parse input attributes.
	 *
	 * @param clist
	 *            list of cellformattributes.
	 * @param controlAttrs
	 *            control attrs.
	 */
	public static void parseInputAttributes(
			final List<CellFormAttributes> clist,
			final String controlAttrs) {
		// only one type control allowed for one cell.
		clist.clear();
		if (controlAttrs != null) {
			String[] cattrs = controlAttrs.split(
					TieConstants.SPLIT_SPACE_SEPERATE_ATTRS_REGX, -1);
			for (String cattr : cattrs) {
				String[] details = splitByEualSign(cattr);
				if (details.length > 1) {
					CellFormAttributes attr = new CellFormAttributes();
					attr.setType(details[0].trim());
					attr.setValue(details[1].replaceAll("\"", ""));
					clist.add(attr);
				}
			}
		}
	}

	/**
	 * parse validate attributes.
	 *
	 * @param clist
	 *            list of cellformattributes.
	 * @param controlAttrs
	 *            control attrs.
	 */
	public static void parseValidateAttributes(
			final List<CellFormAttributes> clist,
			final String controlAttrs) {
		// one cell could have multiple validation rules.
		if (controlAttrs == null) {
			return;
		}
		String[] cattrs = controlAttrs
				.split(TieConstants.SPLIT_SPACE_SEPERATE_ATTRS_REGX, -1);

		CellFormAttributes attr = new CellFormAttributes();
		for (String cattr : cattrs) {
			extractValidationAttributes(attr, cattr);
		}
		if ((attr.getValue() != null) && (!attr.getValue().isEmpty())) {
			clist.add(attr);
		}
	}

	/**
	 *  extractValidationAttributes.
	 * @param attr attribute holder.
	 * @param cattr input attributes.
	 */
	private static void extractValidationAttributes(
			final CellFormAttributes attr, final String cattr) {
		String[] details = splitByEualSign(cattr);
		if (details.length > 1) {
			if (details[0].equalsIgnoreCase(
					TieConstants.VALIDATION_RULE_TAG)) {
				attr.setValue(details[1].replaceAll("\"", ""));
			} else if (details[0].equalsIgnoreCase(
					TieConstants.VALIDATION_ERROR_MSG_TAG)) {
				attr.setMessage(details[1].replaceAll("\"", ""));
			}
		}
	}

	/**
	 * split string by = sign.
	 *
	 * @param attrData
	 *            string.
	 * @return splitted string array.
	 */
	private static String[] splitByEualSign(final String attrData) {
		int attrNameEndIndex = attrData.indexOf('=');
		if (attrNameEndIndex < 0) {
			return new String[0];
		}
		String attrName = attrData.substring(0, attrNameEndIndex).trim();
		String attrValue = attrData.substring(attrNameEndIndex + 1).trim();
		String[] rlist = new String[2];
		rlist[0] = attrName;
		rlist[1] = attrValue;
		return rlist;
	}

	/**
	 * The Class SpecialAttributes.
	 */
	private static class SpecialAttributes {

		/** The select labels. */
		private String[] selectLabels;

		/** The select values. */
		private String[] selectValues = null;

		/** The default select label. */
		private String defaultSelectLabel = null;

		/** The default select value. */
		private String defaultSelectValue = null;

		/** The default date pattern. */
		private String defaultDatePattern = "";

	}

	/**
	 * parse select item attributes.
	 *
	 * @param key
	 *            key.
	 * @param type
	 *            type.
	 * @param inputs
	 *            inputs.
	 * @param cellAttributesMap
	 *            cellattributesmap.
	 */
	public static void parseSpecialAttributes(final String key,
			final String type, final List<CellFormAttributes> inputs,
			final CellAttributesMap cellAttributesMap) {

		SpecialAttributes sAttr = new SpecialAttributes();

		for (CellFormAttributes attr : inputs) {
			gatherSpecialAttributes(type, sAttr, attr);
		}

		if (sAttr.selectLabels != null) {
			processSelectItemAttributes(key, cellAttributesMap, sAttr);
		}
		if (type.equalsIgnoreCase(TieConstants.WIDGET_CALENDAR)) {
			processCalendarAttributes(key, cellAttributesMap, sAttr);
		}
	}

	/**
	 * Process calendar attributes.
	 *
	 * @param key
	 *            the key
	 * @param cellAttributesMap
	 *            the cell attributes map
	 * @param sAttr
	 *            the s attr
	 */
	private static void processCalendarAttributes(final String key,
			final CellAttributesMap cellAttributesMap,
			final SpecialAttributes sAttr) {
		cellAttributesMap.getCellDatePattern().put(key,
				sAttr.defaultDatePattern);
	}

	/**
	 * Process select item attributes.
	 *
	 * @param key
	 *            the key
	 * @param cellAttributesMap
	 *            the cell attributes map
	 * @param sAttr
	 *            the s attr
	 */
	private static void processSelectItemAttributes(final String key,
			final CellAttributesMap cellAttributesMap,
			final SpecialAttributes sAttr) {
		if ((sAttr.selectValues == null)
				|| (sAttr.selectValues.length != sAttr.selectLabels.length)) {
			sAttr.selectValues = sAttr.selectLabels;
		}
		Map<String, String> smap = cellAttributesMap
				.getCellSelectItemsAttributes().get(key);
		if (smap == null) {
			smap = new LinkedHashMap<>();
		}
		smap.clear();
		if (sAttr.defaultSelectLabel != null) {
			smap.put(sAttr.defaultSelectLabel, sAttr.defaultSelectValue);
		}
		for (int i = 0; i < sAttr.selectLabels.length; i++) {
			smap.put(sAttr.selectLabels[i], sAttr.selectValues[i]);
		}
		cellAttributesMap.getCellSelectItemsAttributes().put(key, smap);
	}

	/**
	 * Gather special attributes.
	 *
	 * @param type
	 *            the type
	 * @param sAttr
	 *            the s attr
	 * @param attr
	 *            the attr
	 */
	private static void gatherSpecialAttributes(final String type,
			final SpecialAttributes sAttr, final CellFormAttributes attr) {
		String attrKey = attr.getType();
		if (attrKey.equalsIgnoreCase(TieConstants.SELECT_ITEM_LABELS)) {
			sAttr.selectLabels = attr.getValue().split(";");
		}
		if (attrKey.equalsIgnoreCase(TieConstants.SELECT_ITEM_VALUES)) {
			sAttr.selectValues = attr.getValue().split(";");
		}
		if (attrKey.equalsIgnoreCase(
				TieConstants.DEFAULT_SELECT_ITEM_LABEL)) {
			sAttr.defaultSelectLabel = attr.getValue();
		}
		if (attrKey.equalsIgnoreCase(
				TieConstants.DEFAULT_SELECT_ITEM_VALUE)) {
			sAttr.defaultSelectValue = attr.getValue();
		}
		if (type.equalsIgnoreCase(TieConstants.WIDGET_CALENDAR)
				&& attrKey.equalsIgnoreCase(
						TieConstants.WIDGET_ATTR_PATTERN)) {
			sAttr.defaultDatePattern = attr.getValue();
		}
	}

	/**
	 * Parse Comment To Map
	 *
	 * Normal comment : key $$ Not Normal comment: key e.g. $save
	 *
	 * @param cellKey
	 *            cellKey.
	 * @param newComment
	 *            updated comment.
	 * @param sheetCommentMap
	 *            the sheet comment map.
	 * @param normalComment
	 *            the normal comment.
	 */
	public static void parseCommentToMap(final String cellKey,
			final String newComment,
			final Map<String, Map<String, String>> sheetCommentMap,
			final boolean normalComment) {
		if ((newComment != null) && (!newComment.trim().isEmpty())) {
			// normal comment key is $$
			String commentKey = TieConstants.NORMAL_COMMENT_KEY_IN_MAP;
			if (!normalComment) {
				// not normal comment. e.g. ${... or $init{... or
				// key = $ or key = $init
				commentKey = newComment.substring(0,
						newComment.indexOf(TieConstants.EL_START_BRACKET));
			}
			Map<String, String> map = sheetCommentMap.get(commentKey);
			if (map == null) {
				map = new HashMap<>();
			}
			// inner map's key is sheetName!$columnIndex$rowIndex
			map.put(cellKey, newComment);
			sheetCommentMap.put(commentKey, map);
		}
	}

	/**
	 * find first non letterordigit position from string.
	 *
	 * @param input input string
	 * @param startPosition startposition
	 * @return first position
	 */

	public static int findFirstNonCellNamePosition(String input, int startPosition) {
		char c;
	    for (int i = startPosition; i < input.length(); i++) {
	    	c = input.charAt(i);
	        if ( c!='$' && !Character.isLetterOrDigit(c)) {
	            return i;
	        }
	    }
	    return -1; // not found
	}

	/**
	 * Convert wildcard expression into regex experssion.
	 *
	 * @param wildcard input wildcard
	 * @return regex string.
	 */
    public static String wildcardToRegex(String wildcard){
    	return wildcardToRegex(wildcard,false);
    }

    /**
     * Convert wildcard expression into regex experssion with option check start and end.
     *
     * @param wildcard input wildcard.
     * @param checkStartEnd check start and end.
     * @return regex string.
     */
    public static String wildcardToRegex(String wildcard, boolean checkStartEnd){
        StringBuilder s = new StringBuilder(wildcard.length());

        if (checkStartEnd) {
        	s.append('^');
        }
        for (int i = 0, is = wildcard.length(); i < is; i++) {
            char c = wildcard.charAt(i);
            switch(c) {
                case '*':
                    s.append(".*");
                    break;
                case '?':
                    s.append(".");
                    break;
                    // escape special regexp-characters
                case '(': case ')': case '[': case ']': case '$':
                case '^': case '.': case '{': case '}': case '|':
                case '\\':
                    s.append("\\");
                    s.append(c);
                    break;
                default:
                    s.append(c);
                    break;
            }
        }
        if (checkStartEnd) {
        	s.append('$');
        }
        return(s.toString());
    }

    /**
     * Removes the chars from string.
     *
     * @param inputStr the input str
     * @param start the start
     * @param end the end
     * @return the string
     */
    public static String removeCharsFromString(String inputStr, int start, int end) {
    	 StringBuilder sb = new StringBuilder(inputStr);
    	 sb.delete(start, end);
//    	 if ((start > 0) && (inputStr.charAt(start - 1) ==' ')) {
//    		 // if end with a space, then remove it as well.
//    		 sb.deleteCharAt(start - 1);
//    	 }
    	 return sb.toString();
    }

}


/*
 * Copyright 2017 TieFaces.
 * Licensed under MIT
 */

package org.tiefaces.components.websheet.utility;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetDimension;
import org.tiefaces.common.TieConstants;
import org.tiefaces.components.websheet.configuration.ConfigRange;

import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * The Class TieWebSheetUtility.
 */
public final class WebSheetUtility {

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

	// Each cell conatins a fixed number of co-ordinate points; this number
	// does not vary with row height or column width or with font. These two
	/** The Constant TOTAL_COLUMN_COORDINATE_POSITIONS. */
	// constants are defined below.
	public static final int TOTAL_COLUMN_COORDINATE_POSITIONS = 1023; // MB

	/** The Constant TOTAL_ROW_COORDINATE_POSITIONS. */
	public static final int TOTAL_ROW_COORDINATE_POSITIONS = 255; // MB
	// The resoultion of an image can be expressed as a specific number
	// of pixels per inch. Displays and printers differ but 96 pixels per
	/** The Constant PIXELS_PER_INCH. */
	// inch is an acceptable standard to beging with.
	public static final int PIXELS_PER_INCH = 96; // MB
	/** The Constant MILLIMETERS_PER_INCH. */
	public static final double MILLIMETERS_PER_INCH = 25.4;
	/** The Constant POINTS_PER_INCH. */
	public static final double POINTS_PER_INCH = 72D;
	// Cnstants that defines how many pixels and points there are in a
	/** The Constant PIXELS_PER_MILLIMETRES. */
	// millimetre. These values are required for the conversion algorithm.
	public static final double PIXELS_PER_MILLIMETRES = 3.78; // MB

	/** The Constant PICTURE_HEIGHT_ADJUST. */
	// These values are required for the conversion algorithm.
	public static final double PICTURE_HEIGHT_ADJUST = 3.03125; // MB

	/** The Constant POINTS_PER_MILLIMETRE. */
	public static final double POINTS_PER_MILLIMETRE = 2.83; // MB
	// The column width returned by HSSF and the width of a picture when
	// positioned to exactly cover one cell are different by almost exactly
	// 2mm - give or take rounding errors. This constant allows that
	// additional amount to be accounted for when calculating how many
	/** The Constant CELL_BORDER_WIDTH_MILLIMETRES. */
	// celles the image ought to overlie.
	public static final double CELL_BORDER_WIDTH_MILLIMETRES = 2.0D; // MB

	/** The Constant EXCEL_COLUMN_WIDTH_FACTOR. */
	public static final short EXCEL_COLUMN_WIDTH_FACTOR = 256;

	/** The Constant UNIT_OFFSET_LENGTH. */
	public static final int UNIT_OFFSET_LENGTH = 7;

	/** The Constant UNIT_OFFSET_MAP. */
	static final int[] UNIT_OFFSET_MAP = new int[] { 0, 36, 73, 109, 146,
			182, 219 };

	/** The Constant EXCEL_ROW_HEIGHT_FACTOR. */
	public static final short EXCEL_ROW_HEIGHT_FACTOR = 20;

	/** The Constant EMU_PER_MM. */
	public static final int EMU_PER_MM = 36000;

	/** The Constant EMU_PER_POINTS. */
	public static final int EMU_PER_POINTS = 12700;

	/** The Constant DATE_REGEX_YEAR_COMM_1. */
	private static final String DATE_REGEX_YEAR_COMM_1 = "([-/.\\\\]{1})";

	/** The Constant DATE_REGEX_YEAR_COMM_2. */
	private static final String DATE_REGEX_YEAR_COMM_2 = "[0?[1-9]|[1-9]|1[012]]{1,2}";

	/** The Constant DATE_REGEX_YEAR_COMM_3. */
	private static final String DATE_REGEX_YEAR_COMM_3 = "([0?[1-9]|[1-9]|1[0-9]|2[0-9]|3[01]]{1,2})";

	/** The Constant DATE_REGEX_4_DIGIT_YEAR. */
	private static final String DATE_REGEX_4_DIGIT_YEAR = "("
			+ "(19|20)[0-9]{2}" + DATE_REGEX_YEAR_COMM_1
			+ DATE_REGEX_YEAR_COMM_2 + "\\3" + DATE_REGEX_YEAR_COMM_3 + ")"
			+ "|" + "(" + DATE_REGEX_YEAR_COMM_2 + DATE_REGEX_YEAR_COMM_1
			+ DATE_REGEX_YEAR_COMM_3 + "\\6" + "(19|20)[0-9]{2}" + ")";

	/** The Constant DATE_REGEX_2_DIGIT_YEAR. */
	private static final String DATE_REGEX_2_DIGIT_YEAR = "(" + "[0-9]{2}"
			+ DATE_REGEX_YEAR_COMM_1 + DATE_REGEX_YEAR_COMM_2 + "\\3"
			+ DATE_REGEX_YEAR_COMM_3 + ")" + "|" + "("
			+ DATE_REGEX_YEAR_COMM_2 + DATE_REGEX_YEAR_COMM_1
			+ DATE_REGEX_YEAR_COMM_3 + "\\6" + "[0-9]{2}" + ")";

	/**
	 * PIXEL_HEIGHT_ASPC_ADJUST.
	 */
	private static final double PIXEL_HEIGHT_ASPC_ADJUST = 14;

	/**
	 * hide constructor.
	 */
	private WebSheetUtility() {
		// not called
	}

	/**
	 * Gets the excel column name.
	 *
	 * @param pnumber
	 *            the number
	 * @return the string
	 */
	public static String getExcelColumnName(final int pnumber) {
		StringBuilder converted = new StringBuilder();
		// Repeatedly divide the number by 26 and convert the
		// remainder into the appropriate letter.
		int number = pnumber;
		while (number >= 0) {
			int remainder = number % TieConstants.EXCEL_LETTER_NUMBERS;
			converted.insert(0, (char) (remainder + 'A'));
			number = (number / TieConstants.EXCEL_LETTER_NUMBERS) - 1;
		}

		return converted.toString();
	}

	/**
	 * return full name for cell with sheet name and $ format e.g. Sheet1$A$1
	 *
	 * @param sheet1
	 *            sheet
	 * @param cell
	 *            cell
	 * @return String full cell reference name
	 */

	public static String getFullCellRefName(final Sheet sheet1,
			final Cell cell) {
		if ((sheet1 != null) && (cell != null)) {
			return sheet1.getSheetName() + "!$"
					+ getExcelColumnName(cell.getColumnIndex()) + "$"
					+ (cell.getRowIndex() + 1);
		}
		return null;
	}

	/**
	 * return full name for cell with sheet name and $ format e.g. Sheet1$A$1
	 *
	 * @param sheetName
	 *            the sheet name
	 * @param rowIndex
	 *            the row index
	 * @param colIndex
	 *            the col index
	 * @return String full cell reference name
	 */

	public static String getFullCellRefName(final String sheetName,
			final int rowIndex, final int colIndex) {
		if (sheetName != null) {
			return sheetName + "!$" + getExcelColumnName(colIndex) + "$"
					+ (rowIndex + 1);
		}
		return null;
	}

	/**
	 * return sheet name from cell full name e.g. return Sheet1 from Sheet1$A$1
	 *
	 * @param fullName
	 *            the full name
	 * @return String Sheet Name
	 */

	public static String getSheetNameFromFullCellRefName(
			final String fullName) {
		if ((fullName != null) && (fullName.contains("!"))) {
			return fullName.substring(0, fullName.indexOf('!'));
		}
		return null;
	}

	/**
	 * remove sheet name from cell full name e.g. return $A$1 from Sheet1$A$1
	 *
	 * @param fullName
	 *            the full name
	 * @return remove Sheet Name from full name
	 */

	public static String removeSheetNameFromFullCellRefName(
			final String fullName) {
		if ((fullName != null) && (fullName.contains("!"))) {
			return fullName.substring(fullName.indexOf('!') + 1);
		}
		return fullName;
	}

	/**
	 * Convert col to int.
	 *
	 * @param col
	 *            the col
	 * @return the int
	 */
	public static int convertColToInt(final String col) {
		String name = col.toUpperCase();
		int number = 0;
		int pow = 1;
		for (int i = name.length() - 1; i >= 0; i--) {
			number += (name.charAt(i) - 'A' + 1) * pow;
			pow *= TieConstants.EXCEL_LETTER_NUMBERS;
		}

		return number - 1;
	}

	/**
	 * Gets the cell by reference.
	 *
	 * @param cellRef
	 *            the cell ref
	 * @param sheet
	 *            the sheet
	 * @return the cell by reference
	 */
	public static Cell getCellByReference(final String cellRef,
			final Sheet sheet) {

		Cell c = null;
		try {
			CellReference ref = new CellReference(cellRef);
			Row r = sheet.getRow(ref.getRow());
			if (r != null) {
				c = r.getCell(ref.getCol(),
						MissingCellPolicy.CREATE_NULL_AS_BLANK);
			}
		} catch (Exception ex) {
			// use log.debug because mostly it's expected
			LOG.log(Level.SEVERE,
					"WebForm WebFormHelper getCellByReference cellRef = "
							+ cellRef + "; error = "
							+ ex.getLocalizedMessage(),
					ex);
		}
		return c;
	}

	/**
	 * pixel units to excel width units(units of 1/256th of a character width).
	 *
	 * @param pxs
	 *            the pxs
	 * @return the short
	 */
	public static short pixel2WidthUnits(final int pxs) {
		short widthUnits = (short) (EXCEL_COLUMN_WIDTH_FACTOR
				* (pxs / UNIT_OFFSET_LENGTH));
		widthUnits += UNIT_OFFSET_MAP[pxs % UNIT_OFFSET_LENGTH];
		return widthUnits;
	}

	/**
	 * excel width units(units of 1/256th of a character width) to pixel units.
	 *
	 * @param widthUnits
	 *            the width units
	 * @return the int
	 */
	public static int widthUnits2Pixel(final int widthUnits) {
		int pixels = (widthUnits / EXCEL_COLUMN_WIDTH_FACTOR)
				* UNIT_OFFSET_LENGTH;
		int offsetWidthUnits = widthUnits % EXCEL_COLUMN_WIDTH_FACTOR;
		pixels += Math.round(offsetWidthUnits
				/ ((float) EXCEL_COLUMN_WIDTH_FACTOR / UNIT_OFFSET_LENGTH));
		return pixels;
	}

	/**
	 * Height units 2 pixel.
	 *
	 * @param heightUnits
	 *            the height units
	 * @return the int
	 */
	public static int heightUnits2Pixel(final short heightUnits) {
		int pixels = heightUnits / EXCEL_ROW_HEIGHT_FACTOR;
		int offsetHeightUnits = heightUnits % EXCEL_ROW_HEIGHT_FACTOR;
		pixels += Math.round((float) offsetHeightUnits
				/ ((float) EXCEL_COLUMN_WIDTH_FACTOR / UNIT_OFFSET_LENGTH
						/ 2));
		pixels += (Math.floor(pixels / PIXEL_HEIGHT_ASPC_ADJUST) + 1) * 4;

		return pixels;
	}

	/**
	 * Convert Excels width units into millimetres.
	 *
	 * @param widthUnits
	 *            The width of the column or the height of the row in Excels
	 *            units.
	 * @return A primitive double that contains the columns width or rows height
	 *         in millimetres.
	 */
	public static double widthUnits2Millimetres(final short widthUnits) {
		return widthUnits2Pixel(widthUnits) / PIXELS_PER_MILLIMETRES;
	}

	/**
	 * Convert into millimetres Excels width units..
	 *
	 * @param millimetres
	 *            A primitive double that contains the columns width or rows
	 *            height in millimetres.
	 * @return A primitive int that contains the columns width or rows height in
	 *         Excels units.
	 */
	public static int millimetres2WidthUnits(final double millimetres) {
		return pixel2WidthUnits(
				(int) (millimetres * PIXELS_PER_MILLIMETRES));
	}

	/**
	 * Points to pixels.
	 *
	 * @param points
	 *            the points
	 * @return the int
	 */
	public static int pointsToPixels(final double points) {
		return (int) Math.round(points / POINTS_PER_INCH * PIXELS_PER_INCH);
	}

	/**
	 * Points to millimeters.
	 *
	 * @param points
	 *            the points
	 * @return the double
	 */
	public static double pointsToMillimeters(final double points) {
		return points / POINTS_PER_INCH * MILLIMETERS_PER_INCH;
	}

	/**
	 * Checks if is date.
	 *
	 * @param s
	 *            the s
	 * @return true, if is date
	 */
	public static boolean isDate(final String s) {
		Pattern pattern = Pattern.compile(DATE_REGEX_4_DIGIT_YEAR);
		String[] terms = s.split(" ");
		Matcher matcher;
		for (String term : terms) {
			matcher = pattern.matcher(term);
			if (matcher.matches()) {
				return true;
			}
		}
		pattern = Pattern.compile(DATE_REGEX_2_DIGIT_YEAR);
		terms = s.split(" ");
		for (String term : terms) {
			matcher = pattern.matcher(term);
			if (matcher.matches()) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Parses the date.
	 *
	 * @param entry
	 *            the entry
	 * @return the string
	 */
	public static String parseDate(final String entry) {
		Pattern pattern = Pattern.compile(DATE_REGEX_4_DIGIT_YEAR);
		String[] terms = entry.split(" ");
		Matcher matcher;
		for (String term : terms) {
			matcher = pattern.matcher(term);
			if (matcher.matches()) {
				return matcher.group();
			}
		}
		pattern = Pattern.compile(DATE_REGEX_2_DIGIT_YEAR);
		terms = entry.split(" ");
		for (String term : terms) {
			matcher = pattern.matcher(term);
			if (matcher.matches()) {
				return matcher.group();
			}
		}
		return "";
	}

	/**
	 * Checks if is numeric.
	 *
	 * @param str
	 *            the str
	 * @return true, if is numeric
	 */
	public static boolean isNumeric(final String str) {

		String s = str;
		if (s.startsWith("-")) {
			s = s.substring(1);
		}
		char c;
		int i;
		int sLen = s.length();
		ShouldContinueParameter sPara = new ShouldContinueParameter(false,
				false, 0);

		for (i = 0; i < sLen; i++) {
			c = s.charAt(i);
			if (c < '0' || c > '9') {
				if (!shouldContinue(c, sPara)) {
					return false;
				}
			} else {
				if (sPara.isCommaHit()) {
					sPara.setSinceLastComma(sPara.getSinceLastComma() + 1);
				}
			}
		}
		return true;
	}

	/**
	 * The Class ShouldContinueParameter.
	 */
	private static class ShouldContinueParameter {

		/** The decimal hit. */
		private Boolean decimalHit;

		/** The comma hit. */
		private Boolean commaHit;

		/** The since last comma. */
		private Integer sinceLastComma;

		/**
		 * Instantiates a new should continue parameter.
		 *
		 * @param pdecimalHit
		 *            the decimal hit
		 * @param pcommaHit
		 *            the comma hit
		 * @param psinceLastComma
		 *            the since last comma
		 */
		ShouldContinueParameter(final Boolean pdecimalHit,
				final Boolean pcommaHit, final Integer psinceLastComma) {
			this.decimalHit = pdecimalHit;
			this.commaHit = pcommaHit;
			this.sinceLastComma = psinceLastComma;
		}

		/**
		 * Checks if is decimal hit.
		 *
		 * @return the boolean
		 */
		public Boolean isDecimalHit() {
			return decimalHit;
		}

		/**
		 * Sets the decimal hit.
		 *
		 * @param pdecimalHit
		 *            the new decimal hit
		 */
		public void setDecimalHit(final Boolean pdecimalHit) {
			this.decimalHit = pdecimalHit;
		}

		/**
		 * Checks if is comma hit.
		 *
		 * @return the boolean
		 */
		public Boolean isCommaHit() {
			return commaHit;
		}

		/**
		 * Sets the comma hit.
		 *
		 * @param pcommaHit
		 *            the new comma hit
		 */
		public void setCommaHit(final Boolean pcommaHit) {
			this.commaHit = pcommaHit;
		}

		/**
		 * Gets the since last comma.
		 *
		 * @return the since last comma
		 */
		public Integer getSinceLastComma() {
			return sinceLastComma;
		}

		/**
		 * Sets the since last comma.
		 *
		 * @param psinceLastComma
		 *            the new since last comma
		 */
		public void setSinceLastComma(final Integer psinceLastComma) {
			this.sinceLastComma = psinceLastComma;
		}
	}

	/**
	 * Should continue.
	 *
	 * @param c
	 *            the c
	 * @param para
	 *            the para
	 * @return true, if successful
	 */
	private static boolean shouldContinue(final char c,
			final ShouldContinueParameter para) {
		if (c == '.' && !para.isDecimalHit()) {
			para.setDecimalHit(true);
			if (para.isCommaHit() && para.getSinceLastComma() != 3) {
				return false;
			}
			return true;
		} else if (c == ',' && !para.isDecimalHit()) {
			if (para.isCommaHit()) {
				if (para.getSinceLastComma() != 3) {
					return false;
				}
				para.setSinceLastComma(0);
			}
			para.setCommaHit(true);
			return true;
		}
		return false;
	}

	/**
	 * Sets the object property.
	 *
	 * @param obj
	 *            the obj
	 * @param propertyName
	 *            the property name
	 * @param propertyValue
	 *            the property value
	 * @param ignoreNonExisting
	 *            the ignore non existing
	 */
	public static void setObjectProperty(final Object obj,
			final String propertyName, final String propertyValue,
			final boolean ignoreNonExisting) {
		try {
			Method method = obj.getClass().getMethod(
					"set" + Character.toUpperCase(propertyName.charAt(0))
							+ propertyName.substring(1),
					new Class[] { String.class });
			method.invoke(obj, propertyValue);
		} catch (Exception e) {
			String msg = "failed to set property '" + propertyName
					+ "' to value '" + propertyValue + "' for object "
					+ obj;
			if (ignoreNonExisting) {
				LOG.info(msg);
			} else {
				LOG.warning(msg);
				throw new IllegalArgumentException(e);
			}
		}
	}

	/**
	 * Cell compare to.
	 *
	 * @param thisCell
	 *            the this cell
	 * @param otherCell
	 *            the other cell
	 * @return the int
	 */
	public static int cellCompareTo(final Cell thisCell,
			final Cell otherCell) {
		int r = thisCell.getRowIndex() - otherCell.getRowIndex();
		if (r != 0) {
			return r;
		}

		r = thisCell.getColumnIndex() - otherCell.getColumnIndex();
		if (r != 0) {
			return r;
		}

		return 0;
	}

	/**
	 * Inside range.
	 *
	 * @param child
	 *            the child
	 * @param parent
	 *            the parent
	 * @return true, if successful
	 */
	public static boolean insideRange(final ConfigRange child,
			final ConfigRange parent) {

		return ((cellCompareTo(child.getFirstRowRef(),
				parent.getFirstRowRef()) >= 0)
				&& (cellCompareTo(child.getLastRowPlusRef(),
						parent.getLastRowPlusRef()) <= 0));
	}

	/**
	 * return the last column of the sheet.
	 *
	 * @param sheet
	 *            sheet.
	 * @return last column number (A column will return 0).
	 */
	public static int getSheetRightCol(final Sheet sheet) {

		try {
			if (sheet instanceof XSSFSheet) {
				XSSFSheet xsheet = (XSSFSheet) sheet;
				int rightCol = getSheetRightColFromDimension(xsheet);
				if (rightCol > TieConstants.MAX_COLUMNS_IN_SHEET) {
					clearHiddenColumns(sheet);
					rightCol = getSheetRightColFromDimension(xsheet);
				}
				return rightCol;

			}
		} catch (Exception e) {
			LOG.log(Level.SEVERE, "error in getSheetRightCol : "
					+ e.getLocalizedMessage(), e);
		}
		return -1;
	}

	/**
	 * Clear hidden columns.
	 *
	 * @param sheet
	 *            the sheet
	 */
	public static void clearHiddenColumns(final Sheet sheet) {

		for (Row row : sheet) {
			if (row.getLastCellNum() > TieConstants.MAX_COLUMNS_IN_SHEET) {
				deleteHiddenColumnsInRow(row);
			}
		}

	}

	/**
	 * Delete hidden columns in row.
	 *
	 * @param row
	 *            the row
	 */
	private static void deleteHiddenColumnsInRow(final Row row) {
		deleteCellFromRow(row,
				TieConstants.HIDDEN_SAVE_OBJECTS_COLUMN);
		deleteCellFromRow(row,
				TieConstants.HIDDEN_ORIGIN_ROW_NUMBER_COLUMN);
		deleteCellFromRow(row,
				TieConstants.HIDDEN_FULL_NAME_COLUMN);
	}

	/**
	 * Delete cell from row.
	 *
	 * @param row
	 *            the row
	 * @param cellNum
	 *            the cell num
	 */
	private static void deleteCellFromRow(final Row row,
			final int cellNum) {
		Cell cell = row.getCell(cellNum);
		if (cell != null) {
			row.removeCell(cell);
		}
	}

	/**
	 * return the last column of the sheet.
	 *
	 * @param xsheet
	 *            the xsheet
	 * @return last column number (A column will return 0).
	 */
	private static int getSheetRightColFromDimension(
			final XSSFSheet xsheet) {
		CTSheetDimension dimension = xsheet.getCTWorksheet().getDimension();
		String sheetDimensions = dimension.getRef();
		if (sheetDimensions.indexOf(':') < 0) {
			return -1;
		} else {
			return CellRangeAddress.valueOf(sheetDimensions)
					.getLastColumn();
		}
	}
}


/*
 * Copyright 2017 TieFaces.
 * Licensed under MIT
 */
package org.tiefaces.components.websheet.chart.objects;

import java.util.ArrayList;
import java.util.List;

import org.openxmlformats.schemas.drawingml.x2006.chart.CTAreaChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTAreaSer;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTAxDataSource;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTDPt;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumDataSource;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;

/**
 * area chart class.
 *
 * @author JASON JIANG
 *
 */
public class AreaChart implements ChartObject {

	/** empty list . */
	private List<CTAreaSer> emptySerlist = new ArrayList<>();

	/** empty list. */
	private List<CTDPt> dPlist = new ArrayList<>();
	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getChartListFromCtChart
	 * (org.openxmlformats.schemas.drawingml.x2006.chart.CTChart)
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public final List getChartListFromCtChart(final CTChart ctChart) {
		return ctChart.getPlotArea().getAreaChartList();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getSerListFromCtObjChart(java.lang.Object)
	 */

	@SuppressWarnings("rawtypes")
	@Override
	public final List getSerListFromCtObjChart(final Object ctObjChart) {

		if (ctObjChart instanceof CTAreaChart) {
			return ((CTAreaChart) ctObjChart).getSerList();
		}
		return emptySerlist;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getCtAxDataSourceFromSerList(java.util.List)
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public final CTAxDataSource getCtAxDataSourceFromSerList(
			final List serList) {

		if ((serList != null) && (!serList.isEmpty())
				&& (serList.get(0) instanceof CTAreaSer)) {
			return ((CTAreaSer) serList.get(0)).getCat();
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getSeriesLabelFromCTSer(java.lang.Object)
	 */
	@Override
	public final String getSeriesLabelFromCTSer(final Object ctObjSer) {
		if (ctObjSer instanceof CTAreaSer) {
			return ((CTAreaSer) ctObjSer).getTx().getStrRef().getF();
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getShapePropertiesFromCTSer(java.lang.Object)
	 */
	@Override
	public final CTShapeProperties getShapePropertiesFromCTSer(
			final Object ctObjSer) {
		if (ctObjSer instanceof CTAreaSer) {
			return ((CTAreaSer) ctObjSer).getSpPr();
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getCTNumDataSourceFromCTSer(java.lang.Object)
	 */
	@Override
	public final CTNumDataSource getCTNumDataSourceFromCTSer(
			final Object ctObjSer) {
		if (ctObjSer instanceof CTAreaSer) {
			return ((CTAreaSer) ctObjSer).getVal();
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.tiefaces.components.websheet.chart.objects.ChartObject#
	 * getDPtListFromCTSer(java.lang.Object)
	 */

	@Override
	public final List<CTDPt> getDPtListFromCTSer(final Object ctObjSer) {
		return dPlist;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.tiefaces.components.websheet.chart.objects.ChartObject#isLineColor()
	 */
	@Override
	public final boolean isLineColor() {
		return false;
	}

}


/*
 * Copyright 2017 TieFaces.
 * Licensed under MIT
 */

package org.tiefaces.common;

import java.util.logging.Level;
import java.util.logging.Logger;

import javax.faces.event.AbortProcessingException;
import javax.faces.event.SystemEvent;
import javax.faces.event.SystemEventListener;

/**
 * use show the version of tiefaces.
 *
 * @author Jason Jiang
 *
 */
public class PostConstructApplicationEventListener
		implements SystemEventListener {

	/** logger. */
	private static final Logger LOGGER = Logger.getLogger(
			PostConstructApplicationEventListener.class.getName());

	/**
	 * is listener for source.
	 *
	 * @param source
	 *            source.
	 * @return true.
	 *
	 */
	@Override
	public final boolean isListenerForSource(final Object source) {
		return true;
	}

	/**
	 * process event.
	 *
	 * @param event
	 *            systemevent.
	 * @throws AbortProcessingException
	 *             abort process exception.
	 */
	@Override
	public final void processEvent(final SystemEvent event) {

		LOGGER.log(Level.INFO, "Running on TieFaces {0}",
				AppUtils.getBuildVersion());
	}

}