/* BookHelper.java

	Purpose:
		
	Description:
		
	History:
		Mar 24, 2010 5:42:58 PM, Created by henrichen

Copyright (C) 2010 Potix Corporation. All Rights Reserved.

*/

package org.zkoss.zssex.formula.fn;

import java.util.Locale;

import org.zkoss.poi.ss.format.Formatters;
import org.zkoss.poi.ss.usermodel.Cell;
import org.zkoss.poi.ss.usermodel.ErrorConstants;
import org.zkoss.poi.ss.usermodel.ZssContext;
import org.zkoss.zss.model.impl.sys.DateInputMask;

/**
 * Internal User only. Helper class to handle the two version of Books.
 * @author henrichen
 * @author Dennis
 */
//partial code of book helper
public final class FunctionHelper {

	//0: value 1: format
	public static Object[] parseToDate(String txt) {
		final ZssContext ctx = ZssContext.getCurrent();
		final int twoDigitYearUpperBound = ctx.getTwoDigitYearUpperBound();
		final Locale locale = ctx.getLocale();
		//TODO when BookHelper refactor to singleton, DateInputMask can be a private variable 
		return new DateInputMask().parseDateInput(txt,locale);
	}	
	
	private static boolean isStringFormat(String formatStr) {
		return "@".equals(formatStr); //TODO, shall prepare a reqular expression match check!
	}
	/**
	 * 
	 * @param txt the text to be input
	 * @param formatStr the cell text format 
	 * @return object array with the value type in 0(an Integer), 
	 * 		the value in 1(an Object), and the date format in 2(a String if parse as a date)   
	 */
	public static Object[] editTextToValue(String txt, String formatStr) {
		if (txt != null) {
			//bug #300:	Numbers in Text-cells are not treated as text (leading zero is removed)
			if (formatStr != null) {
				if (isStringFormat(formatStr)) { 
					return new Object[] {new Integer(Cell.CELL_TYPE_STRING), txt}; //string
				}
			}
			if (txt.startsWith("=")) {
				if (txt.trim().length() > 1) {
					return new Object[] {new Integer(Cell.CELL_TYPE_FORMULA), txt.substring(1)}; //formula 
				} else {
					return new Object[] {new Integer(Cell.CELL_TYPE_STRING), txt}; //string
				}
			} else if ("true".equalsIgnoreCase(txt) || "false".equalsIgnoreCase(txt)) {
				return new Object[] {new Integer(Cell.CELL_TYPE_BOOLEAN), Boolean.valueOf(txt)}; //boolean
			} else if (txt.startsWith("#")) { //might be an error
				final byte err = getErrorCode(txt);
				return err < 0 ? 
					new Object[] {Integer.valueOf(Cell.CELL_TYPE_STRING), txt}: //string
					new Object[] {Integer.valueOf(Cell.CELL_TYPE_ERROR), new Byte(err)}; //error
			} else {
	            return parseEditTextToDoubleDateOrString(txt); //ZSS-67
			}
		}
		return null;
	}
	private static Object[] parseEditTextToDoubleDateOrString(String txt) {
		//TODO prepare a NumberInputMask that will set number format if input with comma thousand separator.
		final Locale locale = ZssContext.getCurrent().getLocale(); //ZSS-67
        final char dot = Formatters.getDecimalSeparator(locale);
        final char comma = Formatters.getGroupingSeparator(locale);
		String txt0 = txt;
		if (dot != '.' || comma != ',') {
	    	final int dotPos = txt.lastIndexOf(dot);
			txt0 = txt.replace(comma, ',');
	    	if (dotPos >= 0) {
	    		txt0 = txt0.substring(0, dotPos)+'.'+txt0.substring(dotPos+1);
	    	}
		}

		try {
			final Double val = Double.parseDouble(txt0);
			return new Object[] {new Integer(Cell.CELL_TYPE_NUMERIC), val}; //double
		} catch (NumberFormatException ex) {
			return parseEditTextToDateOrString(txt);
		}
	}
	private static Object[] parseEditTextToDateOrString(String txt) {
		final Object[] results = parseToDate(txt); 
		if (results[0] instanceof String) { 
			return new Object[] {new Integer(Cell.CELL_TYPE_STRING), results[0]}; //string
		} else { //if (result[0] instanceof Date)
			return new Object[] {Integer.valueOf(Cell.CELL_TYPE_NUMERIC), results[0], results[1]}; //date with format
		}
	}

	private static byte getErrorCode(String errString) {
		if ("#NULL!".equals(errString))
			return ErrorConstants.ERROR_NULL;
		if ("#DIV/0!".equals(errString))
			return ErrorConstants.ERROR_DIV_0;
		if ("#VALUE!".equals(errString))
			return ErrorConstants.ERROR_VALUE;
		if ("#REF!".equals(errString))
			return ErrorConstants.ERROR_REF;
		if ("#NAME?".equals(errString))
			return ErrorConstants.ERROR_NAME;
		if ("#NUM!".equals(errString))
			return ErrorConstants.ERROR_NUM; 
		if ("#N/A".equals(errString))
			return ErrorConstants.ERROR_NA;
		return -1;
	}
}
