#include "UtsusemiContainerTextConverter.hh"
//////////////////////////////////////////////////////////////////////
UtsusemiContainerTextConverter::
UtsusemiContainerTextConverter(){
    Initialize();
}
//////////////////////////////////////////////////////////////////////
UtsusemiContainerTextConverter::
UtsusemiContainerTextConverter( ElementContainer* _EC ){
    Initialize();
    SetTarget( _EC );
}
//////////////////////////////////////////////////////////////////////
UtsusemiContainerTextConverter::
UtsusemiContainerTextConverter( ElementContainerArray* _ECA ){
    Initialize();
    SetTarget( _ECA );
}
//////////////////////////////////////////////////////////////////////
UtsusemiContainerTextConverter::
UtsusemiContainerTextConverter( ElementContainerMatrix* _ECM ){
    Initialize();
    SetTarget( _ECM );
}
//////////////////////////////////////////////////////////////////////
UtsusemiContainerTextConverter::
~UtsusemiContainerTextConverter(){
    delete _st;
}
//////////////////////////////////////////////////////////////////////
void UtsusemiContainerTextConverter::
Initialize(){
    _targettype=0;
    _st = new StringTools();
    _ec=NULL;
    _eca=NULL;
    _ecm=NULL;
}
//////////////////////////////////////////////////////////////////////
void UtsusemiContainerTextConverter::
SetTarget( ElementContainer* _EC ){
    _targettype=1;
    _ec = _EC;
}
//////////////////////////////////////////////////////////////////////
void UtsusemiContainerTextConverter::
SetTarget( ElementContainerArray* _ECA ){
    _targettype=2;
    _eca = _ECA;
}
//////////////////////////////////////////////////////////////////////
void UtsusemiContainerTextConverter::
SetTarget( ElementContainerMatrix* _ECM ){
    _targettype=3;
    _ecm = _ECM;
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiContainerTextConverter::
Save( std::string filename ){
    FILE* fp;
    if ((fp=fopen(filename.c_str(),"w"))==NULL){
        return false;
    }

    if (_targettype==3){
        _SaveECM( fp, _ecm );
    }else if (_targettype==2){
        _SaveECA( fp, _eca );
    }else if (_targettype==1){
        _SaveEC( fp, _ec );
    }else{
        return false;
    }
    fclose(fp);
    return true;
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiContainerTextConverter::
Save( std::string filename, ElementContainerMatrix* _ECM ){
    FILE* fp;
    if ((fp=fopen(filename.c_str(),"w"))==NULL){
        return false;
    }

    _SaveECM( fp, _ECM );
    fclose(fp);

    return true;
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiContainerTextConverter::
Save( std::string filename, ElementContainerArray* _ECA ){
    FILE* fp;
    if ((fp=fopen(filename.c_str(),"w"))==NULL){
        return false;
    }

    _SaveECA( fp, _ECA );
    fclose(fp);

    return true;
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiContainerTextConverter::
Save( std::string filename, ElementContainer* _EC ){
    FILE* fp;
    if ((fp=fopen(filename.c_str(),"w"))==NULL){
        return false;
    }

    _SaveEC( fp, _EC );
    fclose(fp);

    return true;
}
//////////////////////////////////////////////////////////////////////
void UtsusemiContainerTextConverter::
_SaveEC(FILE* _fo, ElementContainer* _EC){
    std::string first_line = "#";
    std::string head_line = "#HEADERDUMP:"+_EC->PutHeaderPointer()->DumpToString();
    std::string keys_line = "#KEYS:";
    std::string nums_line = "#NUMS:";
    std::string setkey_line = "#SETKEYS:"+_EC->PutXYEKeys();

    std::vector<std::string> keys_org = _EC->PutKeys();
    std::string xKey = _EC->PutXKey();
    std::string yKey = _EC->PutYKey();
    std::string eKey = _EC->PutEKey();

    std::vector<std::string> keys;
    keys.push_back( xKey );
    keys.push_back( yKey );
    keys.push_back( eKey );
    for (UInt4 i=0; i<keys_org.size(); i++)
        if ((keys_org[i]!=xKey)&&(keys_org[i]!=yKey)&&(keys_org[i]!=eKey)) keys.push_back( keys_org[i] );

    UInt4 v_size = (UInt4)(keys.size());
    std::vector< std::vector<Double>* > vects( v_size, NULL );
    std::vector<UInt4> nums( v_size,0);
    for (UInt4 i=0; i<v_size; i++){
        vects[i] = (*_EC)( keys[i] );
        nums[i] = (UInt4)(vects[i]->size());

        keys_line += (keys[i]+",");
        char a_num_c[20];
        std::snprintf( a_num_c, sizeof(a_num_c), "%d", nums[i] );
        std::string a_num(a_num_c);
        nums_line += (a_num+",");
    }

    keys_line.erase( keys_line.end()-1 );
    nums_line.erase( nums_line.end()-1 );;


    UInt4 max_num = nums[0];
    for (UInt4 i=0; i<v_size; i++){
        if (nums[i]>max_num)
            max_num=nums[i];
    }

   std::fprintf( _fo, "%s\n", first_line.c_str() );
   std::fprintf( _fo, "%s\n", head_line.c_str() );
   std::fprintf( _fo, "%s\n", keys_line.c_str() );
   std::fprintf( _fo, "%s\n", nums_line.c_str() );
   std::fprintf( _fo, "%s\n", setkey_line.c_str() );

    for (UInt4 i=0; i<max_num; i++){
        std::string a_line = "";
        for (UInt4 j=0; j<v_size; j++){
            if (i<nums[j]){
                char a_val_c[20];
                std::snprintf( a_val_c, sizeof(a_val_c), "%g,", vects[j]->at(i) );
                std::string a_val( a_val_c );
                a_line += a_val;
            }else{
                a_line += "-,";
            }
        }
        a_line.erase( a_line.end()-1 );
       std::fprintf( _fo, "%s\n", a_line.c_str() );
    }

}
//////////////////////////////////////////////////////////////////////
void UtsusemiContainerTextConverter::
_SaveECA(FILE* _fo, ElementContainerArray* _ECA){
    std::string first_line = "##";
    std::string head_line = "##HEADERDUMP:"+_ECA->PutHeaderPointer()->DumpToString();

    char size_c[20];
    std::snprintf( size_c, sizeof(size_c), "%d", _ECA->PutSize() );
    std::string size_s(size_c);
    std::string size_line = "##SIZE:"+size_s;

   std::fprintf( _fo, "%s\n", first_line.c_str() );
   std::fprintf( _fo, "%s\n", head_line.c_str() );
   std::fprintf( _fo, "%s\n", size_line.c_str() );

    for (UInt4 i=0; i<(_ECA->PutSize()); i++)
        _SaveEC( _fo, (*_ECA)(i) );

}
//////////////////////////////////////////////////////////////////////
void UtsusemiContainerTextConverter::
_SaveECM(FILE* _fo, ElementContainerMatrix* _ECM){
    std::string first_line = "###";
    std::string head_line = "###HEADERDUMP:"+_ECM->PutHeaderPointer()->DumpToString();

    char size_c[20];
    std::snprintf( size_c, sizeof(size_c), "%d", _ECM->PutSize() );
    std::string size_s(size_c);
    std::string size_line = "###SIZE:"+size_s;

   std::fprintf( _fo, "%s\n", first_line.c_str() );
   std::fprintf( _fo, "%s\n", head_line.c_str() );
   std::fprintf( _fo, "%s\n", size_line.c_str() );

    for (UInt4 i=0; i<(_ECM->PutSize()); i++)
        _SaveECA( _fo, (*_ECM)(i) );

}

//////////////////////////////////////////////////////////////////////
bool UtsusemiContainerTextConverter::
Load( std::string filename, ElementContainer* _EC ){
    FILE* fp;
    if ((fp=fopen(filename.c_str(),"r"))==NULL){
        return false;
    }

    char s[20000];
    while( fgets( s, 20000, fp )!=NULL ){
        std::string aline0( s );
        if (aline0.find("###")==0) continue;
        if (aline0.find("##")==0) continue;
        if (aline0.find("#")==0){
            std::vector<std::string> bufs;
            bufs.push_back( aline0 );
            bool isHeader=true;
            while( fgets( s, 20000, fp )!=NULL ){
                std::string aline(s);
                if (isHeader){
                    bufs.push_back(aline);
                    if (aline.find("#")==std::string::npos) isHeader=false;

                }else{
                    if (aline.find("#")==0) break;

                    bufs.push_back( aline );
                }
            }
            _ConvEC( bufs, _EC );
            break;
        }
    }
    fclose(fp);
    return true;
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiContainerTextConverter::
Load( std::string filename, ElementContainerArray* _ECA ){
    FILE* fp;
    if ((fp=fopen(filename.c_str(),"r"))==NULL){
        return false;
    }

    char s[20000];
    std::string lastline = "";
    while( fgets( s, 20000, fp )!=NULL ){
        std::string aline0( s );
        if (aline0.find("###")==0) continue;
        if (aline0.find("##")==0){
            std::vector<std::string> bufs1;
            if (lastline!="")
                bufs1.push_back(lastline);

            bufs1.push_back(aline0);
            // Read ECA Header lines
            while( fgets( s, 20000, fp )!=NULL ){
                std::string aline1(s);
                if (aline1.find("##")==0) bufs1.push_back( aline1 );
                else{
                    lastline = aline1;
                    _ConvECA( bufs1, _ECA );
                    break;
                }
            }

            // Read EC
            UInt4 ind = 0;
            while( fgets( s, 20000, fp )!=NULL ){
                std::string aline1(s);
                if (aline1.find("##")==0){
                    lastline=aline1;
                    break;
                }

                std::vector<std::string> bufs;
                if (lastline!="") {
                    bufs.push_back( lastline );
                    lastline="";
                }
                bufs.push_back( aline1 );
                bool isHeader=true;
                ElementContainer* _EC = new ElementContainer();
                while( fgets( s, 20000, fp )!=NULL ){
                    std::string aline(s);
                    if (isHeader){
                        bufs.push_back( aline );
                        if (aline.find("#")==std::string::npos) isHeader=false;

                    }else{
                        if (aline.find("#")==0){
                            lastline=aline;
                            break;
                        }
                        bufs.push_back( aline );
                    }
                }

                _ConvEC( bufs, _EC );

                if (ind<(_ECA->PutSize()))
                    _ECA->Set( ind, _EC );
                else{
                    _ECA->Add( (*_EC) );
                    delete _EC;
                }
                ind++;
            }
        }
    }
    fclose(fp);
    return true;
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiContainerTextConverter::
Load( std::string filename, ElementContainerMatrix* _ECM ){
    FILE* fp;
    if ((fp=fopen(filename.c_str(),"r"))==NULL){
        return false;
    }

    char s[20000];
    std::string lastline = "";
    while( fgets( s, 20000, fp )!=NULL ){
        std::string aline0( s );
        if (aline0.find("###")==0){
            lastline=aline0;
            break;
        }
    }

    bool isHeader0 = true;
    std::vector<std::string> bufs0;
    if (lastline!=""){
        bufs0.push_back(lastline);
        lastline="";
    }

    // Read ECM Header lines
    while( fgets( s, 20000, fp )!=NULL ){
        std::string aline0(s);
        if (aline0.find("###")==0) bufs0.push_back( aline0 );
        else{
            lastline = aline0;
            _ConvECM( bufs0, _ECM );
            break;
        }
    }

    UInt4 ind1 = 0;
    while( fgets( s, 20000, fp )!=NULL){
        // Read ECA Header lines
        ElementContainerArray* _ECA = new ElementContainerArray();
        std::vector<std::string> bufs1;
        if (lastline!="")
            bufs1.push_back( lastline );

        while( fgets( s, 20000, fp )!=NULL ){
            std::string aline1(s);
            if (aline1.find("##")==0) bufs1.push_back( aline1 );
            else{
                lastline = aline1;
                _ConvECA( bufs1, _ECA );
                break;
            }
        }
        //std::cout << "---- step ind1="<<ind1<<std::endl;
        // Read EC
        UInt4 ind = 0;
        while( fgets( s, 20000, fp )!=NULL ){
            std::string aline1(s);
            if (aline1.find("##")==0){
                lastline=aline1;
                break;
            }

            std::vector<std::string> bufs;
            if (lastline!="") {
                bufs.push_back( lastline );
                lastline="";
            }
            bufs.push_back( aline1 );
            bool isHeader=true;
            ElementContainer* _EC = new ElementContainer();
            while( fgets( s, 20000, fp )!=NULL ){
                std::string aline(s);
                if (isHeader){
                    bufs.push_back( aline );
                    if (aline.find("#")==std::string::npos) isHeader=false;

                }else{
                    if (aline.find("#")==0){
                        lastline=aline;
                        break;
                    }
                    bufs.push_back( aline );
                }
            }

            _ConvEC( bufs, _EC );

            if (ind<(_ECA->PutSize()))
                _ECA->Set( ind, _EC );
            else{
                _ECA->Add( (*_EC) );
                delete _EC;
            }
            ind++;
        }

        if (ind1<(_ECM->PutSize()))
            _ECM->Set(ind1, _ECA );
        else{
            _ECM->Add( (*_ECA) );
            delete _ECA;
        }
        ind1++;
    }

    fclose(fp);
    return true;
}
//////////////////////////////////////////////////////////////////////
void UtsusemiContainerTextConverter::
_ConvEC( std::vector<std::string>& lines, ElementContainer* _EC ){
    std::vector<std::string> keys;
    std::vector<UInt4> nums;
    std::vector<std::string> setkeys;

    for (UInt4 i=0; i<lines.size(); i++){
        if (lines[i].find("#HEADERDUMP:")==0){
            std::string head_st = lines[i].substr(12);
            head_st.erase( head_st.end()-1 );
            _EC->PutHeaderPointer()->InputString( head_st );
        }else if (lines[i].find("#HEADER:")==0){
            _ConvHead( lines[i], _EC->PutHeaderPointer() );
        }else if (lines[i].find("#KEYS:")==0){
            std::string tmp = lines[i].substr(6);
            keys = _st->SplitString(tmp,",");
        }else if (lines[i].find("#NUMS:")==0){
            std::string tmp = lines[i].substr(6);
            std::vector<std::string> tmp2 = _st->SplitString(tmp,",");
            for (UInt4 j=0; j<tmp2.size(); j++)
                nums.push_back( _st->StringToUInt4( tmp2[j] ) );
        }else if (lines[i].find("#SETKEYS:")==0){
            std::string tmp = lines[i].substr(9);
            setkeys = _st->SplitString(tmp,",");
        }
    }

    if ((keys.empty())||(nums.empty())){
        return;
    }

    std::vector< std::vector<Double> > vects( keys.size() );

    UInt4 ind=0;
    for (UInt4 i=0; i<lines.size(); i++){
        if (lines[i].find("#")==std::string::npos){
            std::vector<std::string> tmp = _st->SplitString( lines[i], "," );
            if (tmp.size()!=keys.size()) return;
            for (UInt4 j=0; j<tmp.size(); j++)
                if (ind<nums[j]) vects[j].push_back( _st->StringToDouble( tmp[j] ) );
            ind++;
        }
    }

    for (UInt4 i=0; i<keys.size(); i++){
        _EC->Add( keys[i], vects[i] );
    }

    _EC->SetKeys( setkeys[0],setkeys[1],setkeys[2] );
}
//////////////////////////////////////////////////////////////////////
void UtsusemiContainerTextConverter::
_ConvECA( std::vector<std::string>& lines, ElementContainerArray* _ECA ){
    UInt4 size = 0;
    for (UInt4 i=0; i<lines.size(); i++){
        if (lines[i].find("##HEADERDUMP:")==0){
            std::string head_st = lines[i].substr(13);
            head_st.erase( head_st.end()-1 );
            _ECA->PutHeaderPointer()->InputString( head_st );
        }else if (lines[i].find("##HEADER:")==0){
            _ConvHead( lines[i], _ECA->PutHeaderPointer() );
        }else if (lines[i].find("##SIZE:")==0){
            size = _st->StringToUInt4( lines[i].substr(7) );
        }
    }
    if (size!=0) _ECA->Allocate(size);
}
//////////////////////////////////////////////////////////////////////
void UtsusemiContainerTextConverter::
_ConvECM( std::vector<std::string>& lines, ElementContainerMatrix* _ECM ){
    UInt4 size = 0;
    for (UInt4 i=0; i<lines.size(); i++){
        if (lines[i].find("###HEADERDUMP:")==0){
            std::string head_st = lines[i].substr(14);
            head_st.erase( head_st.end()-1 );
            _ECM->PutHeaderPointer()->InputString( head_st );
        }else if (lines[i].find("###HEADER:")==0){
            _ConvHead( lines[i], _ECM->PutHeaderPointer() );
        }else if (lines[i].find("###SIZE:")==0){
            size = _st->StringToUInt4( lines[i].substr(8) );
        }
    }
    if (size!=0) _ECM->Allocate(size);
}
//////////////////////////////////////////////////////////////////////
void UtsusemiContainerTextConverter::
_ConvHead( std::string line, HeaderBase* _H ){
    UInt4 ind;
    if (( ind = (UInt4)(line.find("HEADER:")) )!=(UInt4)std::string::npos){
        line.erase( 0,ind+7 );
        if ((ind = (UInt4)(line.find(":")))!=(UInt4)std::string::npos){
            std::string type=line.substr(0,ind);
            transform( type.begin(), type.end(), type.begin(), ::toupper );
            std::string tmp=line.substr(ind+1);
            if ((ind = (UInt4)(tmp.find(":")))!=(UInt4)std::string::npos){
                std::string name = tmp.substr(0,ind);
                std::string cont = tmp.substr(ind+1);
                std::vector<std::string> cont_list = _st->SplitString( cont, "," );
                if (cont_list.empty()) return;
                bool isVector = false;
                if (cont_list.size()>1) isVector=true;
                if (type=="DOUBLE"){
                    if (isVector){
                        std::vector<Double> dv(cont_list.size());
                        for (UInt4 i=0; i<cont_list.size(); i++){
                            dv[i] = _st->StringToDouble( cont_list[i] );
                        }
                        _H->Add( name, dv );
                    }else{
                        _H->Add( name, _st->StringToDouble( cont_list[0] ) );
                    }
                }else if (type.find("INT")!=std::string::npos){
                    if (isVector){
                        std::vector<Int4> dv(cont_list.size());
                        for (UInt4 i=0; i<cont_list.size(); i++){
                            dv[i] = _st->StringToInt4( cont_list[i] );
                        }
                        _H->Add( name, dv );
                    }else{
                        _H->Add( name, _st->StringToInt4( cont_list[0] ) );
                    }
                }else if (type.find("STRING")!=std::string::npos){
                    if (isVector){
                        _H->Add( name, cont_list );
                    }else{
                        _H->Add( name, cont_list[0] );
                    }
                }
            }
        }
    }
}
