//
// This file is part of MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2015 Richard S. Smith and collaborators.
//
// If you use MorphoGraphX in your work, please cite:
//   http://dx.doi.org/10.7554/eLife.05864
//
// MorphoGraphX is free software, and is licensed under under the terms of the 
// GNU General (GPL) Public License version 2.0, http://www.gnu.org/licenses.
//
#ifndef CLIP_HPP
#define CLIP_HPP

#include <Config.hpp>
#include <Misc.hpp>
#include <MGXViewer/qglviewer.h>

namespace mgx 
{
  class mgx_EXPORT Clip : public QObject 
  {
    Q_OBJECT
  
  public:
    Clip(int id, QObject* parent = 0);
  
    int clipNo() const {
      return _clipNo;
    }
  
    void enable()
    {
      if(!_enable) {
        _enable = true;
        hasChanged();
      }
    }
    void disable()
    {
      if(_enable) {
        _enable = false;
        hasChanged();
      }
    }
    bool enabled() const {
      return _enable;
    }
  
    void showGrid()
    {
      if(!_showGrid) {
        _showGrid = true;
        hasChanged();
      }
    }
    void hideGrid()
    {
      if(_showGrid) {
        _showGrid = false;
        hasChanged();
      }
    }
    /**
     * Returns true if the grid is to be shown, false otherwise
     */
    bool grid() const {
      return _showGrid;
    }
  
    void setWidth(float f)
    {
      if(_width != f) {
        _width = f;
        hasChanged();
      }
    }
    float width() const {
      return _width;
    }
  
    void setGridSize(float s)
    {
      if(_gridSize != s) {
        _gridSize = s;
        hasChanged();
      }
    }
    float gridSize() const {
      return _gridSize;
    }
  
    void setNormal(const Point3f& n)
    {
      if(n != _normal) {
        _normal = n;
        hasChanged();
        computeBasis();
      }
    }
    const Point3f& normal() const {
      return _normal;
    }
  
    /**
     * Return the description of the clipping plane as a 4d point, as used by OpenGL
     * This one returns the positive plane (i.e. the one with positive normal)
     */
    Point4f normalFormPos() const;
    /**
     * Return the description of the clipping plane as a 4d point, as used by OpenGL
     * This one returns the negative plane (i.e. the one with negative normal)
     */
    Point4f normalFormNeg() const;
  
    void setGridSquares(uint n)
    {
      if(n != _gridSquares) {
        _gridSquares = n;
        hasChanged();
      }
    }
    uint gridSquares() const {
      return _gridSquares;
    }
  
    /// Get frame
    qglviewer::ManipulatedFrame& frame() {
      return _frame;
    }
    const qglviewer::ManipulatedFrame& frame() const {
      return _frame;
    }
  
    /**
     * Call this if you change the manipulated frame
     */
    void hasChanged() {
      _changed = true;
    }
  
    bool changed() const {
      return _changed;
    }
    void resetChanges() {
      _changed = false;
    }
  
    bool isClipped(const Point3f& p);
  
    const Point3f& xb() const {
      return _xb;
    }
    const Point3f& yb() const {
      return _yb;
    }
    const Point3f& zb() const {
      return _zb;
    }
  
  protected:
    void computeBasis();
  
    bool _enable;        ///< If true, these planes are used to clipping
    bool _showGrid;      ///< Show the grid corresponding to the clipping plane
    float _width;        ///< Width of the region
    float _gridSize;     ///< Size of the grid (i.e. in the clipping plane)
    Point3f _normal;     ///< Normal to the grid
    Point3f _xb;         ///< X-axis of the planes
    Point3f _yb;         ///< Y-axis of the planes
    Point3f _zb;         ///< Thickness of the region
    uint _gridSquares;   ///< Number of squares drawn for the grid
    int _clipNo;         ///< Id of the clipping region (0, 1 or 2)
    bool _changed;       ///< If true, it changed and need update in OpenGL
    qglviewer::ManipulatedFrame _frame;
  };
}
#endif
