
#include <XmlRpc.h>
#include <stdlib.h>
#include <vector>
#include <math.h>
#include "Tipus_Globals.h"
#include "Servidor_Xmlrpc_Mart.h"
#include "Comunicacio_Robot.h"
#include <iostream>
#include <ptime.h>
#include <pinet.h>

// Per a depuracio de la imatge {
#include <fstream>
#include <time.h>
// }

USING_PTYPES

using namespace XmlRpc;

XmlRpcServer servidor;
extern Comunicacio_Robot *interficie_robot;

void Thread_Servidor_Mart::execute()
{
   XmlRpc::setVerbosity(5);

   // Crea el server socket al port especificat
   servidor.bindAndListen(port_mart);

   // Permet introspeccio: funcio que retorna al client els metodes
   //                      que el servidor ofereix.
   servidor.enableIntrospection(true);

   // Esperar infefinidament peticions del client (Mars Rover).
   servidor.work(-1.0);
}

mutex mutex_informe;
std::vector<TInforme> informe_mart;

void modificar_informe(TInforme dada, int esborrar)
{
   mutex_informe.lock();
   if(esborrar) {
      informe_mart.clear();
   }
   else {
      informe_mart.push_back(dada);
   }   
   mutex_informe.unlock();
}   

void Thread_Servidor_Informes::execute()
{
   int tasca_activa = interficie_robot -> get_Funcionament();
   while(tasca_activa) {
      TInforme dada_informe;
      TPosicio posicio;
      interficie_robot -> get_posicio_actual(&posicio);
      dada_informe.posicio = posicio;
      interficie_robot -> get_posicio_actual(&posicio);
      dada_informe.material = interficie_robot -> analitzar_material();
      dada_informe.ferro = interficie_robot -> analitzar_ferro();
      dada_informe.llum = interficie_robot -> get_nivell_llum_actual();
      dada_informe.temperatura = interficie_robot -> get_temperatura_actual();
      dada_informe.bateria = interficie_robot -> get_carrega_bateria();
      dada_informe.xray = interficie_robot -> analitzar_xray();
      modificar_informe(dada_informe,0);
      relax(MILISEGONS_CLIENT_INFORME / 10);
      tasca_activa = interficie_robot -> get_Funcionament();
   }   
}

class Servei_Activacio : public XmlRpcServerMethod
{
   public:
      Servei_Activacio(XmlRpcServer* servidor) : XmlRpcServerMethod("activacio", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         std::string accio = std::string(params[0]);
         if(accio.compare("activar") == 0) {
            interficie_robot -> activar_robot();
            result = "activat";
         }
         else if (accio.compare("desactivar") != 0) {
            interficie_robot -> desactivar_robot();
            result = "desactivat";
         }      
      }

      std::string help() 
      { 
         return std::string("Activa o desactiva el funcionament del robot."); 
      }
} servei_Activacio(&servidor);

class Servei_Inici_Moviment : public XmlRpcServerMethod
{
   public:
      Servei_Inici_Moviment(XmlRpcServer* servidor) : XmlRpcServerMethod("inici_moviment_robot", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         interficie_robot -> iniciar_moviment();
         result = "OK";
      }

      std::string help() 
      { 
         return std::string("Activa o desactiva el funcionament del robot."); 
      }
} servei_Inici_Moviment(&servidor);

class Servei_Fi_Moviment : public XmlRpcServerMethod
{
   public:
      Servei_Fi_Moviment(XmlRpcServer* servidor) : XmlRpcServerMethod("fi_moviment_robot", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         interficie_robot -> finalitzar_moviment();
         result = "OK";
      }

      std::string help() 
      { 
         return std::string("Activa o desactiva el funcionament del robot."); 
      }
} servei_Fi_Moviment(&servidor);

class Servei_Gir_Robot : public XmlRpcServerMethod
{
   public:
      Servei_Gir_Robot(XmlRpcServer* servidor) : XmlRpcServerMethod("girar_robot", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         int graus = int(params[0]);
         interficie_robot -> girar_robot(graus);
         result = "OK";
      }

      std::string help() 
      { 
         return std::string("Activa o desactiva el funcionament del robot."); 
      }
} servei_Gir_Robot(&servidor);

class Servei_Gir_Cameres : public XmlRpcServerMethod
{
   public:
      Servei_Gir_Cameres(XmlRpcServer *servidor) : XmlRpcServerMethod("girar_cameres_robot", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         int graus = int(params[0]);
         interficie_robot -> girar_cameres(graus);
         result = "OK";
      }

