package org.maachang.jni.io ;

/**
 * 文字列から他オブジェクト変換用.
 * 
 * @version 2010/10/30
 * @author masahito suzuki
 * @since   SeabassNativeIO-1.0.2
 */
public abstract class StringConverter {
    private StringConverter(){}
    
    /**
     * 文字列内容が数値かチェック.
     * @param num 対象の文字列を設定します.
     * @return int [-1]の場合、文字列内は数値以外です.
     *             [0]の場合は、文字列内は整数です.
     *             [1]の場合は、文字列内は、小数点ありの数値です.
     */
    public static final int isNumberType( String num ) {
        if( num == null || num.length() <= 0 ) {
            return -1 ;
        }
        int start = 0 ;
        if( num.startsWith( "-" ) ) {
            start = 1 ;
        }
        boolean dt = false ;
        int len = num.length() ;
        if( start < len ) {
            for( int i = start ; i < len ; i ++ ) {
                char c = num.charAt( i ) ;
                if( c == '.' ) {
                    if( dt ) {
                        return -1 ;
                    }
                    dt = true ;
                }
                else if( ( c >= '0' && c <= '9' ) == false ) {
                    return -1 ;
                }
            }
        }
        else {
            return -1 ;
        }
        return (dt)?1:0 ;
    }
    
    /**
     * 最適な型に変換.
     * @param o 変換対象のオブジェクトを設定します.
     * @return Object 変換されたオブジェクトが返されます.
     */
    public static final Object parseObject( Object o ) {
        if( ( o instanceof String ) == false ) {
            return o ;
        }
        String s = (String)o ;
        Object ret = null ;
        try {
            switch( isNumberType( s ) ) {
                case -1 : ret = parseBoolean( s ) ; break ;
                case 0 : ret = parseNumber( s ) ; break ;
                case 1 : ret = parseDouble( s ) ; break ;
            }
        } catch( Exception e ) {
            ret = o ;
        }
        return ret ;
    }
    
    /**
     * 文字列から、Boolean型に変換.
     * @param s 対象の文字列を設定します.
     * @return boolean Boolean型が返されます.
     */
    public static final boolean parseBoolean( String s ) {
        if( s == null || s.length() <= 0 ) {
            throw new IllegalArgumentException( "文字列は空です" ) ;
        }
        if( s.length() == 4 ) {
            if( "true" == s || "true".equals( s ) ) {
                return true ;
            }
        }
        else if( s.length() == 5 ) {
            if( "false" == s || "false".equals( s ) ) {
                return false ;
            }
        }
        throw new NumberFormatException( "Boolean変換に失敗しました:"+s ) ;
    }
    
    /**
     * 最適な数値型に変換.
     * @param s 対象の文字列を設定します.
     * @return Object 最適な数値型が返されます.
     */
    public static final Object parseNumber( String s ) {
        long n = parseLong( s ) ;
        if( n <= -1L ) {
            if( ( (n*-1L) & 0x7fffffff80000000L ) != 0L ) {
                return n ;
            }
            return (int)n ;
        }
        if( ( n & 0x7fffffff80000000L ) != 0L ) {
            return n ;
        }
        return (int)n ;
    }
    
    /**
     * 文字列から、byte型数値に変換.
     * @param num 対象の文字列を設定します.
     * @return byte byte型で変換された数値が返されます.
     */
    public static final byte parseByte( String num ) {
        int len ;
        if( num == null || ( len = num.length() ) <= 0 ) {
            throw new IllegalArgumentException( "文字列は空です" ) ;
        }
        int ret = 0 ;
        int v = 1 ;
        int end = 0 ;
        char c ;
        if( num.charAt( 0 ) == '-' ) {
            end = 1 ;
        }
        int dot = num.indexOf( "." ) ;
        if( dot != -1 ) {
            len = dot ;
        }
        for( int i = len-1 ; i >= end ; i -- ) {
            c = num.charAt( i ) ;
            if( c >= '0' && c <= '9' ) {
                ret += ( v * (int)( c - '0' ) ) ;
                v *= 10 ;
            }
            else {
                throw new NumberFormatException( "数値変換に失敗しました:"+num ) ;
            }
        }
        if( end == 1 ) {
            return ( byte )( ( ( ret ) & 0x000000ff ) * -1 ) ;
        }
        return ( byte )( ret & 0x000000ff ) ;
    }
    
