#ifndef MESH_H
#define MESH_H

#include "vectors.h"
#include "array.h"
#include "bag.h"
#include "boundingbox.h"
#include "argparser.h"

class Vertex;
class Edge;
class Face;
class VertexParent;

// ======================================================================
// ======================================================================

class Mesh {

public:

  // ========================
  // CONSTRUCTOR & DESTRUCTOR
  Mesh();
  virtual ~Mesh();
  void Load(const char *input_file);
    
  // ========
  // VERTICES
  int numVertices() const { return vertices->Count(); }
  Vertex* addVertex(const Vec3f &pos);
  // this creates a relationship between 3 vertices (2 parents, 1 child)
  void setParentsChild(Vertex *p1, Vertex *p2, Vertex *child);
  // this accessor will find a child vertex (if it exists) when given
  // two parent vertices
  Vertex* getChildVertex(Vertex *p1, Vertex *p2) const;
  // look up vertex by index from original .obj file
  Vertex* getVertex(int i) const {
    assert (i >= 0 && i < numVertices());
    Vertex *v = (*vertices)[i];
    assert (v != NULL);
    return v; }

  // =====
  // EDGES
  int numEdges() const { return edges->Count(); }
  // this efficiently looks for an edge with the given vertices, using a hash table
  Edge* getEdge(Vertex *a, Vertex *b) const;

  // =========
  // FACES
  int numFaces() const { return faces->Count(); }
  void addFace(Vertex *a, Vertex *b, Vertex *c, Vertex *d, const Vec3f &color, const Vec3f &emit);
  void removeFace(Face *f);

  // ===============
  // OTHER ACCESSORS
  BoundingBox* getBoundingBox() const { return bbox; }
  Bag<Face*>* getFaces() const { return faces; }

  // ===============
  // OTHER FUNCTIONS
  void PaintWireframe();
  void Subdivision();

private:

  // helper functions
  Vertex* AddEdgeVertex(Vertex *a, Vertex *b);
  Vertex* AddMidVertex(Vertex *a, Vertex *b, Vertex *c, Vertex *d);

  // ==============
  // REPRESENTATION
  Array<Vertex*> *vertices;
  Bag<Edge*> *edges;
  Bag<Face*> *faces;
  BoundingBox *bbox;
  Bag<VertexParent*> *vertex_parents;

};

// ======================================================================
// ======================================================================

#endif