      std::string help() 
      { 
         return std::string("Activa o desactiva el funcionament del robot."); 
      }
} servei_Gir_Cameres(&servidor);

class Servei_Fotografia : public XmlRpcServerMethod
{
   private:
      int primera_transmissio;
      ipstream *client;
      unsigned char *imatge;
      int amplada;
      int altura;
   public:
      Servei_Fotografia(XmlRpcServer* servidor) : XmlRpcServerMethod("obtenir_fotografia", servidor) 
      {
         primera_transmissio = 1;
      }

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         try {
         int num_camera = int(params[0]);
         if(primera_transmissio) {
            amplada = interficie_robot -> get_amplada_imatge();
            altura = interficie_robot -> get_altura_imatge();
            imatge = (unsigned char*)malloc(3*amplada*altura*sizeof(char));
         }   

         interficie_robot -> capturar_fotografia(1,num_camera,imatge);
         //interficie_robot -> realitzar_fotografia(num_camera);
         
/*         result[0] = 3 * amplada * altura;
         result[1] = amplada;
         result[2] = altura;
         int comptador = 3;*/

         FILE *fptr = fopen("imatge_mart.tga","w");

         fputc(0,fptr);
         fputc(0,fptr);
         fputc(2,fptr);
         for(int i=3;i<12;i++) fputc(0,fptr);
         fputc(amplada&0xff,fptr);
         fputc(amplada/256,fptr);
         fputc(altura&0xff,fptr);
         fputc(altura/256,fptr);
         fputc(24,fptr);
         fputc(32,fptr);

         for (int j = altura - 1; j >= 0; j--) {
            for (int i = 0; i < amplada; i++) {
               //result[comptador] = imatge[3*j*amplada+3*i+2]; 
               fputc(imatge[3*j*amplada+3*i+2],fptr);
               //comptador++;
               //result[comptador] = imatge[3*j*amplada+3*i+1];
               fputc(imatge[3*j*amplada+3*i+1],fptr);
               //comptador++;
               //result[comptador] = imatge[3*j*amplada+3*i+0]; 
               fputc(imatge[3*j*amplada+3*i+0],fptr);
               //comptador++;
           }
        }
        fclose(fptr);

        if(primera_transmissio) {
         int ip_terra[4];
         interficie_robot -> get_ip_terra(ip_terra);
         const int port = 10000;
         int a = ip_terra[0], b = ip_terra[1], c = ip_terra[2], d = ip_terra[3];
            client = new ipstream(ipaddress(a,b,c,d), port);
            primera_transmissio = 0;
         }   
         client -> open();
         char ampladaStr[4], alturaStr[4];
         interficie_robot -> conversio_a_cadena(amplada,ampladaStr);
         interficie_robot -> conversio_a_cadena(altura,alturaStr);
         //itoa(amplada,ampladaStr,10);
         //itoa(altura,alturaStr,10);
         
         time_t temps_actual;
         time(&temps_actual);
         std::ofstream f("debug.txt",std::ios::app|std::ios::out);
         f << "\nEnviament de imatge a l'hora: " << ctime(&temps_actual) << ":\n";

         client -> write(ampladaStr,sizeof(ampladaStr));
         client -> flush();
         f << "Escriu amplada imatge\n";
         //client -> read(ampladaStr,sizeof(ampladaStr));
         //*f << "Reb amplada imatge\n";
         client -> write(alturaStr,sizeof(alturaStr));
         client -> flush();
         f << "Escriu altura imatge\n";
         //client -> read(alturaStr,sizeof(alturaStr));
         //*f << "Reb altura imatge\n";
         std::cout << "ABANS ENVIAMENT IMATGE...\n";
         client -> write(imatge,amplada*altura*3); // Error en execucio de segona obtencio de foto !?!?
         std::cout << "DESPRES ENVIAMENT IMATGE...\n";
         f << "Escriu dades imatge\n";
         client -> flush();
         f << "Flush del socket\n";
         f.close();
         client -> close();
         }
         catch(estream* e)
         {
            //std::cout << "Error: %s\n" << pconst(e->get_message());
            perr.putf("Error: %s\n", pconst(e->get_message()));
            delete e;
         }         
         //client.close();

        //free(imatge);
        
        result = "OK";
      }

      std::string help() 
      { 
         return std::string("Activa o desactiva el funcionament del robot."); 
      }
} servei_Fotografia(&servidor);