    /**
     * 文字列から、short型数値に変換.
     * @param num 対象の文字列を設定します.
     * @return short short型で変換された数値が返されます.
     */
    public static final short parseShort( String num ) {
        int len ;
        if( num == null || ( len = num.length() ) <= 0 ) {
            throw new IllegalArgumentException( "文字列は空です" ) ;
        }
        int ret = 0 ;
        int v = 1 ;
        int end = 0 ;
        char c ;
        if( num.charAt( 0 ) == '-' ) {
            end = 1 ;
        }
        int dot = num.indexOf( "." ) ;
        if( dot != -1 ) {
            len = dot ;
        }
        for( int i = len-1 ; i >= end ; i -- ) {
            c = num.charAt( i ) ;
            if( c >= '0' && c <= '9' ) {
                ret += ( v * (int)( c - '0' ) ) ;
                v *= 10 ;
            }
            else {
                throw new NumberFormatException( "数値変換に失敗しました:"+num ) ;
            }
        }
        if( end == 1 ) {
            return ( short )( ( ( ret ) & 0x0000ffff ) * -1 ) ;
        }
        return ( short )( ret & 0x0000ffff ) ;
    }
    
    /**
     * 文字列から、int型数値に変換.
     * @param num 対象の文字列を設定します.
     * @return int int型で変換された数値が返されます.
     */
    public static final int parseInt( String num ) {
        int len ;
        if( num == null || ( len = num.length() ) <= 0 ) {
            throw new IllegalArgumentException( "文字列は空です" ) ;
        }
        int ret = 0 ;
        int v = 1 ;
        int end = 0 ;
        char c ;
        if( num.charAt( 0 ) == '-' ) {
            end = 1 ;
        }
        int dot = num.indexOf( "." ) ;
        if( dot != -1 ) {
            len = dot ;
        }
        for( int i = len-1 ; i >= end ; i -- ) {
            c = num.charAt( i ) ;
            if( c >= '0' && c <= '9' ) {
                ret += ( v * (int)( c - '0' ) ) ;
                v *= 10 ;
            }
            else {
                throw new NumberFormatException( "数値変換に失敗しました:"+num ) ;
            }
        }
        if( end == 1 ) {
            return ret * -1 ;
        }
        return ret ;
    }
    
    /**
     * 文字列から、long型数値に変換.
     * @param num 対象の文字列を設定します.
     * @return long long型で変換された数値が返されます.
     */
    public static final long parseLong( String num ) {
        int len ;
        if( num == null || ( len = num.length() ) <= 0 ) {
            throw new IllegalArgumentException( "文字列は空です" ) ;
        }
        long ret = 0L ;
        long v = 1L ;
        int end = 0 ;
        char c ;
        if( num.charAt( 0 ) == '-' ) {
            end = 1 ;
        }
        int dot = num.indexOf( "." ) ;
        if( dot != -1 ) {
            len = dot ;
        }
        for( int i = len-1 ; i >= end ; i -- ) {
            c = num.charAt( i ) ;
            if( c >= '0' && c <= '9' ) {
                ret += ( v * (long)( c - '0' ) ) ;
                v *= 10L ;
            }
            else {
                throw new NumberFormatException( "数値変換に失敗しました:"+num ) ;
            }
        }
        if( end == 1 ) {
            return ret * -1L ;
        }
        return ret ;
    }
    
