#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: seleciona modelo anterior
               case osgGA::GUIEventAdapter::KEY_Left:
                  if (CurrentModel == 0)
                     CurrentModel = TheSwitch->getNumChildren() - 1;
                  else
                     --CurrentModel;

                  TheSwitch->setSingleChildOn (CurrentModel);

                  return true;

               // Right key: seleciona próximo modelo
               case osgGA::GUIEventAdapter::KEY_Right:
                  if (CurrentModel == TheSwitch->getNumChildren() - 1)
                     CurrentModel = 0;
                  else
                     ++CurrentModel;

                  TheSwitch->setSingleChildOn (CurrentModel);

                  return true;

               // Up key: aumenta escala do modelo atual
               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: diminui escala do modelo atual
               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;
               }

               // Não trata outras teclas
               default:
                  return false;
            }
         }
         else
            return false;
      }
};


int main (int argc, char* argv[])
{
   // Checa parâmetros da linha de comando
   if (argc < 2)
   {
      std::cerr << "Uso: " << argv[0]
                << " <arquivo com modelo> [ <arquivo com modelo> ... ]\n";
      exit (1);
   }

   // Cria visualizador baseado em Producer
   osgProducer::Viewer viewer;
   viewer.setUpViewer (osgProducer::Viewer::STANDARD_SETTINGS);

   // Cria o event handler e o atacha ao visualizador
   osg::ref_ptr<osgGA::GUIEventHandler> eh (new ViewerEventHandler());
	viewer.getEventHandlerList().push_front (eh);

   // Constrói o grafo de cena
   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::PositionAttitudeTransform> pat(
            new osg::PositionAttitudeTransform());
         pat->addChild (loadedNode.get());
         TheSwitch->addChild (pat.get());
      }
   }

   // Garante que temos pelo menos 1 modelo antes de prosseguir
   if (TheSwitch->getNumChildren() == 0)
   {
      std::cerr << "Nenhum modelo 3D foi carregado. Abortando...\n";
      exit (1);
   }

   viewer.setSceneData (TheSwitch.get());

   TheSwitch->setSingleChildOn (0);

   // Entra no loop de renderização
   viewer.realize();

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

   // Espera todas as threads de descarte e de desenho completarem antes de sair
   viewer.sync();
}
