// Cutmesh - Copyright (C) 2010-2018 T. Mouton, E. Bechet 
//
// See the LICENSE file for license information and contributions.
// bugs and problems to <thibaud.mouton@gmail.com>.

#ifndef _LSQUERY_CUTMESH_H_
#define _LSQUERY_CUTMESH_H_

#include "topo.h"

class query_result
{
  private :
    std::set<TopoVolume *> vols;
    std::set<TopoFace *> faces;
    std::set<TopoEdge *> edges;
    std::set<TopoVertex *> verts;

    std::set<TopoVolume *>::iterator itv;
    std::set<TopoFace *>::iterator  itf;
    std::set<TopoEdge *>::iterator  ite;
    std::set<TopoVertex *>::iterator itx;

  public :

    void add_volume ( TopoVolume *tv )
    {
      vols.insert ( tv );
    }
    void add_face ( TopoFace *tf )
    {
      faces.insert ( tf );
    }
    void add_edge ( TopoEdge *te )
    {
      edges.insert ( te );
    }
    void add_vertex ( TopoVertex *tx )
    {
      verts.insert ( tx );
    }

    void init_read_volumes()
    {
      itv = vols.begin();
    }
    void init_read_faces()
    {
      itf = faces.begin();
    }
    void init_read_edges()
    {
      ite = edges.begin();
    }
    void init_read_vertices()
    {
      itx = verts.begin();
    }

    TopoVolume *current_volume()
    {
      if ( itv != vols.end() )
        return *itv;
      else
        return NULL;
    }
    TopoFace *current_face()
    {
      if ( itf != faces.end() )
        return *itf;
      else
        return NULL;
    }
    TopoEdge *current_edge()
    {
      if ( ite != edges.end() )
        return *ite;
      else
        return NULL;
    }
    TopoVertex *current_vertex()
    {
      if ( itx != verts.end() )
        return *itx;
      else
        return NULL;
    }

    void next_volume()
    {
      itv++;
    }
    void next_face()
    {
      itf++;
    }
    void next_edge()
    {
      ite++;
    }
    void next_vertex()
    {
      itx++;
    }

    bool end_volume()
    {
      return ( itv == vols.end() );
    }
    bool end_face()
    {
      return ( itf == faces.end() );
    }
    bool end_edge()
    {
      return ( ite == edges.end() );
    }
    bool end_vertex()
    {
      return ( itx == verts.end() );
    }

    int volume_size()
    {
      return vols.size();
    }
    int face_size()
    {
      return faces.size();
    }
    int edge_size()
    {
      return edges.size();
    }
    int vertex_size()
    {
      return verts.size();
    }

    void union_result ( query_result *qr );
    void inter_result ( query_result *qr );
    void sub_result ( query_result *qr );
};


class Topology_query
{
    struct expr_element
    {
      query_result *qr;
      int op;

      expr_element()
      {
        qr = NULL;
        op = -1;
      }
    };

  private :
    Topo *topo_object;
    std::map<int, TopoFace*> levelset_map;
    std::map<int, TopoFace*>::iterator itlm;
    enum enum_position { NEGATIVE, ZERO, POSITIVE };

    // for the RPN calculator
    std::vector<expr_element> rpn_expr;
    std::stack<query_result *> rpn_stack;
    query_result *result;

  public :
    Topology_query ( Topo *topo );
    void split_line ( const char *line, std::vector<char*> &exp );
    query_result *query ( int surf, int position );
    void set_expression ( std::vector<char *> expr );
    void compute_expression();
    query_result *get_result()
    {
      return result;
    }

    std::vector<int> get_result_volumes_physicals();
    std::vector<int> get_result_faces_physicals();
    std::vector<int> get_result_edges_physicals();
    std::vector<int> get_result_vertices_physicals();

    void dump ( query_result * qr );
    void minishell();
};


#endif
