package org.maachang.rimdb.index.string ;

/**
 * インデックス用文字情報.
 *
 * @version 2014/07/04
 * @author  masahito suzuki
 * @since   rimdb-1.00
 */
public final class IString implements Comparable<IString> {
    protected final char[] value ;
    protected final int length ;
    
    /**
     * コンストラクタ.
     * ゼロ文字を表すオブジェクトを生成.
     */
    public IString() {
        value = new char[ 0 ] ;
        length = 0 ;
    }
    
    /**
     * コンストラクタ.
     * @param v 対象のキャラクタを設定.
     */
    public IString( final char[] v ) {
        if( v == null ) {
            value = new char[ 0 ] ;
            length = 0 ;
        }
        else {
            value = v ;
            length = v.length ;
        }
    }
    
    /**
     * コンストラクタ.
     * @param v 対象の文字を設定.
     */
    public IString( final String v ) {
        if( v == null || v.length() == 0 ) {
            value = new char[ 0 ] ;
            length = 0 ;
        }
        else {
            final int len = v.length() ;
            final char[] vv = new char[ len ] ;
            for( int i = 0 ; i < len ; i ++ ) {
                vv[ i ] = v.charAt( i ) ;
            }
            value = vv ;
            length = len ;
        }
    }
    
    /**
     * 情報が存在しないかチェック.
     * @return boolean [true]の場合、空です.
     */
    public final boolean isEmpty() {
        return length == 0 ;
    }
    
    /**
     * 同一チェック.
     * @param o チェック対象を設定します.
     * @return boolean [true]の場合、一致しています.
     */
    public final boolean equals( final Object o ) {
        if( o == this ) return true ;
        if( o instanceof IString ) {
            final IString oo = ( IString )o ;
            if( oo.length == length && oo.value[ 0 ] == value[ 0 ] ) {
                int i = 0 ;
                final int len = length ;
                final char[] ooo = oo.value ;
                final char[] v = value ;
                while( ++ i < len && ooo[ i ] == v[ i ] ) ;
                return ( i == len ) ;
            }
        }
        else if( o instanceof String ) {
            final String oo = (String)o ;
            if( oo.length() == length && oo.charAt( 0 ) == value[ 0 ] ) {
                int i = 0 ;
                final int len = length ;
                final char[] v = value ;
                while( ++ i < len && oo.charAt( i ) == v[ i ] ) ;
                return ( i == len ) ;
            }
        }
        return false ;
    }
    
    /**
     * 同一チェック.
     * @param off チェック元の文字オフセット値を設定します.
     * @param o チェック先の文字を設定します.
     * @param oOff チェック先の文字オフセット値を設定します.
     * @param len チェック先の文字長を設定します.
     * @return boolean [true]の場合、一致しています.
     */
    public final boolean equals( final int off,IString o,final int oOff,final int len ) {
        if( o.value[ oOff ] == value[ off ] ) {
            int i = 0 ;
            final char[] oval = o.value ;
            final char[] v = value ;
            while( ++ i < len && oval[ oOff + i ] == v[ off + i ] ) ;
            return i == len ;
        }
        return false ;
    }
    
    /**
     * 比較.
     * @param n 比較先の情報を設定します.
     * @return int 0以上の場合、比較元が大きい.
     *             0以下の場合、比較先が大きい.
     *             0の場合は同一.
     */
    public final int compareTo( final IString n ) {
        if( n == this ) return 0 ;
        final int len = ( length < n.length ) ? length : n.length ;
        if( n.value[ 0 ] == value[ 0 ] ) {
            int i = 0 ;
            final char[] ooo = n.value ;
            final char[] v = value ;
            while( ++ i < len && ooo[ i ] == v[ i ] ) ;
            return ( i == len ) ? length - n.length : (int)v[ i ] - (int)ooo[ i ] ;
        }
        return (int)value[ 0 ] - (int)n.value[ 0 ] ;
    }
    