    /**
     * 文字列から、float型数値に変換.
     * @param num 対象の文字列を設定します.
     * @return float float型で変換された数値が返されます.
     */
    public static final float parseFloat( String num ) {
        int len ;
        if( num == null || ( len = num.length() ) <= 0 ) {
            throw new IllegalArgumentException( "文字列は空です" ) ;
        }
        float ret = 0f ;
        float v = 1f ;
        int end = 0 ;
        char c ;
        if( num.charAt( 0 ) == '-' ) {
            end = 1 ;
        }
        int dot = num.indexOf( "." ) ;
        if( dot == -1 ) {
            for( int i = len-1 ; i >= end ; i -- ) {
                c = num.charAt( i ) ;
                if( c >= '0' && c <= '9' ) {
                    ret += ( v * (float)( c - '0' ) ) ;
                    v *= 10f ;
                }
                else {
                    throw new NumberFormatException( "数値変換に失敗しました:"+num ) ;
                }
            }
            if( end == 1 ) {
                return ret * -1f ;
            }
            return ret ;
        }
        else {
            for( int i = dot-1 ; i >= end ; i -- ) {
                c = num.charAt( i ) ;
                if( c >= '0' && c <= '9' ) {
                    ret += ( v * (float)( c - '0' ) ) ;
                    v *= 10f ;
                }
                else {
                    throw new NumberFormatException( "数値変換に失敗しました:"+num ) ;
                }
            }
            float fret = 0f ;
            v = 1f ;
            for( int i = len-1 ; i > dot ; i -- ) {
                c = num.charAt( i ) ;
                if( c >= '0' && c <= '9' ) {
                    fret += ( v * (float)( c - '0' ) ) ;
                    v *= 10f ;
                }
                else {
                    throw new NumberFormatException( "数値変換に失敗しました:"+num ) ;
                }
            }
            if( end == 1 ) {
                ret = ( ret + ( fret / v ) ) * -1f ;
            }
            else {
                ret += ( fret / v ) ;
            }
            return ret ;
        }
    }
    
    /**
     * 文字列から、double型数値に変換.
     * @param num 対象の文字列を設定します.
     * @return double double型で変換された数値が返されます.
     */
    public static final double parseDouble( String num ) {
        int len ;
        if( num == null || ( len = num.length() ) <= 0 ) {
            throw new IllegalArgumentException( "文字列は空です" ) ;
        }
        double ret = 0d ;
        double v = 1d ;
        int end = 0 ;
        char c ;
        if( num.charAt( 0 ) == '-' ) {
            end = 1 ;
        }
        int dot = num.indexOf( "." ) ;
        if( dot == -1 ) {
            for( int i = len-1 ; i >= end ; i -- ) {
                c = num.charAt( i ) ;
                if( c >= '0' && c <= '9' ) {
                    ret += ( v * (double)( c - '0' ) ) ;
                    v *= 10d ;
                }
                else {
                    throw new NumberFormatException( "数値変換に失敗しました:"+num ) ;
                }
            }
            if( end == 1 ) {
                return ret * -1d ;
            }
            return ret ;
        }
        else {
            for( int i = dot-1 ; i >= end ; i -- ) {
                c = num.charAt( i ) ;
                if( c >= '0' && c <= '9' ) {
                    ret += ( v * (double)( c - '0' ) ) ;
                    v *= 10d ;
                }
                else {
                    throw new NumberFormatException( "数値変換に失敗しました:"+num ) ;
                }
            }
            double dret = 0d ;
            v = 1d ;
            for( int i = len-1 ; i > dot ; i -- ) {
                c = num.charAt( i ) ;
                if( c >= '0' && c <= '9' ) {
                    dret += ( v * (double)( c - '0' ) ) ;
                    v *= 10d ;
                }
                else {
                    throw new NumberFormatException( "数値変換に失敗しました:"+num ) ;
                }
            }
            if( end == 1 ) {
                ret = ( ret + ( dret / v ) ) * -1d ;
            }
            else {
                ret += ( dret / v ) ;
            }
            return ret ;
        }
    }
    
}
