/*
 * Enginyeria Informàtica 2004-05 :: Sistemes Informàtics I
 *
 *   Francisco J. Aguilar Celdrán
 *   Francisco J. Carrillo
 *   Sergio Blanco Cuaresma
 */

#include "MyApp.h"

Control_Comandament_Terra *control_terra;
Comunicacio_Interficie_Grafica *comunicacio_interficie;
//Logica_Interficie_Grafica *logica_interficie;
Thread_Servidor_Terra* servidor;
MyFrame *frame;

//// OBJETO PRINCIPAL
IMPLEMENT_APP(MyApp)
/*IMPLEMENT_APP_NO_MAIN(MyApp)
int main(int argc, char* argv[]) {
//    wxEntryStart(argc,argv)
wxAppInitializer appInitializer((wxAppInitializerFunction)
wxCreateApp); 
wxEntry(NULL, NULL, "", 0, true);
MyApp *a = new MyApp();
   return 1;
}*/
/*int main(int argc, char* argv[])
{
    MyApp *app = new MyApp(argc, argv);
}*/


////
//// IMPLEMENTACIÓN DE CLASES
////

bool MyApp::OnInit()
{
    //system("convert imatge.tga imatge.bmp");
    // Creamos ventana principal
    frame = new MyFrame("Control Terra", wxPoint(0,0), wxSize(1000,600) );
    frame->Show(TRUE);
    SetTopWindow(frame);
    
    //logica_interficie = new Logica_Interficie_Grafica();
    comunicacio_interficie = new Comunicacio_Interficie_Grafica();
    control_terra = new Control_Comandament_Terra();
    
    wxTextEntryDialog *ip = new wxTextEntryDialog(NULL, "Adreça IP", "Adreça IP", "127.0.0.1", wxOK);
    ip->ShowModal();
    wxTextEntryDialog *remotePort = new wxTextEntryDialog(NULL, "Port remot", "Port remot", "5000", wxOK);
    remotePort->ShowModal();
    wxTextEntryDialog *localPort = new wxTextEntryDialog(NULL, "Port local", "Port local", "6000", wxOK);
    localPort->ShowModal();
    wxTextEntryDialog *informe = new wxTextEntryDialog(NULL, "Fitxer informe", "Fitxer informe", "informe", wxOK);
    informe->ShowModal();
    
    wxString ipNumber = ip->GetValue();
    wxString remotePortNumber = remotePort->GetValue();
    wxString localPortNumber = localPort->GetValue();
    wxString fitxerInforme = informe->GetValue();
    int err = comunicacio_interficie -> establir_Parametres_Inicials((char*)ipNumber.c_str(),atoi(remotePortNumber),atoi(localPortNumber),(char*)fitxerInforme.c_str());
    //int err = comunicacio_interficie -> establir_Parametres_Inicials("127.0.0.1",10000,10001,"debug.txt");
    if (err) {
       std::cerr << "Error en l'establiment dels parametres!";
       wxMessageBox("Error en l'establiment dels parametres!");
       exit(1);
    }
    control_terra -> iniciar_servidor();
    
    return TRUE;
} 


