// ファイルの読み込み操作用関数群
#include "./loadfile.h"

/* ## 関数の実装セクション ## */
typedef vector<string> myVS;


int LoadData(string filename,  double* data)
{
  myVS lines;
  if(! Convert(filename, lines) ){ return(0); }

  for(uint i=0; i<lines.size(); i++){
     if(lines[i].size()>0){ data[i] =  atof( lines[i].c_str() );  }
  }
  return(1);
}

int LoadMap(string delimiter, string filename, map<string, double> &data)
{
  myVS lines;
  if(! Convert(filename, lines) ){ return(0); }

  for( myVS::iterator i = lines.begin(); i!=lines.end(); i++)
    {
      myVS tmp;
      split(delimiter, (*i), tmp);
      // 空白行およびキーのみ値のみの行を格納しない
      if(tmp.size()>1){ data[ tmp[0] ] = atof( tmp[1].c_str() ); }
    }
  return(1);
}


int Convert(string filename, myVS &data)
{
  string str;
  ifstream infile;
 
  // ファイルを読み込んでstring型ベクタに格納する
  infile.open(filename.c_str(),ios::in);
  if(!infile){
    cout << "Can't open file:["<<filename<<"]"<< endl;
    return(0);
  }
  int errcnt=0;
  while(1) {
    getline(infile,str);
    if (infile.fail()){
      // 行の取得に失敗したら中止
      cout<<" FAIL:read lines error."<<endl;
      return(0);
    }
    if (str[0] == '!') break;     // 終了行がきたら読むのを止めて格納処理に移る    
    if (str[0] == '#') continue;  // コメント行は読み飛ばす
    //if (str[0] == '\n'){ cout<<"kaigyo only\n"; continue;}
    data.push_back(str);

    errcnt++;
    if(errcnt>10000){
      // データ行が大き過ぎる（想定外）ならエラー終了
      cout<<" FAIL:terminater [!] doesnt exist."<<endl;
      return(0); 
    }
  }
  infile.close();

  // 正常終了したら1を返す
  return(1);
}


// perl でいうところの split() っぽい関数のC++版実装
int split(string delimiter, string source, myVS &storage) 
{
  storage.clear();
  string::iterator delim_It, srcIt;

  string word = "";
  int wordnum=0;

  for( srcIt=source.begin(); srcIt!=source.end(); srcIt++){
    int flg_delim=0;

    // 複数のデリミタについて走査,デリミタがあったらフラグを立てる
    for( delim_It=delimiter.begin(); delim_It!=delimiter.end(); delim_It++ )
      if( (*srcIt)==(*delim_It) ) flg_delim=1;

    // デリミタフラグが立っているなら単語として格納
    if( flg_delim!=1 ) word.push_back(*srcIt);
    else if( !(word.empty()) ){
      storage.push_back(word);
      wordnum++;
      word="";
    }
  }

  // 入力行末がデリミタまたはwordが空なら関数を抜ける
  for( delim_It=delimiter.begin(); delim_It!=delimiter.end(); delim_It++ )
    if( (*(source.end()-1)==(*delim_It))||(word.empty()) ) return(wordnum);

  storage.push_back(word);
  wordnum++;
  return(wordnum);
}



// おまけ
// split()をつかってテーブル形式のデータファイルから二次元ベクタに格納．
int LoadData(string delimiter, string filename, 
	     vector< vector<double> > &data)
{
  myVS lines;
  if(! Convert(filename, lines)){ return(0); }  

  // string型ベクタ"lines"をdouble型二次元なベクタに変換する
  for(  myVS::iterator linesIt = lines.begin();
        linesIt!=lines.end();
        linesIt++)
    {
      myVS tmp;
      split(delimiter, (*linesIt), tmp);

      vector<double> t2d;

      for(myVS::iterator i=tmp.begin(); i!=tmp.end(); i++)
	{ t2d.push_back( atof( i->c_str() ) ); }

      data.push_back( t2d );
    }
  return(1);
}


int LoadData(string delimiter, string filename,
             int &size_i, int &size_j, double** &storage)
{
  vector< vector<double> > tmpvect;

  // テーブル形式のデータファイルから二次元に格納
  LoadData(delimiter, filename, tmpvect);

  // arr[i][j]について最大のjを取得する(動的に配列を確保する時のオーバーフロー防止)
  // 計算領域を矩形として扱うためにすべてのjを揃える
  size_i = tmpvect.size();
  for(int i=0; i<size_i; i++)
    if( size_j < (int)tmpvect[i].size() ) size_j = tmpvect[i].size();

  // double型の二次元配列を動的に確保し,初期化する
  storage = new (double*)[size_i];
  for(int i=0; i<size_i; i++) { storage[i] = new (double)[size_j]; }
  for(int i=0; i<size_i; i++) {
    for(int j=0; j<size_j; j++){
      storage[i][j]=0;
    }
  }

  // 二元ベクタ→二元配列
  {
    vector< vector<double> >::iterator i_It;
    vector<double>::iterator j_It;

    int i=0;
    for( i_It=tmpvect.begin(); i_It!=tmpvect.end(); i_It++ ){
      int j=0;
      for( j_It=(*i_It).begin(); j_It!=(*i_It).end(); j_It++){
        storage[i][j]=(*j_It);
        j++;
      }
      i++;
    }
  }

  return(1);
}

