// $Id: StringUtil.java,v 1.10 2004/11/07 03:00:53 caron Exp $
/*
 * Copyright 1997-2004 Unidata Program Center/University Corporation for
 * Atmospheric Research, P.O. Box 3000, Boulder, CO 80307,
 * support@unidata.ucar.edu.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at
 * your option) any later version.
 *
 * This library 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 Lesser
 * General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

package ucar.unidata.util;

/**
 * String utilities
 * @author John Caron
 * @version $Id: StringUtil.java,v 1.10 2004/11/07 03:00:53 caron Exp $
 */

public class StringUtil {

  /**
   * Collapse continuous whitespace into one single " ".
   */
  static public String collapseWhitespace( String s) {
    int len = s.length();
    StringBuffer b = new StringBuffer( len);
    for (int i=0; i< len; i++) {
      char c = s.charAt(i);
      if (!Character.isWhitespace(c))
        b.append(c);
      else {
        b.append(' ');
        while ((i+1<len) && Character.isWhitespace(s.charAt(i+1)))
          i++;  /// skip further whitespace
      }
    }
    return b.toString();
  }

  /**
   * Remove all whitespace in the string.
   */
  static public String removeWhitespace( String s) {
    int len = s.length();
    StringBuffer b = new StringBuffer( len);
    for (int i=0; i< len; i++) {
      char c = s.charAt(i);
      if (!Character.isWhitespace(c))
        b.append(c);
    }
    return b.toString();
  }

  /**
   * Remove all occurrences of the substring sub in the string s.
   */
  static public String remove( String s, String sub) {
    int len = sub.length();
    int pos;
    while (0 <= (pos = s.indexOf(sub)))
      s = s.substring(0, pos) + s.substring(pos+len);
    return s;
  }

  /**
   * Remove all occurrences of the character c in the string s.
   */
  static public String remove( String s, int c) {
    if (0 > s.indexOf(c)) // none
      return s;

    StringBuffer buff = new StringBuffer(s);
    int i=0;
    while (i<buff.length()) {
      if (buff.charAt(i) == c)
        buff.deleteCharAt(i);
      else
        i++;
    }
    return buff.toString();
  }

  /**
   * Find all occurences of match strings in original, and substitute the corresponding
   *   subst string.
   * @param original starting string
   * @param match array of strings to match
   * @param subst array of strings to substitute
   * @return a new string with substitutions
   */
   static public String substitute( String original, String[] match, String[] subst) {
    String s = original;
    int pos;
    for (int i=0; i< match.length; i++) {
      while (0 <= (pos = s.indexOf( match[i]))) {
        StringBuffer sb = new StringBuffer( s);
        s = sb.replace( pos, pos + match[i].length(), subst[i]).toString();
      }
    }
    return s;
  }

  /**
   * Find all occurences of the "match" in original, and substitute the "subst" string.
   * @param original starting string
   * @param match string to match
   * @param subst string to substitute
   * @return a new string with substitutions
   */
   static public String substitute( String original, String match, String subst) {
    String s = original;
    int pos;
    while (0 <= (pos = s.indexOf( match))) {
      StringBuffer sb = new StringBuffer( s);
      s = sb.replace( pos, pos + match.length(), subst).toString();
    }

    return s;
  }

  /**
   * Find all occurences of the "match" in original, and substitute the "subst" string,
   *  directly into the original.
   * @param sbuff starting string buffer
   * @param match string to match
   * @param subst string to substitute
   */
   static public void substitute( StringBuffer sbuff, String match, String subst) {
    int pos, fromIndex = 0;
    int substLen = subst.length();
    int matchLen = match.length();
    while (0 <= (pos = sbuff.indexOf( match, fromIndex))) {
      sbuff.replace( pos, pos + matchLen, subst);
      fromIndex = pos + substLen; // make sure dont get into an infinite loop
    }
  }

  /**
   * Return true if all characters are numeric.
   */
  static public boolean isDigits( String s) {
    for (int i=0; i< s.length(); i++)
      if (!Character.isDigit(s.charAt(i)))
        return false;
    return true;
  }

  /******************************************************************/
  /**
   * Replace special characters with entities for HTML content.
   * special: '&', '<', '>', '\n'
   * @param x string to quote
   * @return equivilent string using entities for any special chars
   */
  static public String quoteHtmlContent(String x) {
    return replace(x, htmlIn, htmlOut);
  }
  private static char[] htmlIn = {'&', '<', '>', '\n'};
  private static String[] htmlOut = {"&amp;", "&lt;", "&gt;", "\n<p>" };

  /**
   * Replace special characters with entities for XML attributes.
   * special: '&', '<', '>', '\'', '"', '\r', '\n'
   * @param x string to quote
   * @return equivilent string using entities for any special chars
   */
  static public String quoteXmlAttribute(String x) {
    return replace(x, xmlIn, xmlOut);
  }