//// DEFINICIÓN DE LA VENTANA PRINCIPAL
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame((wxFrame *)NULL, -1, title, pos, size) {
    // Contenedores
    wxBoxSizer *mainHSizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer *imagenVSizer = new wxBoxSizer(wxVERTICAL);
    wxGridSizer *buttonsGrid = new wxGridSizer(8, 2, 0, 0);
    
    mainHSizer->Add(buttonsGrid, 0, wxALIGN_CENTER);
    mainHSizer->Add(imagenVSizer, 1, wxALIGN_CENTER);
    
    // Etiquetas de estado
    posicionRobot = new wxStaticText(this, -1, "Posició: 0, 0, 0");
    anglesRobot = new wxStaticText(this, -1, "Angles: 0º d'orientació, 0º d'alçada");
    material = new wxStaticText(this, -1, "Material: 200");
    nivelHierro = new wxStaticText(this, -1, "Nivell Ferro: 50%");
    nivelLuz = new wxStaticText(this, -1, "Nivell Llum: 10%");
    temperatura = new wxStaticText(this, -1, "Temperatura: 22º");
    nivelBateria = new wxStaticText(this, -1, "Bateria: 33%");
    nivelXRay = new wxStaticText(this, -1, "Nivell Raig X: 24");
    
    // Botones de control
    buttonsGrid->Add(NULL, 0, wxALIGN_CENTER);
    buttonsGrid->Add(NULL, 0, wxALIGN_CENTER);
    IniciarButton = new wxButton(this, BUTTON_INICIAR, "Iniciar", wxDefaultPosition);
    FinalizarButton = new wxButton(this, BUTTON_FINALIZAR, "Finalitzar", wxDefaultPosition);
    FinalizarButton->Disable();
    ActivarMovimientoButton = new wxButton(this, BUTTON_ACTIVAR_MOVIMIENTO, "Activar moviments", wxDefaultPosition);
    ActivarMovimientoButton->Disable();
    DesactivarMovimientoButton = new wxButton(this, BUTTON_DESACTIVAR_MOVIMIENTO, "Desactivar moviments", wxDefaultPosition);
    DesactivarMovimientoButton->Disable();
    GirarRobotButton = new wxButton(this, BUTTON_GIRAR_ROBOT, "Girar Robot", wxDefaultPosition);
    GirarRobotButton->Disable();
    FotoButton = new wxButton(this, BUTTON_FOTO, "Foto", wxDefaultPosition);
    FotoButton->Disable();
    GirarCamarasButton = new wxButton(this, BUTTON_GIRAR_CAMARAS, "Girar Camares", wxDefaultPosition);
    GirarCamarasButton->Disable();
    
    wxString list[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9",  };
    /*camara = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize, 8, list);
    camara->SetSelection(0);
    camara->Disable();*/
    
    CamaraActivaButton = new wxButton(this, BUTTON_CAMARA_ACTIVA, "Canviar camara activa", wxDefaultPosition);
    CamaraActivaButton->Disable();
    
    camaraActiva = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize, 9, list);
    camaraActiva->SetSelection(0);
    camaraActiva->Disable();
    
    wxString listGrados[] = { "+45", "-45"};
    grados1 = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize, 2, listGrados);
    grados1->SetSelection(0);
    grados1->Disable();
    
    grados2 = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize, 2, listGrados);
    grados2->SetSelection(0);
    grados2->Disable();
  
    ExitButton = new wxButton(this, BUTTON_EXIT, "Sortir", wxDefaultPosition);
    
    buttonsGrid->Add(IniciarButton, 0, wxALIGN_CENTER| wxEXPAND);
    buttonsGrid->Add(FinalizarButton, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(ActivarMovimientoButton, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(DesactivarMovimientoButton, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(GirarRobotButton, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(grados1, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(CamaraActivaButton, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(camaraActiva, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(FotoButton, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(NULL, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(GirarCamarasButton, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(grados2, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(ExitButton, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(NULL, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(posicionRobot, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(NULL, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(anglesRobot, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(NULL, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(material, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(NULL, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(nivelHierro, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(NULL, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(nivelLuz, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(NULL, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(temperatura, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(NULL, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(nivelBateria, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(NULL, 0, wxALIGN_CENTER | wxEXPAND);
    buttonsGrid->Add(nivelXRay, 0, wxALIGN_CENTER | wxEXPAND);
    
    // Foto de marte
    foto = new wxStaticBitmap(this, -1, wxBitmap("logo.bmp", wxBITMAP_TYPE_BMP));
    imagenVSizer->Add(foto, 1, wxALIGN_CENTER);

    // Establecemos el contenedor principal a la ventana
    SetSizer(mainHSizer);
    
}

////////////
//// EVENTOS
////////////
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    Close(TRUE);
}

void MyFrame::OnIniciarButton(wxCommandEvent& command)
{
    control_terra -> activar_Comunicacio_Terra();
    
     // Interficie
    IniciarButton->Disable();
    FinalizarButton->Enable();
    ActivarMovimientoButton->Enable();
    DesactivarMovimientoButton->Disable();
    GirarRobotButton->Enable();
    FotoButton->Enable();
    CamaraActivaButton->Enable();
    camaraActiva->Enable();
    GirarCamarasButton->Enable();
    //camara->Enable(); // Fallo de segmentacion de memoria aqui
    grados1->Enable();
    grados2->Enable();
    foto->Enable();
    ExitButton->Disable();
}

void MyFrame::OnFinalizarButton(wxCommandEvent& command)
{
    control_terra -> desactivar_Comunicacio_Terra();
    
    IniciarButton->Enable();
    FinalizarButton->Disable();
    ActivarMovimientoButton->Disable();
    DesactivarMovimientoButton->Disable();
    GirarRobotButton->Disable();
    FotoButton->Disable();
    CamaraActivaButton->Disable();
    camaraActiva->Disable();
    GirarCamarasButton->Disable();
    //camara->Disable();
    grados1->Disable();
    grados2->Disable();
    foto->Disable();
    ExitButton->Enable();
}

void MyFrame::OnActivarMovimientoButton(wxCommandEvent& command){
     ActivarMovimientoButton->Disable();
     DesactivarMovimientoButton->Enable();
     
     control_terra -> iniciar_Moviment_Robot();
}

void MyFrame::OnDesactivarMovimientoButton(wxCommandEvent& command) {
     ActivarMovimientoButton->Enable();
     DesactivarMovimientoButton->Disable();
     
     control_terra -> finalitzar_Moviment_Robot();
}

void MyFrame::OnGirarRobotButton(wxCommandEvent& command){
     if (grados1->GetSelection() == 0) {
        control_terra -> girar_Robot(45);
     } else {
        control_terra -> girar_Robot(-45);
     }
     /*wxString grados = grados1->GetLineText(0);
     if ((grados.IsNumber()) && (!grados.IsEmpty())) {
        //wxMessageBox(grados);
        control_terra -> girar_Robot(atoi(grados));
     } else {
        wxMessageBox("Error");
     }*/
}

void MyFrame::OnFotoButton(wxCommandEvent& command) {
       //wxString numCamara = wxString::Format(wxT("%d"), camara->GetSelection() + 1);
       //wxMessageBox(numCamara);
       wxString numCamara = wxString::Format(wxT("%d"), camaraActiva->GetSelection() + 1);
       control_terra -> obtenir_Fotografia(atoi(numCamara));
}

void MyFrame::OnGirarCamarasButton(wxCommandEvent& command){
     if (camaraActiva->GetSelection() + 1 > 4) {
        wxString error = wxString::Format(wxT("Només es poden girar les camares 1,2,3,4 (camara actual %d)"), camaraActiva->GetSelection() + 1);
        wxMessageBox(error);
     } else {
         if (grados2->GetSelection() == 0) {
            control_terra -> girar_Cameres_Robot(45);
         } else {
            control_terra -> girar_Cameres_Robot(-45);
         }
         }
     /*
     wxString grados = grados2->GetLineText(0);
     if ((grados.IsNumber()) && (!grados.IsEmpty())) {
        //wxMessageBox(grados);
        control_terra -> girar_Cameres_Robot(atoi(grados));
     } else {
        wxMessageBox("Error");
     }*/
}

void MyFrame::OnCamaraActivaButton(wxCommandEvent& command) {
       wxString numCamara = wxString::Format(wxT("%d"), camaraActiva->GetSelection() + 1);
       //wxMessageBox(numCamara);
       control_terra->canviar_Camara_Activa(atoi(numCamara));
}

void MyFrame::OnExitButton(wxCommandEvent& command) {
    exit(0);
}


//// FIN EVENTOS

//// Métodos para establecer el estado
void MyFrame::SetPosicionRobot(wxString value){
     posicionRobot->SetLabel(wxString("Posició: ") + value);
}
void MyFrame::SetAnglesRobot(wxString value){
     anglesRobot->SetLabel(wxString("Angles: ") + value);
}
void MyFrame::SetMaterial(wxString value){
     material->SetLabel(wxString("Material: ") + value);
}
void MyFrame::SetNivelHierro(wxString value){
     nivelHierro->SetLabel(wxString("Nivell Ferro: ") + value);
}
void MyFrame::SetNivelLuz(wxString value){
     nivelLuz->SetLabel(wxString("Nivell llum: ") + value);
}
void MyFrame::SetTemperatura(wxString value){
     temperatura->SetLabel(wxString("Temperatura: ") + value);
}
void MyFrame::SetNivelBateria(wxString value){
     nivelBateria->SetLabel(wxString("Nivell bateria: ") + value);
}
void MyFrame::SetNivelXRay(wxString value){
     nivelXRay->SetLabel(wxString("Nivell Raig X: ") + value);
}
void MyFrame::SetImagen(wxString value){
     foto->SetBitmap(wxBitmap(value, wxBITMAP_TYPE_BMP));
}
void MyFrame::Alarm(wxString value){
     wxMessageBox(value);
}

//////////////////

Comunicacio_Interficie_Grafica::Comunicacio_Interficie_Grafica()
{
//   logica = referencia_gui;
}

int Comunicacio_Interficie_Grafica::establir_Parametres_Inicials(char *ip_mart, int port_mart, 
                                                                  int port_terra, char *fitxer_informe)
{
   //Inicialitzar amb els parametres obtinguts de la logica interficie grafica:
   int problema = control_terra -> inicialitzar_Dades(ip_mart,port_mart,port_terra,fitxer_informe);   
   if (!problema) {
      // Execucio d'un thread per a manegar el servidor XML-RPC de la Terra
      // que ofereix procediments remots al Mars Rovers de Mart.
      servidor = new Thread_Servidor_Terra(port_terra);
      servidor -> start();
      return 0;
   }
   else {
      return 1;
   }   
}   

void Comunicacio_Interficie_Grafica::set_Posicio_Robot(float x, float y, float z, int angleOrientacio, int angleAltura)
{
   // IMPLEMENTAR LA CRIDA AL CORRESPONENT WIDGET PER MOSTRAR LA INFORMACIO
   std::cout << "Obtencio de posicio: x=" << x << " y=" << y << " z=" << z
             << " angleOrientacio=" << angleOrientacio << " angleAltura=" << angleAltura << "\n";
   wxString posicio = wxString::Format(wxT("x: %f y: %f z:%f"), x, y, z, angleOrientacio, angleAltura);
   wxString angles = wxString::Format(wxT("%iº d'orientació, %iº d'alçada"), angleOrientacio, angleAltura);
   frame->SetPosicionRobot(posicio);
   frame->SetAnglesRobot(angles);
}   
void Comunicacio_Interficie_Grafica::set_Material(int material)
{
   // IMPLEMENTAR LA CRIDA AL CORRESPONENT WIDGET PER MOSTRAR LA INFORMACIO
   std::cout << "Obtencio de material: " << material << "\n";         
   wxString materialS = wxString::Format(wxT("%i"), material);
   frame->SetMaterial(materialS);
}   
void Comunicacio_Interficie_Grafica::set_Nivell_Ferro(float ferro)
{
   // IMPLEMENTAR LA CRIDA AL CORRESPONENT WIDGET PER MOSTRAR LA INFORMACIO
   std::cout << "Obtencio de nivell de ferro: " << ferro << "\n";
   wxString ferroS = wxString::Format(wxT("%f"), ferro);
   frame->SetNivelHierro(ferroS);
}   

void Comunicacio_Interficie_Grafica::set_Nivell_Llum(float llum)
{
   // IMPLEMENTAR LA CRIDA AL CORRESPONENT WIDGET PER MOSTRAR LA INFORMACIO
   std::cout << "Obtencio de nivell de llum: " << llum << "\n";         
   wxString llumS = wxString::Format(wxT("%f"), llum);
   frame->SetNivelLuz(llumS);
}   

void Comunicacio_Interficie_Grafica::set_Temperatura(int temperatura)
{
   // IMPLEMENTAR LA CRIDA AL CORRESPONENT WIDGET PER MOSTRAR LA INFORMACIO
   std::cout << "Obtencio de la temperatura: " << temperatura << "\n";
   wxString temperaturaS = wxString::Format(wxT("%i"), temperatura);
   frame->SetTemperatura(temperaturaS);
}   

void Comunicacio_Interficie_Grafica::set_Nivell_Bateria(int bateria)
{
   // IMPLEMENTAR LA CRIDA AL CORRESPONENT WIDGET PER MOSTRAR LA INFORMACIO
   std::cout << "Obtencio de nivell de bateria: " << bateria << "\n";     
   wxString bateriaS = wxString::Format(wxT("%i"), bateria);
   frame->SetNivelBateria(bateriaS);
}

void Comunicacio_Interficie_Grafica::set_Nivell_XRay(float xray)
{
   // IMPLEMENTAR LA CRIDA AL CORRESPONENT WIDGET PER MOSTRAR LA INFORMACIO
   std::cout << "Obtencio de nivell de xray: " << xray << "\n";   
   wxString xrayS = wxString::Format(wxT("%f"), xray);
   frame->SetNivelXRay(xrayS);
}   

void Comunicacio_Interficie_Grafica::set_Fotografia(char *fitxer_imatge)
{
   // IMPLEMENTAR LA CRIDA AL CORRESPONENT WIDGET PER MOSTRAR LA INFORMACIO
   std::cout << "Obtencio de fotografia correcta\n";
   frame->SetImagen(fitxer_imatge);
}   

void Comunicacio_Interficie_Grafica::indicar_Operacio_Fallida(char *operacio)
{
   // --------------------------------------------------------------------------
   // SEGONS CADA CAS S'INVOCARA AL WIDGET CORRESPONENT DE LA INTERFICIE GRAFICA
   // Es mostra temporalment per sortida estandard mentre no hi ha GUI
   // --------------------------------------------------------------------------
   if(strcmp(operacio,"posicio_robot") == 0) {
      std::cout << "Operacio de posicionament de robot fallida\n";
      frame->Alarm("Operacio de posicionament de robot fallida");
   }
   else if (strcmp(operacio,"material") == 0) {
      std::cout << "Operacio d'obtencio de material fallida\n";   
      frame->Alarm("Operacio d'obtencio de material fallida");
   }
   else if (strcmp(operacio,"ferro") == 0) {
      std::cout << "Operacio d'obtencio de ferro fallida\n";      
      frame->Alarm("Operacio d'obtencio de ferro fallida");
   }
   else if (strcmp(operacio,"temperatura") == 0) {
      std::cout << "Operacio d'obtencio de temperatura fallida\n";      
      frame->Alarm("Operacio d'obtencio de temperatura fallida");
   }
   else if (strcmp(operacio,"llum") == 0) {
      std::cout << "Operacio d'obtencio de llum fallida\n";      
      frame->Alarm("Operacio d'obtencio de llum fallida");
   }
   else if (strcmp(operacio,"bateria") == 0) {
      std::cout << "Operacio d'obtencio de nivell de bateria del robot fallida\n";     
      frame->Alarm("Operacio d'obtencio de nivell de bateria del robot fallida");
   }   
   else if (strcmp(operacio,"xray") == 0) {
      std::cout << "Operacio d'obtencio de raigs X fallida\n";      
      frame->Alarm("Operacio d'obtencio de raigs X fallida");
   }
   else if (strcmp(operacio,"obtenir_fotografia") == 0) {
      std::cout << "Operacio d'obtencio de fotografia fallida\n";      
      frame->Alarm("Operacio d'obtencio de fotografia fallida");
   }
   else if (strcmp(operacio,"girar_robot") == 0) {
      std::cout << "Operacio de gir del robot fallida\n";      
      frame->Alarm("Operacio de gir del robot fallida");
   }
   else if (strcmp(operacio,"girar_cameres_robot") == 0) {
      std::cout << "Operacio de gir de cameres del robot fallida\n";      
      frame->Alarm("Operacio de gir de cameres del robot fallida");
   }
   else if (strcmp(operacio,"activar_comunicacio_terra") == 0) {
      std::cout << "Operacio d'activacio de funcionament del robot fallida\n";      
      frame->Alarm("Operacio d'activacio de funcionament del robot fallida");
   }
   else if (strcmp(operacio,"desactivar_comunicacio_terra") == 0) {
      std::cout << "Operacio de desactivacio de funcionament del robot fallida\n";      
      frame->Alarm("Operacio de desactivacio de funcionament del robot fallida");
   }
   else if (strcmp(operacio,"inici_moviment_robot") == 0) {
      std::cout << "Operacio d'inici de moviment del robot fallida\n";    
      frame->Alarm("Operacio d'inici de moviment del robot fallida");
   }
   else if (strcmp(operacio,"fi_moviment_robot") == 0) {
      std::cout << "Operacio de finalitzacio de moviment del robot fallida\n";      
      frame->Alarm("Operacio de finalitzacio de moviment del robot fallida");
   }
   else if (strcmp(operacio,"dades_completes") == 0) {
      std::cout << "Operacio de obtencio de dades completes fallida\n";
      frame->Alarm("Operacio de obtencio de dades completes fallida");
   }   
   else if (strcmp(operacio,"canviar_camara_activa") == 0) {
      std::cout << "Operacio de modificacio de camara activa fallida\n";
      frame->Alarm("Operacio de modificacio de camara activa fallida");
   } 
}   

void Comunicacio_Interficie_Grafica::indicar_Parada_Emergencia(std::string motiu)
{
   // IMPLEMENTAR LA CRIDA AL CORRESPONENT WIDGET PER MOSTRAR LA INFORMACIO
   std::cout << "Parada de emergencia del robot per la causa: " + motiu + "\n";   
}   

/*Logica_Interficie_Grafica::Logica_Interficie_Grafica()
{
   // IMPLEMENTAR INTERFICIE GRAFICA I AFEGIR ELS METODES I CLASSES NECESSARIS
} */  


