// CSV_line.cpp  (C) 2008 adolfo@di-mare.com

#ifdef English_dox
/** \file  CSV_line.cpp
    \brief  Implementation for \c CSV_line.h.
    \author Adolfo Di Mare <adolfo@di-mare.com>
    \date   2008
*/
#endif

#ifdef Spanish_dox
/** \file  CSV_line.cpp
    \brief  Implementacin para \c CSV_line.h.
    \author Adolfo Di Mare <adolfo@di-mare.com>
    \date   2008
*/
#endif

#include "CSV_line.h"

#include <sstream> // basic_istringstream<>

void CSV_line::setData( const std::string & str ) {
    std::vector<std::string>& VEC = (*this);
    // see http://www.horstmann.com/cpp/pitfalls.html
{{  // test::getNextCSV()
    VEC.clear();          // std::vector<std::string> VEC;
    std::string csv;
    bool eol_CIN = false; // stop when the end of line is reached
    std::istringstream ist( str , std::ios::binary );
    while ( ! eol_CIN && ! ist.fail() ) { // ! ist.eof() pitfall!
        eol_CIN = getNextCSV( csv, ist );
        VEC.push_back( csv );
    }
    return;
    //  Using std::ios::binary ensures that no CR+LF chars are discarded
}}
}

void CSV_line::setData( const char *str , size_t n ) {
    #if 1
        n = ( n>0 ? n : strlen( str ) );
        std::string st; st.assign( str, n );
        setData( st );
        return;
    #else
        realSetData( m_DATA, str, n );
        return size();
    #endif

    #if 0
        // Implementacin errnea y vieja (no maneja DQUOTE)
        clear(); // borra el vector de subhileras
        std::string valor; // valor de cada dato extrado de "str"
        std::string::size_type len = str.size();
        std::string::size_type last, i = 0; // primer valor de "str"
        int n = 0, pos = 0; // posicin primera
        while ( i<len ) {
            last = str.find( ',' , i );
            if (last == std::string::npos) {
                valor = str.substr(i, len-i);
                i = len;
            }
            else {
                valor = str.substr(i, last-i);
                i = last+1;
            }

            trim( valor );
            if ( valor != "" ) {
                m_DATA[ pos ] = valor;
                ++n; // cuenta cuntos obtuvo
            }
            pos++;
        }
        return pos;
    #endif
}

//      ["cero",  "el "" 1" , , " 3ro"  \r\n]
//      [....0.,........ 1..,2,.........3...]

//    Actions for the finite automaton used to parse CSV input
//    ========================================================
//    [   n=0  i=0   ] ==> n=0; i=0; DATA[0] = "";
//    [ ++n h="" ++i ] ==> ++n; DATA[n] = ""; ++i;
//    [     ++i      ] ==> ++i;
//    [   h+= ++i    ] ==> DATA[n] += str[i]; ++i;
//    [  h+='""' ++i ] ==> DATA[n] = '"' + DATA[n] + '"' + str[i]; ++i;
//    [     END      ] ==> return n;
//
//            |  ',' '\n'  |    "       |     l      |
//    delta() |  comma+LF  |  d-quote   |   letter   |
//  ----------+------------+------------+------------+
//   ==>  0   |     0      |     1      |     3      |
//       init |++n h="" ++i|    ++i     |  h+= ++i   |
//  ----------+------------+------------+------------+
//        1   |     1      |     2      |     1      |
//   quoted(1)|  h+= ++i   |    ++i     |  h+= ++i   |
//  ----------+------------+------------+------------+
//        2   |     0      |     1      |     3      |
//  inquote(2)|++n h="" ++i|  h+= ++i   | h+='""' ++i|
//  ----------+------------+------------+------------+
//        3   |     0      |     3      |     3      |
//     regular|++n h="" ++i|  h+= ++i   |  h+= ++i   |
//  ----------+------------+------------+------------+

#if 0 // DEPRECATED

