#include <iostream>
#include <osg/PositionAttitudeTransform>
#include <osg/Switch>
#include <osgDB/ReadFile>
#include <osgGA/GUIEventHandler>
#include <osgProducer/Viewer>

osg::ref_ptr<osg::Switch> TheSwitch;
unsigned CurrentModel = 0;

class ViewerEventHandler: public osgGA::GUIEventHandler
{
   public:
      virtual bool handle (const osgGA::GUIEventAdapter& ea,
                           osgGA::GUIActionAdapter&)
      {
         if (ea.getEventType() == osgGA::GUIEventAdapter::KEYUP)
         {
            switch (ea.getKey())
            {
               // Left key: select previous model
               case osgGA::GUIEventAdapter::KEY_Left:
                  if (CurrentModel == 0)
                     CurrentModel = TheSwitch->getNumChildren() - 1;
                  else
                     --CurrentModel;

                  TheSwitch->setSingleChildOn (CurrentModel);

                  return true;

               // Right key: select next model
               case osgGA::GUIEventAdapter::KEY_Right:
                  if (CurrentModel == TheSwitch->getNumChildren() - 1)
                     CurrentModel = 0;
                  else
                     ++CurrentModel;

                  TheSwitch->setSingleChildOn (CurrentModel);

                  return true;

               // Up key: increase the current model scale
               case osgGA::GUIEventAdapter::KEY_Up:
               {
                  osg::ref_ptr<osg::PositionAttitudeTransform> pat =
                     dynamic_cast<osg::PositionAttitudeTransform*>(
                        TheSwitch->getChild (CurrentModel));
                  pat->setScale (pat->getScale() * 1.1);

                  return true;
               }

               // Down key: decrease the current model scale
               case osgGA::GUIEventAdapter::KEY_Down:
               {
                  osg::ref_ptr<osg::PositionAttitudeTransform> pat =
                     dynamic_cast<osg::PositionAttitudeTransform*>(
                        TheSwitch->getChild (CurrentModel));
                  pat->setScale (pat->getScale() / 1.1);
                  return true;
               }

               // Don't handle other keys
               default:
                  return false;
            }
         }
         else
            return false;
      }
};


int main (int argc, char* argv[])
{
   // Check command-line parameters
   if (argc < 2)
   {
      std::cerr << "Usage: " << argv[0]
                << " <model file> [ <model file> ... ]\n";
      exit (1);
   }

   // Create a Producer-based viewer
   osgProducer::Viewer viewer;
   viewer.setUpViewer (osgProducer::Viewer::STANDARD_SETTINGS);

   // Create the event handler and attach it to the viewer
   osg::ref_ptr<osgGA::GUIEventHandler> eh (new ViewerEventHandler());
	viewer.getEventHandlerList().push_front (eh);

   // Construct the scene graph
   TheSwitch = osg::ref_ptr<osg::Switch> (new osg::Switch());

   for (int i = 1; i < argc; ++i)
   {
      osg::ref_ptr<osg::Node> loadedNode = osgDB::readNodeFile(argv[i]);
      if (!loadedNode)
         std::cerr << "Problem opening '" << argv[i] << "'\n";
      else
      {
         osg::ref_ptr<osg::StateSet> ss (loadedNode->getOrCreateStateSet());
         ss->setMode (GL_NORMALIZE, osg::StateAttribute::ON);
         osg::ref_ptr<osg::PositionAttitudeTransform> pat(
            new osg::PositionAttitudeTransform());
         pat->addChild (loadedNode.get());
         TheSwitch->addChild (pat.get());
      }
   }

   // Ensure that we have at least on model before going on
   if (TheSwitch->getNumChildren() == 0)
   {
      std::cerr << "No 3D model was loaded. Aborting...\n";
      exit (1);
   }

   viewer.setSceneData (TheSwitch.get());

   TheSwitch->setSingleChildOn (0);

   // Enter rendering loop
   viewer.realize();

   while (!viewer.done())
   {
      viewer.sync();
      viewer.update();
      viewer.frame();
   }

   // Wait for all cull and draw threads to complete before exit
   viewer.sync();
}
