/*


    ========== licence begin GPL
    Copyright (C) 2002-2003 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end


*/

package com.sap.dbtech.util.printf;


import com.sap.dbtech.util.MessageKey;
import com.sap.dbtech.util.MessageTranslator;

/**
 *
 */
public class PrintfFormat {
    private Formatter [] formats;
    private int elements;
/**
 *
 * @param formatString java.lang.String
 * @exception com.sap.dbtech.util.printf.FormatException The exception description.
 */
public PrintfFormat(String formatString)
        throws FormatException
{
    this.formats = this.parseFormatString (formatString);
}
/**
 *
 * @return com.sap.dbtech.util.printf.Formatter
 * @param format java.lang.String
 * @param kind char
 * @exception lava.clib.stdio.PrintfFormatException The exception description.
 */
private Formatter createFormatter (String format, char kind) throws FormatException {
    Formatter result;

    switch (kind) {
        case 's':
            result = new StringFormatter (format);
            break;
        case 'd':
        case 'i':
        case 'o':
        case 'x':
            result = new IntegerFormatter (format);
            break;
        default:
            throw new FormatException(MessageTranslator.translate(MessageKey.ERROR_FORMAT_UNKNOWN,
                                                                  String.valueOf(kind)));
    }
    return result;
}
/**
 *
 * @return java.lang.String
 * @param objects java.lang.Object[]
 */
public String format (Object [] objects)
    throws PrintfArgumentMismatch
{
    OArrayEnumeration enume = new OArrayEnumeration (objects);
    StringBuffer buf = new StringBuffer ();

    for (int i = 0; i < this.elements; ++i) {
        buf.append (this.formats [i].format (enume));
    }
    if (enume.hasMoreElements ()) {
        throw new PrintfArgumentMismatch (MessageTranslator.translate(MessageKey.ERROR_FORMAT_TOOMANYARGS));
    }
    return buf.toString ();
}
/**
 *
 * @return com.sap.dbtech.util.printf.Formatter[]
 * @param formatString java.lang.String
 * @exception lava.clib.stdio.PrintfFormatException The exception description.
 */
private Formatter [] parseFormatString (String formatString) throws FormatException {
    Formatter [] result;
    int arrayPos;
    int arrayLength = 8;
    int stringPos = 0;
    int lastPos = 0;
    int endPos = formatString.length ();
    char current;
    int formatStart;

    result = new Formatter [arrayLength];
    arrayPos = 0;

    while (stringPos < endPos) {
        stringPos = formatString.indexOf ('%', lastPos);
        if (stringPos == -1) {
            break;
        }
        if (formatString.charAt (stringPos + 1) == '%') {
            // escaped %
            result [arrayPos] = new LiteralFormatter ("%");
            ++arrayPos;
            ++stringPos;
        }
        else {
            // real format string
            /*
             * reserve three slots
             */
            if (arrayPos + 3 > arrayLength) {
                Formatter [] tmp = new Formatter [arrayLength * 2];
                System.arraycopy (result, 0, tmp, 0, arrayLength);
                arrayLength *= 2;
                result = tmp;
            }
            /*
             * copy literal
             */
            result [arrayPos] = new LiteralFormatter (formatString.substring (lastPos, stringPos));
            ++arrayPos;
            lastPos = stringPos;
            /*
             * find end of format
             */
            formatStart = stringPos;
            do {
                ++stringPos;
                current = formatString.charAt (stringPos);
            } while (!(('a' <= current) && (current <= 'z'))
                || (('A' <= current) && (current <= 'Z')));
            result [arrayPos] = this.createFormatter (
                formatString.substring (lastPos, stringPos + 1), current);
            ++arrayPos;
            lastPos = stringPos + 1;
        }
    }
    result [arrayPos] = new LiteralFormatter (formatString.substring (lastPos));
    this.elements = arrayPos + 1;
    return result;
}
}
