/**
* Copyright (C) 2001-2017 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License along with this program.
* If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.tools.expression.internal.function.conversion;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.Callable;
import com.rapidminer.tools.Ontology;
import com.rapidminer.tools.expression.ExpressionEvaluator;
import com.rapidminer.tools.expression.ExpressionParsingException;
import com.rapidminer.tools.expression.ExpressionType;
import com.rapidminer.tools.expression.FunctionDescription;
import com.rapidminer.tools.expression.FunctionInputException;
import com.rapidminer.tools.expression.internal.ExpressionParserConstants;
import com.rapidminer.tools.expression.internal.SimpleExpressionEvaluator;
import com.rapidminer.tools.expression.internal.function.AbstractFunction;
/**
*
* A {@link Function} parsing a date to a string with respect to the size, format and locale.
*
* @author Marcel Seifert
*
*/
public class DateStringLocale extends AbstractFunction {
/**
* Constructs an AbstractFunction with {@link FunctionDescription} generated from the arguments
* and the function name generated from the description.
*/
public DateStringLocale() {
super("conversion.date_str_loc", 4, Ontology.NOMINAL);
}
@Override
public ExpressionEvaluator compute(ExpressionEvaluator... inputEvaluators) {
if (inputEvaluators.length != 4) {
throw new FunctionInputException("expression_parser.function_wrong_input", getFunctionName(), 4,
inputEvaluators.length);
}
ExpressionType type = getResultType(inputEvaluators);
ExpressionEvaluator date = inputEvaluators[0];
ExpressionEvaluator size = inputEvaluators[1];
ExpressionEvaluator format = inputEvaluators[2];
ExpressionEvaluator locale = inputEvaluators[3];
return new SimpleExpressionEvaluator(makeStringCallable(date, size, format, locale), type,
isResultConstant(inputEvaluators));
}
/**
* Builds a String Callable from one date and three string arguments
*
* @param date
* the input date
* @param size
* the input size
* @param format
* the input format
* @return the resulting callable<String>
*/
protected Callable<String> makeStringCallable(final ExpressionEvaluator date, final ExpressionEvaluator size,
final ExpressionEvaluator format, final ExpressionEvaluator locale) {
final Callable<Date> funcDate = date.getDateFunction();
final Callable<String> funcSize = size.getStringFunction();
final Callable<String> funcFormat = format.getStringFunction();
final Callable<String> funcLocale = locale.getStringFunction();
try {
final Date valueDate = date.isConstant() ? funcDate.call() : null;
final String valueSize = size.isConstant() ? funcSize.call() : null;
final String valueFormat = format.isConstant() ? funcFormat.call() : null;
final String valueLocale = locale.isConstant() ? funcLocale.call() : null;
if (locale.isConstant()) {
if (size.isConstant()) {
if (date.isConstant() && format.isConstant()) {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(valueDate, valueSize, valueFormat, valueLocale);
}
};
} else if (date.isConstant()) {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(valueDate, valueSize, funcFormat.call(), valueLocale);
}
};
} else if (format.isConstant()) {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(funcDate.call(), valueSize, valueFormat, valueLocale);
}
};
} else {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(funcDate.call(), valueSize, funcFormat.call(), valueLocale);
}
};
}
} else {
if (date.isConstant() && format.isConstant()) {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(valueDate, funcSize.call(), valueFormat, valueLocale);
}
};
} else if (date.isConstant()) {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(valueDate, funcSize.call(), funcFormat.call(), valueLocale);
}
};
} else if (format.isConstant()) {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(funcDate.call(), funcSize.call(), valueFormat, valueLocale);
}
};
} else {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(funcDate.call(), funcSize.call(), funcFormat.call(), valueLocale);
}
};
}
}
} else {
if (size.isConstant()) {
if (date.isConstant() && format.isConstant()) {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(valueDate, valueSize, valueFormat, funcLocale.call());
}
};
} else if (date.isConstant()) {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(valueDate, valueSize, funcFormat.call(), funcLocale.call());
}
};
} else if (format.isConstant()) {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(funcDate.call(), valueSize, valueFormat, funcLocale.call());
}
};
} else {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(funcDate.call(), valueSize, funcFormat.call(), funcLocale.call());
}
};
}
} else {
if (date.isConstant() && format.isConstant()) {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(valueDate, funcSize.call(), valueFormat, funcLocale.call());
}
};
} else if (date.isConstant()) {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(valueDate, funcSize.call(), funcFormat.call(), funcLocale.call());
}
};
} else if (format.isConstant()) {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(funcDate.call(), funcSize.call(), valueFormat, funcLocale.call());
}
};
} else {
return new Callable<String>() {
@Override
public String call() throws Exception {
return compute(funcDate.call(), funcSize.call(), funcFormat.call(), funcLocale.call());
}
};
}
}
}
} catch (ExpressionParsingException e) {
throw e;
} catch (Exception e) {
throw new ExpressionParsingException(e);
}
}
/**
* Computes the result for one date and three string input values.
*
* @param dateDate
* the date
* @param sizeString
* the sizeString from {@link ExpressionParserConstants}
* @param formatString
* the formatString from {@link ExpressionParserConstants}
* @param localeString
* the locale string
* @return the result of the computation.
*/
protected String compute(Date dateDate, String sizeString, String formatString, String localeString) {
if (dateDate == null || sizeString == null || formatString == null || localeString == null) {
return null;
}
String result;
DateFormat dateFormat;
Locale locale = new Locale(localeString);
int formatting;
if (sizeString.equals(ExpressionParserConstants.DATE_FORMAT_FULL)) {
formatting = DateFormat.FULL;
} else if (sizeString.equals(ExpressionParserConstants.DATE_FORMAT_LONG)) {
formatting = DateFormat.LONG;
} else if (sizeString.equals(ExpressionParserConstants.DATE_FORMAT_MEDIUM)) {
formatting = DateFormat.MEDIUM;
} else if (sizeString.equals(ExpressionParserConstants.DATE_FORMAT_SHORT)) {
formatting = DateFormat.SHORT;
} else {
throw new FunctionInputException("invalid_argument.date_size", getFunctionName());
}
if (formatString.equals(ExpressionParserConstants.DATE_SHOW_DATE_ONLY)) {
// clone because getDateInstance uses an internal pool which can return the
// same instance for multiple threads
dateFormat = (DateFormat) DateFormat.getDateInstance(formatting, locale).clone();
} else if (formatString.equals(ExpressionParserConstants.DATE_SHOW_TIME_ONLY)) {
// clone because getDateInstance uses an internal pool which can return the
// same instance for multiple threads
dateFormat = (DateFormat) DateFormat.getTimeInstance(formatting, locale).clone();
} else if (formatString.equals(ExpressionParserConstants.DATE_SHOW_DATE_AND_TIME)) {
// clone because getDateInstance uses an internal pool which can return the
// same instance for multiple threads
dateFormat = (DateFormat) DateFormat.getDateTimeInstance(formatting, formatting, locale).clone();
} else {
throw new FunctionInputException("invalid_argument.date_format", getFunctionName());
}
result = dateFormat.format(dateDate);
return result;
}
@Override
protected ExpressionType computeType(ExpressionType... inputTypes) {
ExpressionType date = inputTypes[0];
ExpressionType size = inputTypes[1];
ExpressionType format = inputTypes[2];
ExpressionType locale = inputTypes[3];
if (date != ExpressionType.DATE) {
throw new FunctionInputException("expression_parser.function_wrong_type.argument", 1, getFunctionName(), "date");
} else if (size != ExpressionType.STRING) {
throw new FunctionInputException("expression_parser.function_wrong_type.argument", 2, getFunctionName(),
"string");
} else if (format != ExpressionType.STRING) {
throw new FunctionInputException("expression_parser.function_wrong_type.argument", 3, getFunctionName(),
"string");
} else if (locale != ExpressionType.STRING) {
throw new FunctionInputException("expression_parser.function_wrong_type.argument", 4, getFunctionName(),
"string");
} else {
return ExpressionType.STRING;
}
}
}