/// Funcin que carga el vector \c DATA[] con los valores CSV que contiene la hilera \c str.
void realSetData( std::vector<std::string> & DATA, const char *str , size_t n ) {
    size_t N = ( n>0 ? n : strlen( str ) );
    size_t i=0; int state=0; n = 0;
    DATA.clear();  DATA.push_back("");
    // N: cantidad de letras a procesar
    // n: cantidad de columnas extradas de str[]
    // i: caracter en proceso.
    while( i<N ) {
        switch (state) {
        case 0: { // init
                if ( str[i] == COMMA ) {
                    ++n; DATA.push_back(""); ++i;
                //  state = 0;
                }
                else if ( str[i] == LF ) {
                    if ( i+1 == N ) {
                        chop( DATA[n], CR );     // handle CR+LF at the end of line
                        i = N;
                    }
                    else {
                        ++n; DATA.push_back(""); ++i;
                    }
                //  state = 0;
                }
                else if ( str[i] == DQUOTE ) {   //            |  ',' '\n'  |    "       |     l      |
                    ++i;                         //    delta() |  comma+LF  |  d-quote   |   letter   |
                    state = 1;                   //  ----------+------------+------------+------------+
                }                                //   ==>  0   |     0      |     1      |     3      |
                else { // letter                 //       init |++n h="" ++i|    ++i     |  h+= ++i   |
                    DATA[n] += str[i]; ++i;      //  ----------+------------+------------+------------+
                    state = 3;
                }
            }
            break;

        case 1: { // quote(1)
        //      if ( str[i] == COMMA ) {
        //          DATA[n] += str[i]; ++i;
        //      //  state = 1;
        //      }
        /*      else */ if ( str[i] == DQUOTE ) {//            |  ',' '\n'  |    "       |     l      |
                    ++i;                         //    delta() |  comma+LF  |  d-quote   |   letter   |
                    state = 2;                   //  ----------+------------+------------+------------+
                }                                //        1   |     1      |     2      |     1      |
        //      else if ( str[i] == LF ) {       //   quoted(1)|  h+= ++i   |    ++i     |  h+= ++i   |
        //          DATA[n] += str[i]; ++i;      //  ----------+------------+------------+------------+
        //      //  state = 1;
        //      }
                else { // letter
                    DATA[n] += str[i]; ++i;
                //  state = 1;
                }
            }
            break;

        case 2: { // inquote(2)
                if ( str[i] == COMMA ) {
                    ++n; DATA.push_back(""); ++i;
                    state = 0;
                }
                else if ( str[i] == DQUOTE ) {   //            |  ',' '\n'  |    "       |     l      |
                    DATA[n] += str[i]; ++i;      //    delta() |  comma+LF  |  d-quote   |   letter   |
                    state = 1;                   //  ----------+------------+------------+------------+
                }                                //        2   |     0      |     1      |     3      |
        //      else if ( str[i] == LF ) {       //  inquote(2)|++n h="" ++i|  h+= ++i   | h+='""' ++i|
        //      //  chop( DATA[n], CR );         //  ----------+------------+------------+------------+
        //          rebuildDquote( DATA[n] );
        //          DATA[n] = DQUOTE + DATA[n] + DQUOTE + str[i]; ++i;
        //          state = 3;
        //      }
                else if ( str[i] == CR ) {       // handle CR+LF at the end of line
                    bool LF_is_last = false;
                    if ( i == N-2 ) {
                        if ( str[i+1] == LF ) {
                            LF_is_last = true;   // take out CR+LF
                        }
                    }
                    if ( ! LF_is_last ) {
                        rebuildDquote( DATA[n] );
                        DATA[n] = DQUOTE + DATA[n] + str[i]; ++i;
                        state = 3;
                    }
                }
                else { // letter
                    rebuildDquote( DATA[n] );
                    DATA[n] = DQUOTE + DATA[n] + DQUOTE + str[i]; ++i;  // assertTrue( """" == "" );
                    state = 3;
                }
            }
            break;

        case 3: { // regular
                if ( str[i] == COMMA ) {
                    ++n; DATA.push_back(""); ++i;
                    state = 0;
                }
        //      else if ( str[i] == DQUOTE ) {   //            |  ',' '\n'  |    "       |     l      |
        //          DATA[n] += str[i]; ++i;      //    delta() |  comma+LF  |  d-quote   |   letter   |
        //      //  state = 3;                   //  ----------+------------+------------+------------+
        //      }                                //        3   |     0      |     3      |     3      |
                else if ( str[i] == LF ) {       //    regular |++n h="" ++i|  h+= ++i   |  h+= ++i   |
                    if ( i+1 == N ) {            //  ----------+------------+------------+------------+
                        chop( DATA[n], CR );
                        i = N; // ++i; state = 0;     // handle CR+LF at the end of line
                    }
                    else {
                        ++n; DATA.push_back(""); ++i;
                        state = 0;
                    }
                }
                else { // letter
                    DATA[n] += str[i]; ++i;
                //  state = 3;
                }
            }
            break;
        }
    }
    return;
}

#endif

// EOF: CSV_line.cpp
