/* OpenSceneGraph example, osgcompositeviewer.
*
*  Permission is hereby granted, free of charge, to any person obtaining a copy
*  of this software and associated documentation files (the "Software"), to deal
*  in the Software without restriction, including without limitation the rights
*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the Software is
*  furnished to do so, subject to the following conditions:
*
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*  THE SOFTWARE.
*/

#include <iostream>

#include <osg/Notify>
#include <osg/io_utils>

#include <osg/ArgumentParser>
#include <osgDB/WriteFile>
#include <osgGA/TrackballManipulator>
#include <osgGA/StateSetManipulator>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgWidget/Browser>


#include <QtWebKit/QWebSettings>
#include <QtWebKit/QtWebKit>
#include <QtGui/QGraphicsScene>
#include <QtGui/QGraphicsView>
#include <QtGui/QApplication>
#include <QtGui/QPainter>
#include <QtGui/QtEvents>

//#include "QGraphicsViewAdapter.h"
#include "QWebViewImage.h"


// Thread that runs the viewer's frame loop as we can't run Qt in the background...
class ViewerFrameThread : public OpenThreads::Thread
{
    public:

        ViewerFrameThread(osgViewer::ViewerBase* viewerBase, bool doQApplicationExit):
            _viewerBase(viewerBase),
            _doQApplicationExit(doQApplicationExit) {}

        ~ViewerFrameThread()
        {
            cancel();
            while(isRunning())
            {
                OpenThreads::Thread::YieldCurrentThread();
            }
        }

        int cancel()
        {
            _viewerBase->setDone(true);
            return 0;
        }

        void run()
        {
            int result = _viewerBase->run();

            if (_doQApplicationExit) QApplication::exit(result);
        }

        osg::ref_ptr<osgViewer::ViewerBase> _viewerBase;
        bool _doQApplicationExit;
};

// Class to try runnig QtWebBrowser in a background thread.
// weird message when exiting application - how to exit qt properly??
class QtBrowserThread : public OpenThreads::Thread
{
public:

   QtBrowserThread() :
      _done(false),
      _newUrl(false)
   {}

   ~QtBrowserThread()
   {
      //cancel();
      _done = true;
      while(isRunning())
      {
         OpenThreads::Thread::YieldCurrentThread();
      }
   }

   void run()
   {
      PrepareApp();

      //_qtApp->exec();

      while (!_done)
      {
         _qtApp->processEvents(QEventLoop::AllEvents, 100);
         OpenThreads::Thread::microSleep(1000);

         if (_newUrl)
         {
            _webImage->navigateTo(_currentUrl);
            _newUrl = false;
         }         
      }
      
      cancel();
   }

   int cancel()
   {
      _qtApp->quit();
      return 0;
   }

   void PrepareApp()
   {
      // Qt requires that we construct the global QApplication before creating any widgets.
      char** argv = 0;
      int argc = 0;
      _qtApp = new QApplication(argc, argv);      

      _webImage = new QWebViewImage;

      if (_webImage.valid())
         _webImage->navigateTo("http://www.openscenegraph.org/");
   }

   // this method must be called from inside this thread to work
   void NavigateTo(const std::string& url)
   {
      _currentUrl.assign(url);
      _newUrl = true;      
   }

   bool _done;
   QApplication* _qtApp;
   osg::ref_ptr<QWebViewImage> _webImage;
   std::string _currentUrl;
   bool _newUrl;
};

// test handler to load a new page at runtime
class BrowserHandler : public osgGA::GUIEventHandler 
{
public:
   BrowserHandler(QtBrowserThread* pBrowserThread) :
      _browserThread(pBrowserThread)
   {
   }

   virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
   {
      if ('l' == ea.getKey())
      {
         std::cout << "Load Google webpage" << std::endl;
         _browserThread->NavigateTo("http://www.google.com");
         return true;
      }

      return false;      
   }

   QtBrowserThread* _browserThread;
};


int main(int argc, char **argv)
{
    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    bool useFrameLoopThread = true;
    if (arguments.read("--no-frame-thread")) useFrameLoopThread = false;

    bool useQtWebThread = false;
    if (arguments.read("--qt-web-thread")) useQtWebThread = true;


    osgWidget::GeometryHints hints(osg::Vec3(0.0f,0.0f,0.0f),
                                   osg::Vec3(1.0f,0.0f,0.0f),
                                   osg::Vec3(0.0f,0.0f,1.0f),
                                   osg::Vec4(1.0f,1.0f,1.0f,1.0f),
                                   osgWidget::GeometryHints::RESIZE_HEIGHT_TO_MAINTAINCE_ASPECT_RATIO);


    osg::ref_ptr<osgWidget::Browser> browser = new osgWidget::Browser;
    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer(arguments);


    viewer->setCameraManipulator(new osgGA::TrackballManipulator());
    viewer->addEventHandler(new osgViewer::StatsHandler);
    viewer->addEventHandler(new osgViewer::WindowSizeHandler);

    viewer->setSceneData(browser.get());


    if (useQtWebThread)
    {
       std::cout << " start in threaded QT mode " << std::endl;

       QtBrowserThread browserThread;
       browserThread.startThread();
      
       // wait for the image to be created in the Qt Browser thread
       unsigned int count = 0;
       while (!browserThread._webImage.valid() && count < 3)
       {
          OpenThreads::Thread::microSleep(1000000);
          ++count;

          std::cout << "waited " << count << " second(s)" << std::endl;
       }       
       

       if (browserThread._webImage.valid())       
          std::cout << " assigned image" << browserThread._webImage.get()->s() << " " << browserThread._webImage.get()->t() << std::endl;       
       else
          std::cout << " NO valid image to assign" << std::endl;

       browser->assign(browserThread._webImage.get(), hints);

       // test handler to load a new page
       viewer->addEventHandler(new BrowserHandler(&browserThread));

       // run viewer loop on main thread
       viewer->run();
    }
    else 
    {
       // Qt requires that we construct the global QApplication before creating any widgets.
       QApplication app(argc, argv);

       osg::ref_ptr<QWebViewImage> image = new QWebViewImage;

       if (arguments.argc()>1) image->navigateTo((arguments[1]));
       else image->navigateTo("http://www.google.com/");


       browser->assign(image.get(), hints);
       // image->focusBrowser(true);

       if (useFrameLoopThread)
       {
          std::cout << " start in threaded mode " << std::endl;
          // create a thread to run the viewer's frame loop
          ViewerFrameThread viewerThread(viewer.get(), true);
          viewerThread.startThread();

          // now start the standard Qt event loop, then exists when the viewerThead sends the QApplication::exit() signal.
          return QApplication::exec();

       }
       else
       {
          std::cout << " start in Interleaved mode " << std::endl;
          // run the frame loop, interleaving Qt and the main OSG frame loop
          while(!viewer->done())
          {
             // process Qt events - this handles both events and paints the browser image
             QCoreApplication::processEvents(QEventLoop::AllEvents, 100);

             viewer->frame();
          }

          return 0;
       }
    }  
   
}
