/*
 *  
 *  $Id: panelconfiguracionubicaciones.cpp $
 *  Ginkgo CADx Project
 *
 *  Copyright 2008-12 MetaEmotion S.L. All rights reserved.
 *  http://ginkgo-cadx.com
 *
 *  This file is licensed under LGPL v3 license.
 *  See License.txt for details
 *
 *
 */
#include <vector>
#include <sstream>
#include <limits>

#include <wx/msgdlg.h>
#include <wx/msgout.h>
#include <wx/filename.h>
#include <main/controllers/configurationcontroller.h>
#include <wx/valtext.h>
#include <wx/ginkgostyle/ginkgostyle.h>
#include <wx/mstream.h>
#include <wx/dirdlg.h>

#include <wx/file.h>
#include <wx/dir.h>
#include <wx/log.h>
#include <wx/xml/xml.h>
#include <wx/log.h>

#include <wx/tokenzr.h>

#include "panelconfiguracionubicaciones.h"
#include <api/ubication.h>

#include <sstream>
#include <api/imodelointegracion.h>
#include <main/controllers/controladorextensiones.h>
#include <main/controllers/controladorlog.h>
#include <main/entorno.h>
#include <resources/ginkgoresourcesmanager.h>
#include <api/internationalization/internationalization.h>


#define SEPARADOR "|"

namespace Ubicaciones {
	class UbicacionesGridTable : public wxGridTableBase
	{
	public:

		GNC::GCS::IEntorno::MapaUbicaciones m_Ubicaciones;

		UbicacionesGridTable()
		{
		}


		virtual ~UbicacionesGridTable()
		{
			m_Ubicaciones.clear();
		}


		virtual int GetNumberRows()
		{
			 return m_Ubicaciones.size();
		}
		virtual int GetNumberCols()
		{
			return 6;
		}

		int FindUbicacion(const std::string& title)
		{
			int pos = -1;
			for (unsigned int i = 0; pos == -1 && i < m_Ubicaciones.size(); i++) {
				if (m_Ubicaciones.find(title) != m_Ubicaciones.end()) {
					pos = (int)i;
				}
			}
			return pos;
		}

		virtual bool AddUbicacion(const std::string& title, const std::string& path, const std::string& desc, bool monitorize, bool cleanbefore, bool cleanafter)
		{

			if (title.empty() || path.empty()) {
				LOG_ERROR("Config/Ubicaciones", "Title and path are both mandatory entries");
				return false;
			}
			if (FindUbicacion(title) != -1) {
				LOG_ERROR("Config/Ubicaciones", "Location entry already exists");
				return false;
			}

			m_Ubicaciones[title] = new GIL::Ubicacion(title, path, desc, monitorize, cleanbefore, cleanafter);
			wxGridTableMessage msg1( this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
	                        m_Ubicaciones.size() - 1, 1);
			GetView()->ProcessTableMessage( msg1 );

			wxGridTableMessage msg2( this, wxGRIDTABLE_REQUEST_VIEW_GET_VALUES,
					0, m_Ubicaciones.size());
			GetView()->ProcessTableMessage( msg2 );
			GetView()->Refresh();
			return true;
		}

		virtual void RemoveUbicacion(const std::string& titulo)
		{
			RemoveUbicacion(FindUbicacion(titulo));
		}

		virtual void RemoveUbicacion(GIL::Ubicacion& ub)
		{
			RemoveUbicacion(FindUbicacion(ub.Titulo));

		}

		virtual bool DeleteRows( size_t pos = 0, size_t numRows = 1 )
		{
			bool removed = false;
			for (unsigned int i = 0; i < numRows; i++) {
				RemoveUbicacion(pos);
				removed = true;
			}
			return removed;
		}

		virtual void RemoveUbicacion(int pos)
		{
			if (pos < 0) {
				return;
			}
			else {
				GNC::GCS::IEntorno::MapaUbicaciones::iterator it;
				int i = 0;
				for (it = m_Ubicaciones.begin(); it != m_Ubicaciones.end() && i != pos; ++it, i++);
				if (it != m_Ubicaciones.end()) {
					m_Ubicaciones.erase(  it );
					wxGridTableMessage msg1( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, pos, 1);
					GetView()->ProcessTableMessage( msg1 );
					wxGridTableMessage msg2( this, wxGRIDTABLE_REQUEST_VIEW_GET_VALUES,
						0, m_Ubicaciones.size());
					GetView()->ProcessTableMessage( msg2 );
					GetView()->Refresh();
				}
			}
		}

