/**********************************************************************
 *
 * This file is part of HBCI4Java.
 * Copyright (c) 2001-2008 Stefan Palme
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **********************************************************************/

/** @internal
    @brief Collection of HBCI datatypes.

    This package contains a collection of classes, where each class represents
    one of the datatypes defined in HBCI syntax descriptions (e.g. AN for
    alphanumeric data, Bin for binary data etc.).
    These classes are used during the message generation process either when
    building a new message to be sent or when parsing a received message.
    These classes are never instantiated directly, but they are loaded and instantiated
    dynamically (for a certain syntax element, the name of the class to be used
    for storing its value is determined by the value of the attribute @c type in
    the syntax description for this syntax element). The classname to be loaded is
    built from the @c type attribute by prepending @c org.kapott.hbci.datatypes.Syntax */
package org.kapott.hbci.datatypes; 

import org.kapott.hbci.exceptions.InvalidArgumentException;
import org.kapott.hbci.manager.HBCIUtilsInternal;

/* @internal
    @brief Abstract base class for datatypes.

    This is an abstract base class for all classes that will represent a certain HBCI-datatype.

    @author $Author: willuhn $
*/
public abstract class SyntaxDE
{
    private String content;  /**< @internal @brief contains the value of the DE in human readable format */
    
    private void initData(String x,int minsize,int maxsize)
    {
        content=null;
        setContent(x,minsize,maxsize);
    }

    /** @internal 
        @brief Creates a new instance of a datatype.

        In this constructor the data element will be initialized with the given value @p x.
        During initializing process the size constraints for this element will be verified.
        If verification fails, an IllegalArgumentException will be thrown.

        @param x The string representation of the init value.
        @param minsize The minimum size (string length) of the init value.
        @param maxsize The maximum size (string length) of the init value. If this is zero, no
                       checking for @p maxsize will be done.
    */
    public SyntaxDE(String x, int minsize, int maxsize)
    {
        initData(x,minsize,maxsize);
    }
    
    public void init(String x, int minsize, int maxsize)
    {
        initData(x,minsize,maxsize);
    }
    
    public void init(StringBuffer x, int minsize, int maxsize)
    {
        initData(x.toString(),minsize,maxsize);
    }
    
    private void initData()
    {
        content=null;
    }

    /** @internal @overload */
    protected SyntaxDE()
    {
        initData();
    }
    
    protected void init()
    {
        initData();
    }

    /** @internal
        @brief Sets the value for a data element.

        @param st The string representation of the init value.
        @param minsize The minimum size (string length) of the init value.
        @param maxsize The maximum size (string length) of the init value. If this is zero, no
                       checking for @p maxsize will be done.
        @exception IllegalArgumentException when the length of @p x is not in the range
                                            @p minsize ... @p maxsize
    */
    protected final void setContent(String st,int minsize,int maxsize)
    {
        /* die stringlaenge muss zwischen minsize und maxsize liegen,
           im falle 'maxsize=0' kann sie beliebig gross sein */
        int len=st.length();
        if (len<minsize || (maxsize!=0 && len>maxsize)) {
            String msg=HBCIUtilsInternal.getLocMsg("EXC_DT_INV_STRINGLEN",new Object[] {
                                           st,Integer.toString(len),Integer.toString(minsize),Integer.toString(maxsize)});
            if (len==0 || !HBCIUtilsInternal.ignoreError(null,"client.errors.ignoreWrongDataLengthErrors",msg))
                throw new InvalidArgumentException(msg);
        }

        content=st;
    }

    /** @internal
        @brief Returns the value of the data element in the form needed in HBCI messages

        @param zero Just a dummy argument to overload the toString method.
        @return A String containing the HBCI representation of this data element
    */
    public String toString(int zero)
    {
        return (content!=null)?content:"";
    }

    /** @internal @brief Returns the current @c content. 

        @return den aktuellen Inhalt des SyntaxDE in der intern gespeicherten
                Form (human-readable)
     */
    protected String getContent()
    {
        return content;
    }

    // -----------------------------------------------------------------------------------

    /** @internal
        @brief Returns the index, where the next value in the HBCI message @c res
               starts.

        This method is needed when parsing HBCI messages. It checks the first
        character of String @p res. If this character is one of the
        HBCI-specific data-element-delimiters, 1 will be returned, else 0
        (i.e. the return value is the index into the String @p res where we
        can start fetching the next syntax token)

        @param res A part of an HBCI message to be parsed.
        @return Index into @p res where next token starts.
    */
    protected static int skipPreDelim(StringBuffer res)
    {
        int ret = 0;

        if (res.length() != 0) {
            char ch = res.charAt(0);
 
            if (ch == '\'' || ch == '+' || ch == ':') {
                ret++;
            }
        }

        return ret;
    }

    /** @internal
        @brief Returns the index of the next delimiter token.

        This method is needed when parsing an HBCI message. It scans
        @p res starting at position @p startidx for the next occurence
        of an HBCI-specific data-element-delimiter and returns its
        position.

        @param res Part of an HBCI-message to be parsed.
        @param startidx Index position where to start looking for the next delimiter.
        @return The position of the next delimiter character in @p res. If there is no
                next delimiter character, the return value will be the next character
                after the end of the String @p res (i.e. will equal @c res.length())
    */
    public static int findNextDelim(StringBuffer res, int startidx)
    {
        int ret = startidx;
        boolean quoted = false;
        boolean quit = false;
        boolean inBinLen = false;
        int binLenStart = 0;
        int len=res.length();

        while (ret<len && !quit) {
            char ch=res.charAt(ret++);

            if (!quoted) {
                if (ch == '?') {
                    quoted = true;
                } else if (ch == '@') {
                    if (!inBinLen) {
                        inBinLen = true;
                        binLenStart = ret;
                    } else {
                        int binLenEnd=ret-1;
                        String st=res.substring(binLenStart, binLenEnd);
                        int binLen = Integer.parseInt(st);

                        ret+=binLen;
                        inBinLen=false;
                    }
                } else if (ch == '\'' || ch == '+' || ch == ':') {
                    ret--;
                    quit=true;
                }
            } else {
                quoted = false;
            }
        }

        return ret;
    }

    /** @internal @brief Returns the human-readable value of this data element. 

        @return Die human-reable Repraesentation dieses Elementes
    */
    public String toString()
    {
        return (content==null)?"":content;
    }
    
    public void destroy()
    {
        content=null;
    }
}