class Servei_Posicio_Robot : public XmlRpcServerMethod
{
   public:
      Servei_Posicio_Robot(XmlRpcServer* servidor) : XmlRpcServerMethod("get_posicio_robot", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         TPosicio posicio;
         interficie_robot -> get_posicio_actual(&posicio);
         result[0] = posicio.x;
         result[1] = posicio.y;
         result[2] = posicio.z;
         result[3] = posicio.angle_orientacio;
         result[4] = posicio.angle_horitzo;
      }

      std::string help() 
      { 
         return std::string("Retorna la posicio 3D actual del robot."); 
      }
} servei_Posicio_Robot(&servidor);

class Servei_Material : public XmlRpcServerMethod
{
   public:
      Servei_Material(XmlRpcServer* servidor) : XmlRpcServerMethod("get_material", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         result = interficie_robot -> analitzar_material();
      }

      std::string help() 
      { 
         return std::string("Retorna el tipus de material de la posicio actual de Mart."); 
      }
} servei_Material(&servidor);

class Servei_Ferro : public XmlRpcServerMethod
{
   public:
      Servei_Ferro(XmlRpcServer* servidor) : XmlRpcServerMethod("get_nivell_ferro", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         result = (double)interficie_robot -> analitzar_ferro();
      }

      std::string help() 
      { 
         return std::string("Retorna el nivell actual de ferro a Mart."); 
      }
} servei_Ferro(&servidor);

class Servei_Llum : public XmlRpcServerMethod
{
   public:
      Servei_Llum(XmlRpcServer* servidor) : XmlRpcServerMethod("get_nivell_llum", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         result = (double)interficie_robot -> get_nivell_llum_actual();
      }

      std::string help() 
      { 
         return std::string("Retorna el nivell actual de llum a Mart."); 
      }
} servei_Llum(&servidor);

class Servei_Temperatura : public XmlRpcServerMethod
{
   public:
      Servei_Temperatura(XmlRpcServer* servidor) : XmlRpcServerMethod("get_temperatura", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         result = interficie_robot -> get_temperatura_actual();
      }

      std::string help() 
      { 
         return std::string("Retorna la temperatura actual de Mart."); 
      }
} servei_Temperatura(&servidor);

class Servei_Bateria : public XmlRpcServerMethod
{
   public:
      Servei_Bateria(XmlRpcServer* servidor) : XmlRpcServerMethod("get_bateria", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         result = interficie_robot -> get_carrega_bateria();
      }

      std::string help() 
      { 
         return std::string("Retorna la carrega bateria actual del Mars Rover."); 
      }
} servei_Bateria(&servidor);

class Servei_Xray : public XmlRpcServerMethod
{
   public:
      Servei_Xray(XmlRpcServer* servidor) : XmlRpcServerMethod("get_xray", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         result = (double)interficie_robot -> analitzar_xray();
      }

      std::string help() 
      { 
         return std::string("Retorna el valor de raigs X analitzat en la posicio actual de Mart."); 
      }
} servei_XRay(&servidor);

class Servei_Dades_Completes : public XmlRpcServerMethod
{
   public:
      Servei_Dades_Completes(XmlRpcServer* servidor) : XmlRpcServerMethod("get_dades_completes", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         TPosicio posicio;
         
         interficie_robot -> get_posicio_actual(&posicio);
         result[0] = (double)posicio.x;
         result[1] = (double)posicio.y;
         result[2] = (double)posicio.z;
         result[3] = (int)posicio.angle_orientacio;
         result[4] = (int)posicio.angle_horitzo;
         result[5] = (int)interficie_robot -> analitzar_material();         
         result[6] = (double)interficie_robot -> analitzar_ferro();
         result[7] = (double)interficie_robot -> get_nivell_llum_actual();
         result[8] = (int)interficie_robot -> get_temperatura_actual();
         result[9] = (int)interficie_robot -> get_carrega_bateria();
         result[10] = (double)interficie_robot -> analitzar_xray();
      }   

      std::string help() 
      { 
         return std::string("Retorna les dades completes actuals del robot i mart."); 
      }
  
   
} servei_Dades_Completes(&servidor);   

class Servei_Canviar_Camara_Activa : public XmlRpcServerMethod
{
   public:
      Servei_Canviar_Camara_Activa(XmlRpcServer *servidor) : XmlRpcServerMethod("canviar_camara_activa", servidor) {}

      void execute(XmlRpcValue& params, XmlRpcValue& result)
      {
         int num_camara = int(params[0]);
         interficie_robot -> canviar_camara_activa(num_camara - 1);
         result = "OK";
      }

      std::string help() 
      { 
         return std::string("Activa o desactiva el funcionament del robot."); 
      }
} servei_Canviar_Camara_Activa(&servidor);