  /**
   * Reverse XML quoting to recover the original string.
   * @param x string to quote
   * @return equivilent string
   */
  static public String unquoteXmlAttribute(String x) {
    return unreplace(x, xmlOut, xmlIn);
  }

  private static char[] xmlIn = {'&', '<', '>', '\'', '"', '\r', '\n'};
  private static String[] xmlOut = {"&amp;", "&lt;", "&gt;", "&apos;", "&quot;", "&#13;", "&#10;" };

  static private String replace(String x, char[] replaceChar, String[] replaceWith) {
    // common case no replacement
    boolean ok = true;
    for (int i = 0; i < replaceChar.length; i++) {
      int pos = x.indexOf(replaceChar[i]);
      ok &= (pos < 0);
    }
    if (ok)
      return x;

    // gotta do it
    StringBuffer sb = new StringBuffer(x);
    for (int i=0; i<replaceChar.length; i++) {
      int pos = x.indexOf(replaceChar[i]);
      if (pos >= 0)
        replace( sb, replaceChar[i], replaceWith[i]);
    }

    return sb.toString();
  }


  static private String unreplace(String x, String[] orgReplace, char[] orgChar) {
    // common case no replacement
    boolean ok = true;
    for (int i=0; i<orgReplace.length; i++) {
      int pos = x.indexOf(orgReplace[i]);
      ok &= (pos < 0);
    }
    if (ok) return x;

    // gotta do it
    StringBuffer result = new StringBuffer(x);
    for (int i=0; i<orgReplace.length; i++) {
      int pos = result.indexOf(orgReplace[i]);
      if (pos >= 0)
        unreplace( result, orgReplace[i], orgChar[i]);
    }

    return result.toString();
  }

  /**
   * Replace any char "out" in sb with "in".
   * @param sb StringBuffer to replace
   * @param out repalce this character
   * @param in with this string
   */
  static public void replace(StringBuffer sb, char out, String in) {
    for (int i = 0; i < sb.length(); i++) {
      if (sb.charAt(i) == out) {
        sb.replace(i, i+1, in);
        i += in.length();
      }
    }
  }

  /**
   * Replace any String "out" in sb with char "in".
   * @param sb StringBuffer to replace
   * @param out repalce this String
   * @param in with this char
   */
  static public void unreplace(StringBuffer sb, String out, char in) {
    int pos;
    while( 0 <= (pos = sb.indexOf(out))) {
      sb.setCharAt(pos, in);
      sb.delete(pos+1, pos+out.length());
    }
  }

  /**
   * Replace any char "out" in s with "in".
   * @param s string to replace
   * @param out repalce this character
   * @param in with this string
   * @return modified string if needed
   */
  static public String replace(String s, char out, String in) {
    if (s.indexOf(out) < 0) return s;

    // gotta do it
    StringBuffer sb = new StringBuffer(s);
    replace(sb, out, in);
    return sb.toString();
  }


  /////////////////////////////////////////////////////////////

  private static void testMatch() {

    String[] match = {"$test", "$subst", "barf"};
    String[] subst = {"TESTING123", "ok", "BARFOLA"};

    System.out.println(substitute("$test $test $test", match, subst));
    System.out.println(substitute("test $test test", match, subst));
    System.out.println(substitute("$subst $SUbST $barf", match, subst));
    System.out.println(substitute("why cant you just $test??", match, subst));

  }

  /** test */
  public static void main(String args[]) {

    System.out.println("<"+remove("startRE:RE:RE:end", "RE:")+"> should be <startend>");
    System.out.println("<"+remove("RE:RE:RE:end", "RE:")+"> should be <end>");
    System.out.println("<"+remove("startRE:RE:RE:", "RE:")+"> should be <start>");

    System.out.println("<"+remove("RE:RE:RE:", ":RE:")+"> should be <RERE:>");
    System.out.println("<"+remove("RE:RE:RE:", "RE")+"> should be <:::>");
    System.out.println("<"+remove("RE:middleRE:", "RE:")+"> should be <middle>");

  }

}


/* Change History:
   $Log: StringUtil.java,v $
   Revision 1.10  2004/11/07 03:00:53  caron
   *** empty log message ***

   Revision 1.9  2004/11/04 00:39:24  caron
   add XML quote/unquote

   Revision 1.8  2004/09/22 21:26:15  caron
   add new methods


   Revision 1.4  2004/05/21 05:57:35  caron
   release 2.0b

   Revision 1.3  2004/05/11 23:30:36  caron
   release 2.0a

   Revision 1.2  2004/02/20 05:02:54  caron
   release 1.3

*/