/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
 * Copyright 2016 Pelican Mapping
 * http://osgearth.org
 *
 * osgEarth 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 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */
#ifndef OSGEARTHQT_LOSCREATIONDIALOG_H
#define OSGEARTHQT_LOSCREATIONDIALOG_H 1

#include "ui_LOSCreationDialog.h"

#include <osgEarthQt/Common>
#include <osgEarthQt/DataManager>

#include <osgEarthAnnotation/Draggers>
#include <osgEarthUtil/LinearLineOfSight>
#include <osgEarthUtil/RadialLineOfSight>

#include <osg/AutoTransform>

#include <QDialog>

namespace osgEarth { namespace QtGui 
{
  class LOSIntersectingDragger : public osgEarth::Annotation::SphereDragger
  {
  public:
      LOSIntersectingDragger(osgEarth::MapNode* mapNode):
        osgEarth::Annotation::SphereDragger(mapNode),
        _heightAboveTerrain(0.0)
    {
      setLineColor(osg::Vec4(1.0f, 1.0f, 0.0f, 0.0f));
      setupDefaultGeometry();
    }

    void setupDefaultGeometry()
    {
      // draw a line from ground to location
      _lineGeometry = new osg::Geometry;
      _lineGeometry->setUseVertexBufferObjects(true);

      _lineVerts = new osg::Vec3Array();
      _lineVerts->reserve(2);
      _lineGeometry->setVertexArray( _lineVerts.get() );

      osg::Vec4Array* colors = new osg::Vec4Array(osg::Array::BIND_PER_VERTEX);
      colors->reserve( 2 );
      _lineGeometry->setColorArray( colors );

      _lineVerts->push_back( osg::Vec3d(0.0, 0.0, 0.0) );
      _lineVerts->push_back( osg::Vec3d(0.0, 0.0, _heightAboveTerrain) );
      colors->push_back( _lineColor );
      colors->push_back( _lineColor );

      _lineGeometry->addPrimitiveSet( new osg::DrawArrays( GL_LINES, 0, _lineVerts->size()) );
      osg::Geode* lineGeode = new osg::Geode();
      lineGeode->addDrawable( _lineGeometry );
      lineGeode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
      lineGeode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
      addChild( lineGeode );
    }

    void setHeightAboveTerrain( double hat )
    {
      _heightAboveTerrain = hat;
      (*_lineVerts)[1].set(0.0, 0.0, _heightAboveTerrain);
      if (_lineGeometry.valid())
        _lineGeometry->dirtyDisplayList();
    }

    void setLineColor(const osg::Vec4& color) { _lineColor = color; }

  private:
    double _offset;
    osg::Vec4 _lineColor;
    osg::ref_ptr<osg::Geometry> _lineGeometry;
    osg::ref_ptr<osg::Vec3Array> _lineVerts;
    double _heightAboveTerrain;
  };

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

  class LOSCreationDialog : public QDialog
  {
  Q_OBJECT

  public:
    enum LOSPoint { P2P_START, P2P_END, RADIAL_CENTER };

    LOSCreationDialog(osgEarth::MapNode* mapNode, osg::Group* root, int losCount, DataManager* manager=0L, ViewVector* views=0L);
    LOSCreationDialog(osgEarth::MapNode* mapNode, osg::Group* root, osg::Group* losNode, const std::string& name, DataManager* manager=0L, ViewVector* views=0L);

    osg::Group* losNode() { return _node.get(); }
    std::string losName() { return _ui.nameBox->text().toStdString(); }

    void getLOSPoint(LOSPoint point, osg::Vec3d& out_point, bool relative=false);
    void setLOSPoint(LOSPoint point, const osg::Vec3d& value, bool updateUi=false);

    bool isAltitudeRelative(LOSPoint point);

    void mapClick(const osg::Vec3d& point);

  public slots:
    void accept();
    void reject();
		
  private slots:
    void onP1TypeChange(const QString& text);
    void onP2TypeChange(const QString& text);
    void onRadTypeChange(const QString& text);

    void onP1MapButtonClicked(bool checked);
    void onP2MapButtonClicked(bool checked);
    void onRadMapButtonClicked(bool checked);

    void onP1FindNodeButtonClicked(bool checked);
    void onP2FindNodeButtonClicked(bool checked);
    void onRadFindNodeButtonClicked(bool checked);

    void onLocationValueChanged(double d);
    void onRelativeCheckChanged(int state);

    void onNodeComboChange(const QString& text);

    void onDepthTestChanged(int state);
    void onCurrentTabChanged(int index);

    void onSpokesBoxChanged(int value);
    void onRadiusBoxChanged(double value);

  protected:
    void closeEvent(QCloseEvent* event);

  private:
    void initUi(const std::string& name, osg::Group* los=0L);
    void updateLOSNodes(bool updateAll=false);
    void cleanupNodes();
    void centerMapOnNode(osg::Node* node);
    void updateDragger(Dragger* dragger, const GeoPoint& point);
    void updateDraggerNodes();
    void updatePoint(LOSPoint point);
    int findAnnotationIndex(osg::Node* annotation);

    Ui::LOSCreationDialog _ui;
    osg::ref_ptr<osg::Group> _node;
    osg::ref_ptr<osgEarth::MapNode> _mapNode;
    osg::ref_ptr<osg::Group> _root;
    osg::ref_ptr<DataManager> _manager;
    osg::ref_ptr<osgEarth::Map> _map;
    osg::ref_ptr<osgEarth::Util::LinearLineOfSightNode> _p2p;
    osg::ref_ptr<osgEarth::Util::RadialLineOfSightNode> _radial;
    osg::ref_ptr<LOSIntersectingDragger> _p1Dragger;
    osg::ref_ptr<LOSIntersectingDragger> _p2Dragger;
    osg::ref_ptr<LOSIntersectingDragger> _radDragger;
    bool _updatingUi;
    bool _updateAlt;
    double _p1BaseAlt;
    double _p2BaseAlt;
    double _radBaseAlt;
    AnnotationVector _annotations;
    ViewVector* _views;

    QPushButton* _activeButton;
  };
} }

#endif // OSGEARTHQT_LOSCREATIONDIALOG_H