    /**
     * このオブジェクトの方が大きいかチェック.
     * compareToと違うのは、文字比較が同一の場合、元の長さではチェックしない.
     * つまり、abcd と abc を比較した場合、同一とみなすと言うこと。
     * @param n 比較先の情報を設定します.
     * @return int 0以上の場合、比較元が大きい.
     *             0以下の場合、比較先が大きい.
     *             0の場合は同一.
     */
    public final int toBig( final IString n ) {
        if( n == this ) return 0 ;
        final int len = ( length < n.length ) ? length : n.length ;
        if( n.value[ 0 ] == value[ 0 ] ) {
            int i = 0 ;
            final char[] ooo = n.value ;
            final char[] v = value ;
            while( ++ i < len && ooo[ i ] == v[ i ] ) ;
            return ( i == len ) ? 0 : (int)v[ i ] - (int)ooo[ i ] ;
        }
        return (int)value[ 0 ] - (int)n.value[ 0 ] ;
    }
    
    /**
     * indexof.
     * @param n 対象の文字を設定します.
     * @param off オフセット値を設定します.
     * @return int 一致場所が返却される.-1の場合は存在しない.
     */
    public final  int indexOf( final String n,final int off ) {
        final int len = n.length() ;
        if( len == 0 || off + len > length ) {
            return -1 ;
        }
        if( len == 1 ) {
            char[] v = value ;
            char nn = n.charAt( 0 ) ;
            int vLen = length ;
            for( int i = off ; i < vLen ; i ++ ) {
                if( nn != v[ i ] ) {
                    while( ++ i < vLen && nn != v[ i ] ) ;
                    if( vLen != i ) {
                        return i ;
                    }
                }
                else {
                    return i ;
                }
            }
        }
        else {
            final char[] v = value ;
            final int vLen = length - (len-1) ;
            final char first = n.charAt( 0 ) ;
            int j,k,next ;
            for( int i = off ; i < vLen ; i ++ ) {
                if( v[ i ] != first ) {
                    while( ++ i < vLen && v[ i ] != first ) ;
                }
                if( i < vLen ) {
                    for( next = i + len , j = i + 1 , k = 1 ;
                        j < next && v[ j ] == n.charAt( k ) ;
                        j ++ , k ++ ) ;
                    if( j == next ) {
                        return i ;
                    }
                }
            }
        }
        return -1 ;
    }
    
    /**
     * indexof.
     * @param n 対象の文字を設定します.
     * @param off オフセット値を設定します.
     * @return int 一致場所が返却される.-1の場合は存在しない.
     */
    public final int indexOf( final char[] n,final int off ) {
        final int len = n.length ;
        if( len == 0 || off + len > length ) {
            return -1 ;
        }
        if( len == 1 ) {
            final char[] v = value ;
            final char nn = n[ 0 ] ;
            final int vLen = length ;
            for( int i = off ; i < vLen ; i ++ ) {
                if( nn != v[ i ] ) {
                    while( ++ i < vLen && nn != v[ i ] ) ;
                    if( vLen != i ) {
                        return i ;
                    }
                }
                else {
                    return i ;
                }
            }
        }
        else {
            final char[] v = value ;
            final int vLen = length - (len-1) ;
            final char first = n[ 0 ] ;
            int j,k,next ;
            for( int i = off ; i < vLen ; i ++ ) {
                if( first != v[ i ] ) {
                    while( ++ i < vLen && v[ i ] != first ) ;
                }
                if( i < vLen ) {
                    for( next = i + len , j = i + 1 , k = 1 ;
                        j < next && v[ j ] == n[ k ] ;
                        j ++ , k ++ ) ;
                    if( j == next ) {
                        return i ;
                    }
                }
            }
        }
        return -1 ;
    }
    
    /**
     * indexof.
     * @param n 対象の文字を設定します.
     * @param off オフセット値を設定します.
     * @return int 一致場所が返却される.-1の場合は存在しない.
     */
    public final int indexOf( final IString n,final int off ) {
        if( n.isEmpty() ) {
            return -1 ;
        }
        return indexOf( n.value,off ) ;
    }
    
    /**
     * 開始一致チェック.
     * @param n 対象の文字を設定します.
     * @return boolean [true]の場合、開始条件が一致しています.
     */
    public final boolean startsWith( String n ) {
        if( n.length() > length ) {
            return false ;
        }
        if( n.charAt( 0 ) == value[ 0 ] ) {
            int i = 0 ;
            final int len = n.length() ;
            final char[] v = value ;
            while( ++ i < len && n.charAt( i ) == v[ i ] ) ;
            return ( i == len ) ;
        }
        return false ;
    }
    
