// 
// readLdmk.cxx : Simplified Reader for .ldmk files 
//  - each non commented line in a ldmk file represent a point and 
//    has the following dictionary-like structure:
//        nb_of_pair key1 value1 key2 value2 ..
//    one of the key being 'position' with corresponding 
//    value format 'x,y,z'
//
//
// Copyright (C) 2010  Clement Creusot
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.


#include <fstream>
#include <sstream>
#include <string.h>
#include <cstdlib> 
#include <list> 
#include <vector>


//-----------------------------------------------------------------------------

/*
 * Print basic error
 * with file and line where it occured
 */
#define PRINT_ERROR(reason, ...) do {					\
    char _str[100];							\
    sprintf(_str, reason, ##__VA_ARGS__);				\
    const char * at = strstr(__FILE__,"face/");				\
    if (at != NULL) {fprintf(stderr,"ERROR %s %d: %s\n",at,__LINE__,_str);} \
    else      {fprintf(stderr,"ERROR %s %d: %s\n",__FILE__,__LINE__,_str);} \
    exit(EXIT_FAILURE);                                                 \
  } while(0)   


// Split input string into a vector using delimiter "delim".
template <class T>
inline void StringSplit(const std::string& sentence, const std::string& delim, std::vector<T>& results)
{
  unsigned int cutAt;
  T val;
  results.clear();
  std::string str = sentence;
  while( (cutAt = str.find_first_of(delim)) != str.npos ){
    if(cutAt >= 0){
      std::istringstream ss(str.substr(0,cutAt));
      ss >> val;
      results.push_back(val);
    }
    str = str.substr(cutAt+1);
  }
  if(str.length() > 0){
    std::istringstream ss(str);
    ss >> val;
    results.push_back(val);
  }
}

//-----------------------------------------------------------------------------


// Simplified landmark structure
struct ALandmark 
{
  double position[3];
  int label;
  int onMeshId;  
  // etc etc
};


// A back inserter for this example
typedef std::back_insert_iterator<std::list<ALandmark*> > OutputLandmarkIterator;  


//-----------------------------------------------------------------------------


OutputLandmarkIterator ReadLdmk(OutputLandmarkIterator landmarkIt, const std::string& filename){
  std::ifstream in;
  std::string buff, name;
  int count;

  if(filename.find(".ldmk") == std::string::npos){
    PRINT_ERROR("Input landmark file doesnt end by '.ldmk': %s",filename.c_str());
  }
  
  in.open(filename.c_str());
  if(!in) { 
    PRINT_ERROR("Unable to open the file %s",filename.c_str());
  }

  in >> buff;
  while( !in.eof() ){
    if (buff[0] == '#'){
      // if we read a comment, read all the line
      getline(in, buff);
    }
    else if (buff[0] == 'i'){
      // simplified version, dont read global values
      getline(in, buff);
    }
    else {
      ALandmark * cur = new ALandmark(); 
      count = atoi(buff.c_str());
      bool hasPosition=false;
      for(int i=0; i < count; i++){
	in >> name;
	if (name.compare("position") ==0){
	  in >> buff;
	  std::vector<double> t; 
	  StringSplit<double>(buff, ",", t);
	  cur->position[0] = t[0];
	  cur->position[1] = t[1];
	  cur->position[2] = t[2];	  
	  hasPosition = true;
	}
	else if (name.compare("label") ==0){
	  in >> cur->label;
	}
	else if (name.compare("onMeshId") ==0){
	  in >> cur->onMeshId;
	}
	// etc etc
	else{
	  in >> buff;
	}
      }
      if (hasPosition){
	*landmarkIt++ = cur;
      }
    }
    in >>buff;
  }
  in.close();
  
  return landmarkIt; 
}



int main(int argc, char** argv){


  if(argc!=2){
    fprintf(stderr,"Bad Arguments; %s file.ldmk\n",argv[0]);
    exit(EXIT_FAILURE);
  }
  std::string filename(argv[1]);

  std::list<ALandmark*> ldmks;
  OutputLandmarkIterator ii = std::back_inserter(ldmks);

  ii = ReadLdmk(ii, filename); 
  
  std::list<ALandmark*>::const_iterator
    itb = ldmks.begin(),
    ite = ldmks.end();
  for(; itb!=ite; ++itb){
    fprintf(stdout,"%f %f %f\n",
	    (*itb)->position[0],
	    (*itb)->position[1],
	    (*itb)->position[2]);    
  }
  return EXIT_SUCCESS;
}