		virtual void UpdateUbicacion(int pos, const std::string& title, const std::string& path, const std::string& desc, bool monitorize, bool cleanbefore, bool cleanafter)
		{
			if (pos >= 0 && pos < (int)m_Ubicaciones.size()) {
				GNC::GCS::IEntorno::MapaUbicaciones::iterator it;
				int i = 0;
				for (it = m_Ubicaciones.begin(); it != m_Ubicaciones.end() && i != pos; ++it, i++);
				if (it != m_Ubicaciones.end()) {
					GIL::Ubicacion* d = (*it).second;
					if (d->Titulo != title) {
						m_Ubicaciones.erase(  it );
						delete d;
					/*	wxGridTableMessage msg1( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, pos, 1);
						GetView()->ProcessTableMessage( msg1 );*/
						m_Ubicaciones[title] = new GIL::Ubicacion(title, path, desc, monitorize, cleanbefore, cleanafter);
						/*wxGridTableMessage msg2( this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
	                        m_Ubicaciones.size() - 1, 1);
						GetView()->ProcessTableMessage( msg1 );*/
					} else {
						d->Update(path, desc, monitorize, cleanbefore, cleanafter);
					}
					
					wxGridTableMessage msg( this, wxGRIDTABLE_REQUEST_VIEW_GET_VALUES, 0, m_Ubicaciones.size());
					GetView()->ProcessTableMessage( msg );
					GetView()->Refresh();
				}
			}
		}

		virtual GIL::Ubicacion* GetUbicacion(int pos)
		{
			if (pos < 0 || pos > (int) m_Ubicaciones.size()) {
				return NULL;
			}
			else {
				GNC::GCS::IEntorno::MapaUbicaciones::iterator it;
				int i = 0;
				for (it = m_Ubicaciones.begin(); it != m_Ubicaciones.end() && i != pos; ++it, i++);

				if (it != m_Ubicaciones.end()) {
					GIL::Ubicacion* d = (*it).second;
					return d;
				}
				else {
					return NULL;
				}
			}
		}

		virtual bool IsEmptyCell( int row, int /*col*/ )
		{
			if (row >= (int)m_Ubicaciones.size()) {
				return true;
			}
			else {
				return false;
			}
		}

		virtual wxString GetValue( int row, int col )
		{
			const GIL::Ubicacion& u = *(GetUbicacion(row));

			switch ( col )
			{
				case 0:
					return wxString::FromUTF8( u.Titulo.c_str() );
				case 1:
					return u.Monitorize ? _("Yes") : _("No");
				case 2:
					return u.CleanBefore ? _("Yes") : _("No");
				case 3:
					return u.CleanAfter ? _("Yes") : _("No");		
				case 4:
					return wxString::FromUTF8( u.Descripcion.c_str() );			
				case 5:
					return wxString::FromUTF8( u.Ruta.c_str() );
			}

			return wxEmptyString;
		}
		virtual void SetValue( int /*row*/, int /*col*/, const wxString& /*value*/ )
		{
		}

		virtual wxString GetColLabelValue( int col )
		{
			switch ( col )
			{
				case 0:
					return _("Title");
				case 1:
					return _("Monitorize");
				case 2:
					return _("Clean before");
				case 3:
					return _("Clean after");
				case 4:
					return _("Description");
				case 5:
					return _("Path");
			}

			wxFAIL_MSG(_("unknown column"));

			return wxEmptyString;
		}

		virtual wxString GetTypeName( int /*row*/, int col )
		{

			switch ( col )
			{
				case 0:
					return wxGRID_VALUE_STRING;

				case 1:
					return wxGRID_VALUE_STRING;

				case 2:
					return wxGRID_VALUE_STRING;

				case 3:
					return wxGRID_VALUE_STRING;

				case 4:
					return wxGRID_VALUE_STRING;

				case 5:
					return wxGRID_VALUE_STRING;
			}

			wxFAIL_MSG(_("unknown column"));

			return wxEmptyString;
		}

		virtual bool CanGetValueAs( int /*row*/, int /*col*/, const wxString& typeName )
		{
			if ( typeName == wxGRID_VALUE_STRING )
			{
				return true;
			}
			return false;
		}

		virtual bool CanSetValueAs( int row, int col, const wxString& typeName )
		{
			 return CanGetValueAs(row, col, typeName);
		}
	};
}


namespace GNC {
	namespace GUI {