    /**
     * 開始一致チェック.
     * @param n 対象の文字を設定します.
     * @return boolean [true]の場合、開始条件が一致しています.
     */
    public final boolean startsWith( final char[] n ) {
        if( n.length > length ) {
            return false ;
        }
        if( n[ 0 ] == value[ 0 ] ) {
            int i = 0 ;
            final int len = n.length ;
            final char[] v = value ;
            while( ++ i < len && n[ i ] == v[ i ] ) ;
            return ( i == len ) ;
        }
        return false ;
    }
    
    /**
     * 開始一致チェック.
     * @param n 対象の文字を設定します.
     * @return boolean [true]の場合、開始条件が一致しています.
     */
    public final boolean startsWith( final IString n ) {
        if( n.isEmpty() ) {
            return false ;
        }
        return startsWith( n.value ) ;
    }
    
    /**
     * 終端一致チェック.
     * @param n 対象の文字を設定します.
     * @return boolean [true]の場合、終端条件が一致しています.
     */
    public final boolean endsWith( final String n ) {
        if( n.length() > length ) {
            return false ;
        }
        final int off = length - n.length() ;
        if( n.charAt( 0 ) == value[ off ] ) {
            int i = 0 ;
            final int len = length - off ;
            final char[] v = value ;
            while( ++ i < len && n.charAt( i ) == v[ off + i ] ) ;
            return ( i == len ) ;
        }
        return false ;
    }
    
    /**
     * 終端一致チェック.
     * @param n 対象の文字を設定します.
     * @return boolean [true]の場合、終端条件が一致しています.
     */
    public final boolean endsWith( final char[] n ) {
        if( n.length > length ) {
            return false ;
        }
        final int off = length - n.length ;
        if( n[ 0 ] == value[ off ] ) {
            int i = 0 ;
            final int len = length - off ;
            final char[] v = value ;
            while( ++ i < len && n[ i ] == v[ off + i ] ) ;
            return ( i == len ) ;
        }
        return false ;
    }
    
    /**
     * 終端一致チェック.
     * @param n 対象の文字を設定します.
     * @return boolean [true]の場合、終端条件が一致しています.
     */
    public final boolean endsWith( final IString n ) {
        if( n.isEmpty() ) {
            return false ;
        }
        return endsWith( n.value ) ;
    }
    
    /**
     * 長さを取得.
     * @return int 文字列長が返却されます.
     */
    public final int length() {
        return length ;
    }
    
    /**
     * 現在のキャラクタ配列を返却.
     * @return char[] char配列が返却されます.
     */
    public final char[] getChars() {
        return value ;
    }
    
    /**
     * substring.
     * @param s 開始位置を設定します.
     * @param e 終了位置を設定します.
     * @return String substringされた文字が返却されます.
     */
    public final String substring( final int s,final int e ) {
        return String.copyValueOf( value,s,e-s ) ;
    }
    
    /**
     * substring.
     * @param s 開始位置を設定します.
     * @return String substringされた文字が返却されます.
     */
    public final String substring( final int s ) {
        return String.copyValueOf( value,s,value.length-s ) ;
    }
    
    /**
     * substring.
     * @param s 開始位置を設定します.
     * @param e 終了位置を設定します.
     * @return IString substringされた文字が返却されます.
     */
    public final IString subIString( final int s,final int e ) {
        final int ln = e-s ;
        final char[] c = new char[ ln ] ;
        System.arraycopy( value,s,c,0,ln ) ;
        return new IString( c ) ;
    }
    
    /**
     * substring.
     * @param s 開始位置を設定します.
     * @return IString substringされた文字が返却されます.
     */
    public final IString subIString( final int s ) {
        final int ln = value.length-s ;
        final char[] c = new char[ ln ] ;
        System.arraycopy( value,s,c,0,ln ) ;
        return new IString( c ) ;
    }
    
    /**
     * 文字列化.
     * @return String 文字列が返却されます.
     */
    public final String toString() {
        return String.copyValueOf( value ) ;
    }
    
}
