Package org.openntf.formula.impl

Source Code of org.openntf.formula.impl.FormatterImpl

/*
* © Copyright FOCONIS AG, 2014
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
*/
package org.openntf.formula.impl;

import static com.ibm.icu.util.Calendar.DAY_OF_MONTH;
import static com.ibm.icu.util.Calendar.HOUR;
import static com.ibm.icu.util.Calendar.HOUR_OF_DAY;
import static com.ibm.icu.util.Calendar.MINUTE;
import static com.ibm.icu.util.Calendar.MONTH;
import static com.ibm.icu.util.Calendar.SECOND;
import static com.ibm.icu.util.Calendar.YEAR;
import static com.ibm.icu.util.Calendar.getInstance;

import java.text.ParsePosition;
import java.util.Date;
import java.util.Locale;

import org.openntf.formula.DateTime;
import org.openntf.formula.Formatter;

import com.ibm.icu.text.DateFormat;
import com.ibm.icu.text.NumberFormat;
import com.ibm.icu.text.SimpleDateFormat;
import com.ibm.icu.util.Calendar;

public class FormatterImpl implements Formatter {
  private Locale iLocale;

  public FormatterImpl(final Locale loc) {
    iLocale = loc;
  }

  public Locale getLocale() {
    return iLocale;
  }

  /*----------------------------------------------------------------------------*/
  public DateTime getNewSDTInstance() {
    return new DateTimeImpl(iLocale);
  }

  public DateTime getNewInitializedSDTInstance(final Date date, final boolean noDate, final boolean noTime) {
    DateTime sdt = getNewSDTInstance();
    sdt.setLocalTime(date);
    if (noDate)
      sdt.setAnyDate();
    if (noTime)
      sdt.setAnyTime();
    return sdt;
  }

  public DateTime getCopyOfSDTInstance(final DateTime sdt) {
    return getNewInitializedSDTInstance(sdt.toJavaDate(), sdt.isAnyDate(), sdt.isAnyTime());
  }

  /*----------------------------------------------------------------------------*/
  public DateTime parseDate(final String image) {
    return parseDate(image, false);
  }

  public DateTime parseDate(final String image, final boolean parseLenient) {
    DateTime ret = getNewSDTInstance();
    ret.setLocalTime(image, parseLenient);
    return ret;
  }

  public DateTime parseDateWithFormat(final String image, final String format, final boolean parseLenient) {
    boolean[] noDT = new boolean[2];
    Calendar cal = parseDateToCalWithFormat(image, format, noDT, parseLenient);
    DateTime ret = getNewInitializedSDTInstance(cal.getTime(), noDT[0], noDT[1]);
    return ret;
  }