		class DialogoAddLocationDialog: public DialogoAddLocationBase
		{

		public:
			DialogoAddLocationDialog(wxWindow* pParent, const Ubicaciones::UbicacionesGridTable* const pUbicacionesGridTable, const GIL::Ubicacion& u, bool isnew = false) : DialogoAddLocationBase(pParent), m_pUbicacionesGridTable(pUbicacionesGridTable)
			{
				m_Ubicacion = u;
				m_IsNew = isnew;
				m_Ok = false;

				m_pTETitle->SetValue( wxString::FromUTF8( m_Ubicacion.Titulo.c_str() ) );
				m_pTELocation->SetValue( wxString::FromUTF8( m_Ubicacion.Ruta.c_str() ) );
				m_pTEDesc->SetValue( wxString::FromUTF8( m_Ubicacion.Descripcion.c_str() ) );
				m_pMonitorize->SetValue(m_Ubicacion.Monitorize);
				m_pCleanBefore->SetValue(m_Ubicacion.CleanBefore);
				m_pCleanAfter->SetValue(m_Ubicacion.CleanAfter);

			}

			~DialogoAddLocationDialog()
			{

			}

			virtual void OnOpenDirClick( wxCommandEvent& /*event*/ ) {
				wxDirDialog dlg(this, _("Choose a directory"), wxEmptyString, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
				if ( dlg.ShowModal() ) {
					wxString path = dlg.GetPath();
					if (path.size() > 0) {
						m_pTELocation->SetValue(path);
					}
				}
			}

			virtual void OnAceptarClick( wxCommandEvent& /*event*/ ) {
				if (Validar()) {
					m_Ok = true;
					Close();
				}
			}

			bool Validar() {

				if(m_pTETitle->GetValue() != wxEmptyString && m_pTELocation->GetValue() != wxEmptyString) {

					std::string title (m_pTETitle->GetValue().ToUTF8());

					for (GNC::GCS::IEntorno::MapaUbicaciones::const_iterator it = m_pUbicacionesGridTable->m_Ubicaciones.begin(); it != m_pUbicacionesGridTable->m_Ubicaciones.end(); ++it)
					{
						const std::string& ti = (*it).first;
						if ((ti == title && m_IsNew) || (!m_IsNew && ti == title && title != m_Ubicacion.Titulo) ){
							wxMessageBox(_("Location titles can't be repeated"),_("Error"),wxOK | wxICON_ERROR, this);
							return false;
						}
					}

					if (title.size() > 8)
					{
						wxMessageBox(_("Maximum length of title is 8 characters"),_("Error"),wxOK | wxICON_ERROR, this);
						return false;
					}

					if (!wxDir::Exists(m_pTELocation->GetValue()))
					{
						wxMessageBox(_("The selected directory can't be opened"),_("Error"),wxOK | wxICON_ERROR, this);
						return false;
					}

					if (m_IsNew) {
						m_Ubicacion = GIL::Ubicacion(
							title,
							std::string(m_pTELocation->GetValue().ToUTF8()),
							std::string(m_pTEDesc->GetValue().ToUTF8()),
							m_pMonitorize->GetValue(),
							m_pCleanBefore->GetValue(),
							m_pCleanAfter->GetValue());
					}
					else {
						m_Ubicacion.Update(
							std::string(m_pTELocation->GetValue().ToUTF8()),
							std::string(m_pTEDesc->GetValue().ToUTF8()),
							m_pMonitorize->GetValue(),
							m_pCleanBefore->GetValue(),
							m_pCleanAfter->GetValue());
						m_Ubicacion.Titulo = title;
					}

					return true;
				}
				else{
					wxMessageBox(_("You must fill both title and location fields to continue") ,_("Error"),wxOK | wxICON_ERROR, this);
					return false;
				}
			}

			bool                                           m_Ok;
			bool                                           m_IsNew;
			GIL::Ubicacion                                 m_Ubicacion;
			const Ubicaciones::UbicacionesGridTable* const m_pUbicacionesGridTable;
		};


		////////////////-------------------------------------------------------------------------------------/////////////////////////////

