/**
 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
 * storing and accessing finite element mesh data.
 * 
 * Copyright 2004 Sandia Corporation.  Under the terms of Contract
 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
 * retains certain rights in this software.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 */

//-----------------------------------------------------------------------------
// Filename : ReadOBJ.hpp
//
// Purpose  : Wavefront obj file reader
//
// Creators : Chelsea D'Angelo, Paul Wilson, Andrew Davis
//
// Date     : 02/16
//
// Owner    : Chelsea D'Angelo
//-----------------------------------------------------------------------------


/**
 * This class will read in an obj file and populate a MOAB instance with the
 * vertex and connectivity information in the file.  A specification for obj files
 * can be found here: https://en.wikipedia.org/wiki/Wavefront_.obj_file
 * This reader only supports a subset of the full file structure, namely, 
 * object names, group names, vertices, and faces.
 *
 * Overview of the supported structure:
 *
 * Heading
 * Object line: o object_name
 * Group line: g group_name1
 * Vertex lines: v x y z
 * Face lines (tri): f v1 v2 v3
 * Face lines (quad): f v1 v2 v3 v4
 *
 * Lines that begin w/ anything other than 'o ', 'g ', 'v ', and 'f ' are not
 * supported. If a valid, but unsupported line is found, it will be ignored.
 * If an invalid line is found, an error will be produced.
 * Face lines that contain 'vertex\texture\normal' are handled by ignoring the
 * texture and normal
 * 
 * 
 * A new meshset will be created for each object or group in the file.
 * Each object and group must have a name, or the line will be ignored.  
 * Groups are thought to be collections of elements with no dimension or category and
 * will therefore only be assigned name and id tags.
 * Objects are thought to be closed surfaces.  A surface meshset will be
 * created for each object.  A volume meshset that directly corresponds
 * to the surface meshset will also be created.  These will have name, id,
 * categorty, and dimension tags.  A parent-child relationship exists
 * between the volume and surface meshsets.
 * Vertices will be created and added to a global vertex meshset.
 * Triangular faces will be created and added as members of the surface meshets.
 */


#ifndef READ_OBJ_HPP
#define READ_OBJ_HPP     
                                     
#ifndef IS_BUILDING_MB                   
  #error "ReadOBJ.hpp isn't supposed to be included into an application"
#endif   

#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>

#include "moab/Interface.hpp"
#include "moab/ReaderIface.hpp"
#include "FileTokenizer.hpp"
#include "moab/RangeMap.hpp"
#include "MBTagConventions.hpp"

/* struct vertex is a structure that stores coordinates
   of vertices. This is a convenience structure making 
   i/o easier.
*/
struct vertex {
  int vertex_id;
  double coord[3];
};

/* struct face is a structure that stores connectivity.
   This is a convenience structure makin i/o easier.
*/
struct face {
  int face_id;
  moab::EntityHandle conn[3];
};
namespace moab {

/* Supported obj file keywords
 */
enum keyword_type {obj_undefined = 0,
                   object_start,
                   group_start,
                   face_start,
                   vertex_start,
                   valid_unsupported};

class ReadUtilIface;
class GeomTopoTool;

class ReadOBJ : public ReaderIface
{
   
public:

  //! factory method 
  static ReaderIface* factory( Interface* );

  ErrorCode load_file( const char* file_name,
                       const EntityHandle* file_set,
                       const FileOptions& opts,
                       const SubsetList* subset_list = 0,
                       const Tag* file_id_tag = 0 );

  ErrorCode read_tag_values( const char* file_name,
                             const char* tag_name,
                             const FileOptions& opts,
                             std::vector<int>& tag_values_out,
                             const SubsetList* subset_list = 0 );
 

 
  //! Constructor
  ReadOBJ(Interface* impl = NULL);

   //! Destructor
  virtual ~ReadOBJ();

private:
  ReadUtilIface* readMeshIface;

  //! interface instance
  Interface* MBI;

  GeomTopoTool* myGeomTool;

  Tag geom_tag,id_tag,name_tag,category_tag,faceting_tol_tag, geometry_resabs_tag, obj_name_tag;

  /*  The keyword type function matches the first character extracted from each line to a type of line
   */ 
  keyword_type get_keyword(std::vector<std::string> tokens);
  
  /*  The match function searches a list of map keys for a match with the token
   */
  template <typename T>
  std::string match(const std::string &token, std::map<std::string, T> &tokenList);
 

  /* The tokenize function takes a string as input and splits it into
   * a vector of strings based on the delimiter
   */
  static const char* delimiters;

  void tokenize( const std::string& str, std::vector<std::string>& tokens,
                 const char* delimiters );
  
  /*
   * The create_object funtion will create a new meshset for
   * each object that contains all vertices and faces 
   */
  ErrorCode create_new_object(std::string object_name, 
                              int object_id,
                              EntityHandle &curr_obj_meshset);
  
  ErrorCode create_new_group ( std::string object_name,
                                       int curr_object, 
                                       EntityHandle &object_meshset );

  /* create_new_vertex converts tokenized string input to 
     vertex structure
   */
  ErrorCode create_new_vertex (std::vector<std::string> v_tokens,
                                      EntityHandle &vertex_eh); 

  /* create_new_face converts tokenized string input to 
   * face structure
   */
  ErrorCode create_new_face (std::vector<std::string> f_tokens,
                                       const std::vector<EntityHandle>&vertex_list,
                                       EntityHandle &face_eh); 
 

  /*
   * The split_quad function creates 1 new vertex and 4 new tri faces
   * from a quad face.  
   */

  ErrorCode split_quad(std::vector<std::string> f_tokens,
                                       std::vector<EntityHandle>&vertex_list,
                                       Range &face_eh);

 ErrorCode create_tri_faces( std::vector<EntityHandle> quad_vert_eh, 
//				       EntityHandle center_vertex_eh,
				       Range &face_eh );

};

} // namespace moab



#endif
