package railo.runtime.text.csv;

import java.util.ArrayList;
import java.util.List;

import railo.commons.lang.StringUtil;


public class CSVString {

    private char[] buffer;
    private int pos;
    private char delim;

    public CSVString( String input, char delim ) {

        this.buffer = input.toCharArray();
        this.delim = delim;
    }

    public List<List<String>> parse() {

        List<List<String>> result = new ArrayList();
        List<String> line = new ArrayList();

        if ( buffer.length == 0 )
            return result;

        StringBuilder sb = new StringBuilder();
        char c;

        do {

            c = buffer[ pos ];

            if ( c == '"' || c == '\'' ) {

                sb.append( fwdQuote( c ) );
            }
            else if ( c == '\n' ) {

                line.add( sb.toString().trim() );
                sb = new StringBuilder();
                if ( isValidLine( line ) )
                    result.add( line );
                line = new ArrayList();
            }
            else if ( c == delim ) {

                line.add( sb.toString().trim() );
                sb = new StringBuilder();
            }
            else
                sb.append( c );

            next();
        } while ( hasNext() );

        sb.append( buffer[ pos ] );
        line.add( sb.toString().trim() );

        if ( isValidLine( line ) )
            result.add( line );

        return result;
    }


    /** forward pos until the end of quote */
    StringBuilder fwdQuote( char q ) {

        StringBuilder sb = new StringBuilder();

        while ( hasNext() ) {

            next();
            sb.append( buffer[ pos ] );

            if ( isCurr( q ) ) {
                if ( isNext( q ) ) {            // consecutive quote sign
                    next();
                }
                else {
                    break;
                }
            }
        }

        if ( sb.length() > 0 )
            sb.setLength( sb.length() - 1 );    // remove closing quote sign

        return sb;
    }

    void next() {

        pos++;
    }

    boolean hasNext() {

        return pos < ( buffer.length - 1 );
    }

    boolean isNext( char c ) {

        if ( !hasNext() )   return false;

        return buffer[ pos + 1 ] == c;
    }


    boolean isCurr( char c ) {

        if ( !isValidPos() )
            return false;

        return buffer[ pos ] == c;
    }


    boolean isValidPos() {

        return pos >= 0 && pos < buffer.length - 1;
    }


    boolean isValidLine( List<String> line ) {

        for ( String s : line ) {

            if ( !StringUtil.isEmpty( s, true ) )
                return true;
        }

        return false;
    }

}