		PanelConfiguracionUbicaciones::PanelConfiguracionUbicaciones(wxWindow* pParent, IDialogoConfiguracion* pDialogo): PanelConfiguracionUbicacionesBase(pParent), IPasoConfiguracion(pDialogo)
		{
			m_pUbicacionesGridTable = new Ubicaciones::UbicacionesGridTable();
			m_pGridUbicaciones->SetTable(m_pUbicacionesGridTable, false, wxGrid::wxGridSelectRows);
			m_pUbicacionesGridTable->SetView(m_pGridUbicaciones);

			wxGridCellAttr *attrRO = new wxGridCellAttr();

			attrRO->SetReadOnly();

			for (int i = 0; i < m_pUbicacionesGridTable->GetNumberCols(); i++) {
				m_pGridUbicaciones->SetColAttr(i, attrRO);
			}
			m_pGridUbicaciones->SetMargins(1, 1);
			//m_pGridUbicaciones->SetSelectionMode(wxGrid::wxGridSelectRows);

			m_pGridUbicaciones->Connect(wxEVT_GRID_RANGE_SELECT, wxGridRangeSelectEventHandler(PanelConfiguracionUbicaciones::OnGridSelectionChanged), NULL, this);
			m_pGridUbicaciones->Connect(wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler(PanelConfiguracionUbicaciones::OnGridDClick), NULL, this);
			Recargar();
			m_pUbicaciones->Layout();
			Layout();
			AutoSizeGrid();
			m_pGridUbicaciones->EnableDragColSize(true);
		}

		PanelConfiguracionUbicaciones::~PanelConfiguracionUbicaciones()
		{
			m_pUbicacionesGridTable->SetView(NULL);
			m_pGridUbicaciones->SetTable(NULL);
			m_pUbicacionesGridTable->Clear();
		}

		void PanelConfiguracionUbicaciones::Recargar()
		{
			GNC::GCS::ConfigurationController::TListGroups locations;
			GNC::GCS::ConfigurationController::Instance()->readGroupGeneral("/GinkgoCore/Locations", locations);

			m_pUbicacionesGridTable->Clear();
			for (GNC::GCS::ConfigurationController::TListGroups::iterator it = locations.begin(); it != locations.end(); ++it) {
				std::string title, path, descr;
				bool monitorize, cleanbefore, cleanafter;
				(*it).readStringValue("Title", title);
				(*it).readStringValue("Path", path);
				(*it).readStringValue("Description", descr);
				(*it).readBoolValue("Monitorize", monitorize, false);
				(*it).readBoolValue("CleanBefore", cleanbefore, false);
				(*it).readBoolValue("CleanAfter", cleanafter, false);
				m_pUbicacionesGridTable->AddUbicacion(title, path, descr, monitorize, cleanbefore, cleanafter);
			}
		}

		//region "Metodos de IPasoConfiguracion"
		wxWindow* PanelConfiguracionUbicaciones::GetPanel()
		{
			return this;
		}

		std::string PanelConfiguracionUbicaciones::GetTitle()
		{
			return _Std("Locations");
		}

		std::string PanelConfiguracionUbicaciones::GetCabecera()
		{
			return _Std("Location Settings");
		}

		bool PanelConfiguracionUbicaciones::Validar()
		{
			bool ok = true;

			return ok;
		}

		bool PanelConfiguracionUbicaciones::Guardar()
		{
			GNC::GCS::IEntorno::MapaUbicaciones& mapa = GNC::Entorno::Instance()->GetUbicaciones();
			for (GNC::GCS::IEntorno::MapaUbicaciones::iterator it = mapa.begin(); it != mapa.end(); ++it) {
				delete (*it).second;
			}
			mapa.clear();

			GNC::GCS::ConfigurationController::Instance()->deleteEntryGeneral("/GinkgoCore/Locations");
			GNC::GCS::ConfigurationController::TListGroups locations;

			for (GNC::GCS::IEntorno::MapaUbicaciones::iterator it = m_pUbicacionesGridTable->m_Ubicaciones.begin(); it != m_pUbicacionesGridTable->m_Ubicaciones.end(); ++it) {
				GIL::Ubicacion* u = (*it).second;
				mapa[u->Titulo] = u;
				GNC::GCS::ConfigurationController::TMapValues location;
				location["Title"] = u->Titulo;
				location["Path"] = u->Ruta;
				location["Description"] = u->Descripcion;
				location.insertBool("Monitorize", u->Monitorize);
				location.insertBool("CleanBefore", u->CleanBefore);
				location.insertBool("CleanAfter", u->CleanAfter);
				locations.push_back(location);
			}
			GNC::GCS::ConfigurationController::Instance()->writeGroupGeneral("/GinkgoCore/Locations", locations, "Location");

			return true;
		}
		//endregion