  /*----------------------------------------------------------------------------*/
  public Calendar parseDateToCal(String image, final boolean[] noDT, final boolean parseLenient) {
    image = image.trim();
    Calendar ret = getInstance(iLocale);
    // Should an empty string lead to a DateTime with noDate=noTime=true?
    // (Lotus doesn't accept empty strings here.)
    char spec = 0;
    if (image.equalsIgnoreCase("TODAY"))
      spec = 'H';
    else if (image.equalsIgnoreCase("TOMORROW"))
      spec = 'M';
    else if (image.equalsIgnoreCase("YESTERDAY"))
      spec = 'G';
    if (spec != 0) {
      ret.setTime(new Date());
      if (spec == 'M')
        ret.add(DAY_OF_MONTH, 1);
      else if (spec == 'G')
        ret.add(DAY_OF_MONTH, -1);
      noDT[0] = false;
      noDT[1] = true;
      return ret;
    }
    ret.setLenient(false);
    ParsePosition p = new ParsePosition(0);
    boolean illegalDateString = false;
    for (;;) {
      ret.clear();
      /*
       * First attempt: Take a full date-time format MEDIUM
       */
      DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, iLocale);
      df.parse(image, ret, p);
      if (p.getErrorIndex() < 0)
        break;
      if (!ret.isSet(DAY_OF_MONTH) || !ret.isSet(MONTH)) {
        //Try with SHORT format     
        ret.clear();
        df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, iLocale);
        p.setIndex(0);
        p.setErrorIndex(-1);
        df.parse(image, ret, p);
        if (!ret.isSet(DAY_OF_MONTH) || !ret.isSet(MONTH)) {  // Give up with date
          ret.clear();
          p.setErrorIndex(0);
        }
      }
      if (ret.isSet(MINUTE))
        break;
      /*
       * If no time found yet (i.e. at least hour+minute like Lotus), try to fish it
       */
      p.setIndex(p.getErrorIndex());
      p.setErrorIndex(-1);
      df = DateFormat.getTimeInstance(DateFormat.MEDIUM, iLocale);
      df.parse(image, ret, p);
      if (ret.isSet(MINUTE))
        break;
      if (ret.isSet(DAY_OF_MONTH)) { // Set back possible hour (in accordance with Lotus)
        ret.clear(HOUR);
        ret.clear(HOUR_OF_DAY);
        break;
      }
      /*
       * Left: No date found, no time found
       */
      illegalDateString = true;
      break;
    }
    //    System.out.println("Lh=" + image.length() + " Index=" + p.getIndex() + " ErrIndex=" + p.getErrorIndex());
    if (!illegalDateString && !parseLenient) {
      int lh = image.length();
      int errInd = p.getErrorIndex();
      illegalDateString = (errInd < 0 && p.getIndex() < lh) || (errInd >= 0 && errInd < lh);
    }
    if (illegalDateString)
      throw new IllegalArgumentException("Illegal date string '" + image + "'");
    boolean contDate = ret.isSet(DAY_OF_MONTH);
    boolean contTime = ret.isSet(MINUTE);
    if (ret.isSet(YEAR)) {
      if (!contTime)
        ret.set(HOUR_OF_DAY, 0);
    } else {
      Calendar now = getInstance(iLocale);
      now.setTime(new Date());
      ret.set(YEAR, now.get(YEAR));
      if (!contDate) {
        ret.set(DAY_OF_MONTH, now.get(DAY_OF_MONTH));
        ret.set(MONTH, now.get(MONTH));
      }
    }
    if (!ret.isSet(MINUTE))
      ret.set(MINUTE, 0);
    if (!ret.isSet(SECOND))
      ret.set(SECOND, 0);
    try {
      ret.getTime();
    } catch (IllegalArgumentException e) {
      throw new IllegalArgumentException("Illegal date string '" + image + "': " + e.getMessage());
    }
    noDT[0] = !contDate;
    noDT[1] = !contTime;
    return ret;
  }

  /*----------------------------------------------------------------------------*/
  public Calendar parseDateToCalWithFormat(final String image, final String format, final boolean[] noDT, final boolean parseLenient) {
    Calendar ret = getInstance(iLocale);
    ret.setLenient(false);
    ParsePosition p = new ParsePosition(0);
    ret.clear();
    SimpleDateFormat sdf = new SimpleDateFormat(format, iLocale);
    sdf.parse(image, ret, p);
    boolean contDate = ret.isSet(YEAR) || ret.isSet(MONTH) || ret.isSet(DAY_OF_MONTH);
    boolean contTime = ret.isSet(HOUR_OF_DAY) || ret.isSet(HOUR) || ret.isSet(MINUTE) || ret.isSet(SECOND);
    boolean illegalDateString = !contDate && !contTime;
    if (!illegalDateString && !parseLenient) {
      int lh = image.length();
      int errInd = p.getErrorIndex();
      illegalDateString = (errInd < 0 && p.getIndex() < lh) || (errInd >= 0 && errInd < lh);
    }
    if (illegalDateString)
      throw new IllegalArgumentException("Illegal date string '" + image + "' for format '" + format + "'");
    //    System.out.println("Y=" + ret.isSet(YEAR) + " M=" + ret.isSet(MONTH) + " D=" + ret.isSet(DAY_OF_MONTH)
    //        + " H=" + ret.isSet(HOUR_OF_DAY) + "m=" + ret.isSet(MINUTE) + " S=" + ret.isSet(SECOND));
    if (!ret.isSet(YEAR))
      ret.set(YEAR, 1970);
    if (!ret.isSet(MONTH))
      ret.set(MONTH, 0);
    if (!ret.isSet(DAY_OF_MONTH))
      ret.set(DAY_OF_MONTH, 1);
    if (!ret.isSet(HOUR_OF_DAY) && !ret.isSet(HOUR))
      ret.set(HOUR_OF_DAY, 0);
    if (!ret.isSet(MINUTE))
      ret.set(MINUTE, 0);
    if (!ret.isSet(SECOND))
      ret.set(SECOND, 0);
    try {
      ret.getTime();
    } catch (IllegalArgumentException e) {
      throw new IllegalArgumentException("Parsing '" + image + "' against '" + format + "' gives Calendar exception: "
          + e.getMessage());
    }
    noDT[0] = !contDate;
    noDT[1] = !contTime;
    return ret;
  }

  /*----------------------------------------------------------------------------*/
  public Number parseNumber(final String image) {
    return parseNumber(image, false);
  }

  public Number parseNumber(String image, final boolean lenient) {
    image = image.trim();
    if (!image.isEmpty()) {
      String toParse = image;
      if (toParse.length() > 1 && toParse.charAt(0) == '+')
        toParse = toParse.substring(1);
      NumberFormat nf = NumberFormat.getNumberInstance(iLocale);
      ParsePosition p = new ParsePosition(0);
      Number ret = nf.parse(toParse, p);
      int errIndex = p.getErrorIndex();
      //System.out.println("Ind=" + index + " ErrInd=" + errIndex);
      if (errIndex == -1) {
        if (p.getIndex() >= toParse.length() || lenient)
          return ret;
      } else if (errIndex != 0 && lenient)
        return ret;
    }
    throw new IllegalArgumentException("Illegal number string '" + image + "'");
  }

  /*----------------------------------------------------------------------------*/
  public String formatDateTime(final DateTime sdt) {
    return sdt.getLocalTime();
  }

  public String formatDateTime(final DateTime sdt, final LotusDateTimeOptions ldto) {
    if (ldto.nothingSet())
      return formatDateTime(sdt);
    String notSupported = "";
    if (ldto.dOption != -1 && ldto.dOption != LotusDateTimeOptions.D_YMD)
      notSupported += "," + ldto.dOptToStr();
    if (ldto.zOption != -1)
      notSupported += "," + ldto.zOptToStr();
    if (ldto.sOption == LotusDateTimeOptions.S_DT_TY)
      notSupported += "," + ldto.sOptToStr();
    if (!notSupported.isEmpty())
      throw new UnsupportedOperationException("Not yet supported formatting option(s): " + notSupported.substring(1));
    if (ldto.sOption == LotusDateTimeOptions.S_D_ONLY || sdt.isAnyTime())
      return sdt.getDateOnly();
    Calendar cal = sdt.toJavaCal();
    if (ldto.sOption == LotusDateTimeOptions.S_T_ONLY || sdt.isAnyDate()) {
      if (ldto.tOption != LotusDateTimeOptions.T_HM)
        return sdt.getTimeOnly();
      return sdt.isAnyTime() ? "" : formatCalTimeOnly(cal, TIMEFORMAT_SHORT);
    }
    int timeFormat = (ldto.tOption == LotusDateTimeOptions.T_HM) ? TIMEFORMAT_SHORT : TIMEFORMAT_MEDIUM;
    return formatCalDateTime(cal, timeFormat);
  }

  public String formatCalDateTime(final Calendar cal) {
    return formatCalDateTime(cal, TIMEFORMAT_LONG);
  }

  public String formatCalDateTime(final Calendar cal, final int timeFormat) {
    DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, transTimeFormat(timeFormat), iLocale);
    df.setCalendar(cal);
    return df.format(cal.getTime());
  }

  public String formatCalDateOnly(final Calendar cal) {
    DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, iLocale);
    df.setCalendar(cal);
    return df.format(cal.getTime());
  }

  public String formatCalTimeOnly(final Calendar cal) {
    return formatCalTimeOnly(cal, TIMEFORMAT_MEDIUM);
  }

  public String formatCalTimeOnly(final Calendar cal, final int timeFormat) {
    DateFormat df = DateFormat.getTimeInstance(transTimeFormat(timeFormat), iLocale);
    df.setCalendar(cal);
    return df.format(cal.getTime());
  }

  private int transTimeFormat(final int timeFormat) {
    if (timeFormat == TIMEFORMAT_MEDIUM)
      return DateFormat.MEDIUM;
    if (timeFormat == TIMEFORMAT_SHORT)
      return DateFormat.SHORT;
    return DateFormat.LONG;
  }

  public String formatDateTimeWithFormat(final DateTime sdt, final String format) {
    Calendar cal = sdt.toJavaCal();
    if (sdt.isAnyDate() || sdt.isAnyTime()) {
      Calendar calCopy = (Calendar) cal.clone();
      if (sdt.isAnyDate()) {
        calCopy.set(YEAR, 1970);
        calCopy.set(MONTH, 0);
        calCopy.set(DAY_OF_MONTH, 1);
      }
      if (sdt.isAnyTime()) {
        calCopy.set(HOUR_OF_DAY, 0);
        calCopy.set(MINUTE, 0);
        calCopy.set(SECOND, 0);
      }
      cal = calCopy;
    }
    return formatCalWithFormat(cal, format);
  }

  public String formatCalWithFormat(final Calendar cal, final String format) {
    SimpleDateFormat sdf = new SimpleDateFormat(format, iLocale);
    sdf.setCalendar(cal);
    return sdf.format(cal.getTime());
  }

  /*----------------------------------------------------------------------------*/
  public String formatNumber(final Number n) {
    LotusNumberOptions lno = new LotusNumberOptions();
    lno.setDefault();
    return formatNumber(n, lno);
  }

  public String formatNumber(final Number n, final LotusNumberOptions lno) {
    NumberFormat nf;
    /*
     * It would have been more convenient to use NumberFormat.getInstance(locale, style),
     * but this method is private in com.ibm.icu_3.8.1.v20120530.jar.
     * (Seems to be public as of ICU 4.2.)
     */
    if (lno.format == 'C')
      nf = NumberFormat.getCurrencyInstance(iLocale);
    else if (lno.format == 'S')
      nf = NumberFormat.getScientificInstance(iLocale);
    else if (lno.format == '%')
      nf = NumberFormat.getPercentInstance(iLocale);
    else
      nf = NumberFormat.getNumberInstance(iLocale);
    nf.setGroupingUsed(lno.useGrouping);
    nf.setMaximumIntegerDigits(1000);
    if (lno.fractionDigits != -1) {
      nf.setMinimumFractionDigits(lno.fractionDigits);
      nf.setMaximumFractionDigits(lno.fractionDigits);
    } else
      nf.setMaximumFractionDigits(1000);
    String ret = nf.format(n);
    do {
      if (lno.format != 'G' || ret.length() <= 15)
        break;
      /*
       * In this case, Lotus implicitly switches to scientific style.
       * When useGrouping is in effect, the limit decreases from 15 to 12 in Lotus
       * (i.e. the grouping bytes are likewise counted), but we are not going to
       *  imitate this strange behaviour.
       */
      String tester = ret;
      if (lno.useGrouping) {
        nf.setGroupingUsed(false);
        tester = nf.format(n);
      }
      int minus = (tester.charAt(0) == '-') ? 1 : 0;
      int lh = tester.length();
      if (lh - minus <= 15)
        break;
      int komma = minus;
      for (; komma < lh; komma++)
        if (!Character.isDigit(tester.charAt(komma)))
          break;
      if (komma - minus <= 15)
        break;
      nf = NumberFormat.getScientificInstance(iLocale);
      nf.setGroupingUsed(lno.useGrouping);
      ret = nf.format(n);
    } while (false);
    if (lno.negativeAsParentheses && ret.charAt(0) == '-')
      ret = '(' + ret.substring(1) + ')';
    return ret;
  }
  /*----------------------------------------------------------------------------*/
TOP

Related Classes of org.openntf.formula.impl.FormatterImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.