+ if (getStartYear() != null){
+ result += String.valueOf(getStartYear());
+ if (getEndYear() != null){
+ result += "-" + String.valueOf(getEndYear());
+ }
+ }else{
+ if (getEndYear() != null){
+ result += String.valueOf(getEndYear());
+ }
+ }
+ return result;
+ }
+
+ @Transient
+ public Integer getStartYear(){
+ return getPartialValue(start, YEAR_TYPE);
+ }
+
+ @Transient
+ public Integer getStartMonth(){
+ return getPartialValue(start, MONTH_TYPE);
+ }
+
+ @Transient
+ public Integer getStartDay(){
+ return getPartialValue(start, DAY_TYPE);
+ }
+
+ @Transient
+ public Integer getEndYear(){
+ return getPartialValue(end, YEAR_TYPE);
+ }
+
+ @Transient
+ public Integer getEndMonth(){
+ return getPartialValue(end, MONTH_TYPE);
+ }
+
+ @Transient
+ public Integer getEndDay(){
+ return getPartialValue(end, DAY_TYPE);
+ }
+
+ public static Integer getPartialValue(Partial partial, DateTimeFieldType type){
+ if (partial == null || ! partial.isSupported(type)){
+ return null;
+ }else{
+ return partial.get(type);
+ }
+
+ }
+
+ public TimePeriod setStartYear(Integer year){
+ return setStartField(year, YEAR_TYPE);
+ }
+
+ public TimePeriod setStartMonth(Integer month) throws IndexOutOfBoundsException{
+ return setStartField(month, MONTH_TYPE);
+ }
+
+ public TimePeriod setStartDay(Integer day) throws IndexOutOfBoundsException{
+ return setStartField(day, DAY_TYPE);
+ }
+
+ public TimePeriod setEndYear(Integer year){
+ return setEndField(year, YEAR_TYPE);
+ }
+
+ public TimePeriod setEndMonth(Integer month) throws IndexOutOfBoundsException{
+ return setEndField(month, MONTH_TYPE);
+ }
+
+ public TimePeriod setEndDay(Integer day) throws IndexOutOfBoundsException{
+ return setEndField(day, DAY_TYPE);
+ }
+
+ public static Partial setPartialField(Partial partial, Integer value, DateTimeFieldType type)
+ throws IndexOutOfBoundsException{
+ if (partial == null){
+ partial = new Partial();
+ }
+ if (value == null){
+ return partial.without(type);
+ }else{
+ checkFieldValues(value, type, partial);
+ return partial.with(type, value);
+ }
+ }
+
+ private TimePeriod setStartField(Integer value, DateTimeFieldType type)
+ throws IndexOutOfBoundsException{
+ start = setPartialField(start, value, type);
+ return this;
+ }
+
+ private TimePeriod setEndField(Integer value, DateTimeFieldType type)
+ throws IndexOutOfBoundsException{
+ end = setPartialField(end, value, type);
+ return this;
+ }
+
+ /**
+ * Throws an IndexOutOfBoundsException if the value does not have a valid value
+ * (e.g. month > 12, month < 1, day > 31, etc.)
+ * @param value
+ * @param type
+ * @throws IndexOutOfBoundsException
+ */
+ private static void checkFieldValues(Integer value, DateTimeFieldType type, Partial partial)
+ throws IndexOutOfBoundsException{
+ int max = 9999999;
+ if (type.equals(MONTH_TYPE)){
+ max = 12;
+ }
+ if (type.equals(DAY_TYPE)){
+ max = 31;
+ Integer month = null;
+ if (partial.isSupported(MONTH_TYPE)){
+ month = partial.get(MONTH_TYPE);
+ }
+ if (month != null){
+ if (month == 2){
+ max = 29;
+ }else if (month == 4 ||month == 6 ||month == 9 ||month == 11){
+ max = 30;
+ }
+ }
+ }
+ if ( (value < 1 || value > max) ){
+ throw new IndexOutOfBoundsException("Value must be between 1 and " + max);
+ }
+ }
+
+ private void initStart(){
+ if (start == null){
+ start = new Partial();
+ }
+ }
+
+ private void initEnd(){
+ if (end == null){
+ end = new Partial();
+ }
+ }
+
+
+ //patter for first year in string;
+ private static final Pattern firstYearPattern = Pattern.compile("\\d{4}");
+ //case "1806"[1807];
+ private static final Pattern uncorrectYearPatter = Pattern.compile("\"\\d{4}\"\\s*\\[\\d{4}\\]");
+ //case fl. 1806 or c. 1806 or fl. 1806?
+ private static final Pattern prefixedYearPattern = Pattern.compile("(fl|c)\\.\\s*\\d{4}(\\s*-\\s*\\d{4})?\\??");
+ //standard
+ private static final Pattern standardPattern = Pattern.compile("\\s*\\d{2,4}(\\s*-(\\s*\\d{2,4})?)?");
+ private static final String strDotDate = "[0-3]?\\d\\.[01]?\\d\\.\\d{4,4}";
+ private static final String strDotDatePeriodPattern = String.format("%s(\\s*-\\s*%s?)?", strDotDate, strDotDate);
+ private static final Pattern dotDatePattern = Pattern.compile(strDotDatePeriodPattern);
+
+
+ public static TimePeriod parseString(TimePeriod timePeriod, String periodString){
+ //TODO move to parser class
+ //TODO until now only quick and dirty (and partly wrong)
+ TimePeriod result = timePeriod;
+
+ if(timePeriod == null){
+ return timePeriod;
+ }
+
+ if (periodString == null){
+ return result;
+ }
+ periodString = periodString.trim();
+
+ result.setFreeText(null);
+ Date date;
+
+ //case "1806"[1807];
+ if (uncorrectYearPatter.matcher(periodString).matches()){
+ result.setFreeText(periodString);
+ String realYear = periodString.split("\\[")[1];
+ realYear = realYear.replace("]", "");
+ result.setStartYear(Integer.valueOf(realYear));
+ result.setFreeText(periodString);
+ //case fl. 1806 or c. 1806 or fl. 1806?
+ }else if(prefixedYearPattern.matcher(periodString).matches()){
+ result.setFreeText(periodString);
+ Matcher yearMatcher = firstYearPattern.matcher(periodString);
+ yearMatcher.find();
+ String startYear = yearMatcher.group();
+ result.setStartYear(Integer.valueOf(startYear));
+ if (yearMatcher.find()){
+ String endYear = yearMatcher.group();
+ result.setEndYear(Integer.valueOf(endYear));
+ }
+ }else if (dotDatePattern.matcher(periodString).matches()){
+ parseDotDatePattern(periodString, result);
+ }else if (standardPattern.matcher(periodString).matches()){
+ parseStandardPattern(periodString, result);
+//TODO first check ambiguity of parser results e.g. for 7/12/11
+// }else if (isDateString(periodString)){
+// String[] startEnd = makeStartEnd(periodString);
+// String start = startEnd[0];
+// DateTime startDateTime = dateStringParse(start, true);
+// result.setStart(startDateTime);
+// if (startEnd.length > 1){
+// DateTime endDateTime = dateStringParse(startEnd[1], true);
+// ;
+// result.setEnd(endDateTime.toLocalDate());
+// }
+
+ }else{
+ result.setFreeText(periodString);
+ }
+ return result;
+ }
+
+ private static boolean isDateString(String periodString) {
+ String[] startEnd = makeStartEnd(periodString);
+ String start = startEnd[0];
+ DateTime startDateTime = dateStringParse(start, true);
+ if (startDateTime == null){
+ return false;
+ }
+ if (startEnd.length > 1){
+ DateTime endDateTime = dateStringParse(startEnd[1], true);
+ if (endDateTime != null){
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * @param periodString
+ * @return
+ */
+ private static String[] makeStartEnd(String periodString) {
+ String[] startEnd = new String[]{periodString};
+ if (periodString.contains("-") && periodString.matches("^-{2,}-^-{2,}")){
+ startEnd = periodString.split("-");
+ }
+ return startEnd;
+ }
+
+
+ private static DateTime dateStringParse(String string, boolean strict) {
+ DateFormat dateFormat = DateFormat.getDateInstance();
+ ParsePosition pos = new ParsePosition(0);
+ Date a = dateFormat.parse(string, pos);
+ if (a == null || pos.getIndex() != string.length()){
+ return null;
+ }
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(a);
+ DateTime result = new DateTime(cal);
+ return result;
+ }
+
+
+ /**
+ * @param periodString
+ * @param result
+ */
+ private static void parseDotDatePattern(String periodString,TimePeriod result) {
+ String[] dates = periodString.split("-");
+ Partial dtStart = null;
+ Partial dtEnd = null;
+
+ if (dates.length > 2 || dates.length <= 0){
+ logger.warn("More than 1 '-' in period String: " + periodString);
+ result.setFreeText(periodString);
+ }else {
+ try {
+ //start
+ if (! CdmUtils.isEmpty(dates[0])){
+ dtStart = parseSingleDotDate(dates[0].trim());
+ }
+
+ //end
+ if (dates.length >= 2 && ! CdmUtils.isEmpty(dates[1])){
+ dtEnd = parseSingleDotDate(dates[1].trim());
+ }
+
+ result.setStart(dtStart);
+ result.setEnd(dtEnd);
+ } catch (IllegalArgumentException e) {
+ //logger.warn(e.getMessage());
+ result.setFreeText(periodString);
+ }
+ }
+ }
+
+
+ /**
+ * @param periodString
+ * @param result
+ */
+ private static void parseStandardPattern(String periodString,
+ TimePeriod result) {
+ String[] years = periodString.split("-");
+ Partial dtStart = null;
+ Partial dtEnd = null;
+
+ if (years.length > 2 || years.length <= 0){
+ logger.warn("More than 1 '-' in period String: " + periodString);
+ }else {
+ try {
+ //start
+ if (! CdmUtils.isEmpty(years[0])){
+ dtStart = parseSingleDate(years[0].trim());
+ }
+
+ //end
+ if (years.length >= 2 && ! CdmUtils.isEmpty(years[1])){
+ years[1] = years[1].trim();
+ if (years[1].length()==2 && dtStart != null && dtStart.isSupported(DateTimeFieldType.year())){
+ years[1] = String.valueOf(dtStart.get(DateTimeFieldType.year())/100) + years[1];
+ }
+ dtEnd = parseSingleDate(years[1]);
+ }
+
+ result.setStart(dtStart);
+ result.setEnd(dtEnd);
+ } catch (IllegalArgumentException e) {
+ //logger.warn(e.getMessage());
+ result.setFreeText(periodString);
+ }
+ }
+ }
+
+ public static TimePeriod parseString(String strPeriod) {
+ TimePeriod timePeriod = TimePeriod.NewInstance();
+ return parseString(timePeriod, strPeriod);
+ }
+
+
+ protected static Partial parseSingleDate(String singleDateString) throws IllegalArgumentException{
+ //FIXME until now only quick and dirty and incomplete
+ Partial partial = new Partial();
+ singleDateString = singleDateString.trim();
+ if (CdmUtils.isNumeric(singleDateString)){
+ try {
+ Integer year = Integer.valueOf(singleDateString.trim());
+ if (year < 1000 && year > 2100){
+ logger.warn("Not a valid year: " + year + ". Year must be between 1000 and 2100");
+ }else if (year < 1700 && year > 2100){
+ logger.warn("Not a valid taxonomic year: " + year + ". Year must be between 1750 and 2100");
+ partial = partial.with(YEAR_TYPE, year);
+ }else{
+ partial = partial.with(YEAR_TYPE, year);
+ }
+ } catch (NumberFormatException e) {
+ logger.debug("Not a Integer format in getCalendar()");
+ throw new IllegalArgumentException(e);