		void PanelConfiguracionUbicaciones::OnGridDClick(wxGridEvent&)
		{
			wxCommandEvent evt;
			OnEditarClick(evt);
		}

		void PanelConfiguracionUbicaciones::OnGridSelectionChanged(wxGridRangeSelectEvent& event)
		{
			if (event.Selecting()) {
				m_pGridUbicaciones->BeginBatch();
				if (event.GetBottomRow() != event.GetTopRow()) {
					m_pGridUbicaciones->SelectRow(event.GetTopRow(), false);
				}
				if (m_pGridUbicaciones->GetSelectedRows().size() == 0) {
					m_pGridUbicaciones->SelectRow(event.GetTopRow(), false);
				}
				if (event.GetSelection() >= 0) {
					m_pBotonEdit->Enable(true);
					m_pBotonDelete->Enable(true);
				}
				else {
					m_pBotonEdit->Enable(false);
					m_pBotonDelete->Enable(false);
				}
				m_pGridUbicaciones->EndBatch();
			}
			else {
				m_pBotonEdit->Enable(false);
				m_pBotonDelete->Enable(false);
			}
		}


		void PanelConfiguracionUbicaciones::OnNuevoClick(wxCommandEvent &){

			DialogoAddLocationDialog dlg(this, m_pUbicacionesGridTable, GIL::Ubicacion(), true);
			dlg.ShowModal();
			if (dlg.m_Ok) {
				GIL::Ubicacion& u = dlg.m_Ubicacion;
				m_pUbicacionesGridTable->AddUbicacion(u.Titulo, u.Ruta, u.Descripcion, u.Monitorize, u.CleanBefore, u.CleanAfter);
				OnPropiedadCambiada();
			}
		}

		void PanelConfiguracionUbicaciones::OnEditarClick(wxCommandEvent &){
			GIL::Ubicacion u;
			wxArrayInt asel = m_pGridUbicaciones->GetSelectedRows();
			if (asel.size() > 0) {
				int sel = asel.front();
				GIL::Ubicacion *pSel = m_pUbicacionesGridTable->GetUbicacion(sel);
				if (pSel != NULL) {
					u = *pSel;
					DialogoAddLocationDialog dlg(this, m_pUbicacionesGridTable, u, false);
					dlg.ShowModal();
					if (dlg.m_Ok) {
						m_pUbicacionesGridTable->UpdateUbicacion(sel, dlg.m_Ubicacion.Titulo, dlg.m_Ubicacion.Ruta, dlg.m_Ubicacion.Descripcion, dlg.m_Ubicacion.Monitorize, dlg.m_Ubicacion.CleanBefore, dlg.m_Ubicacion.CleanAfter);
						OnPropiedadCambiada();
					}
				}
			}
		}

		void PanelConfiguracionUbicaciones::OnEliminarClick(wxCommandEvent &){
			m_pGridUbicaciones->BeginBatch();
			wxArrayInt asel = m_pGridUbicaciones->GetSelectedRows();

			if (asel.size() > 0) {
				int sel = asel.front();
				m_pUbicacionesGridTable->RemoveUbicacion(sel);
				m_pBotonEdit->Enable(false);
				m_pBotonDelete->Enable(false);
				OnPropiedadCambiada();
			}
			m_pGridUbicaciones->EndBatch();
		}

		
		void PanelConfiguracionUbicaciones::OnHelpClick(wxMouseEvent &)
		{
		}

		void PanelConfiguracionUbicaciones::OnSize(wxSizeEvent & event){
			event.Skip(true);
		}

	//region "Helpers"

		void PanelConfiguracionUbicaciones::AutoSizeGrid()
		{
		/*	wxSize s = m_pGridUbicaciones->GetClientSize();

			float prop = 1.0f / ( (float)m_pGridUbicaciones->GetNumberCols() );

			int cw = s.GetWidth();
			int aw = 0;
			int i = 0;
			for (; i < m_pGridUbicaciones->GetNumberCols() - 1; i++)
			{
				int iw = (int) (prop * (float)cw);
				aw += iw;
				m_pGridUbicaciones->SetColSize(i,  iw);
			}
			if ( i < m_pGridUbicaciones->GetNumberCols()) {
				m_pGridUbicaciones->SetColSize(i, cw - aw );
			}
		*/	
			m_pGridUbicaciones->AutoSize();
			m_pGridUbicaciones->AutoSizeColumns(true);
			m_pGridUbicaciones->Refresh();
		}
	//endregion
	}
}
