using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ArcGIS.Core.CIM;
using ArcGIS.Core.Data;
using ArcGIS.Core.Data.UtilityNetwork.Trace;
using ArcGIS.Core.Geometry;
using ArcGIS.Desktop.Catalog;
using ArcGIS.Desktop.Core;
using ArcGIS.Desktop.Editing;
using ArcGIS.Desktop.Extensions;
using ArcGIS.Desktop.Framework;
using ArcGIS.Desktop.Framework.Contracts;
using ArcGIS.Desktop.Framework.Dialogs;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.Mapping;
using System.Collections.ObjectModel;
using OliviaAddInPro.Model;
using OliviaAddInPro.Helper;
using ArcGIS.Desktop.Internal.Layouts.Utilities;
using OliviaAddInPro.Services;
using System.Windows;

namespace OliviaAddInPro
{
    internal class PaneRecogidaSub1ViewModel : PanelViewModelBase
    {
        private ObservableCollection<EnabledComboBoxItem<string>> tiposFrac = new ObservableCollection<EnabledComboBoxItem<string>>();
        private ObservableCollection<EnabledComboBoxItem<string>> tiposCarg = new ObservableCollection<EnabledComboBoxItem<string>>();
        private ObservableCollection<string> tiposLate = new ObservableCollection<string>();
        private ObservableCollection<string> tiposVehic = new ObservableCollection<string>();
        private ObservableCollection<string> tiposCapac = new ObservableCollection<string>();
        private RecogidaServ recoServ = new RecogidaServ(null); //no hace falta instancia reco aquí

        /** 
        * Array de booleanos enumerando si se existen en la capa seleccionada los tipos de fracción
        */
        public bool[] tipos_fracc_bool = new bool[(int)RecogidaDef.TiposFracción.N - 1];
        /** 
        * Array de booleanos enumerando si se existen en la capa seleccionada los tipos de carga
        */
        public bool[] tipos_carg_bool = new bool[(int)RecogidaDef.TiposCarga.N - 1];
        /** 
        * Array de cadenas de caracteres enumerando si se existen en la capa seleccionada los tipos de vehículos
        */
        public bool[] tipos_vehic_bool = new bool[(int)RecogidaDef.TiposVehic.N];

        #region Properties     

        public override string DisplayName
        {
            get { return Resource1.String_tto; }
        }
        public ObservableCollection<EnabledComboBoxItem<string>> TiposFrac
        {
            get { return tiposFrac; }
            set
            {
                tiposFrac = value;
                base.NotifyPropertyChanged("TiposFrac");
            }
        }
        public ObservableCollection<EnabledComboBoxItem<string>> TiposCarg
        {
            get { return tiposCarg; }
            set
            {
                tiposCarg = value;
                base.NotifyPropertyChanged("TiposCarg");
            }
        }
        public ObservableCollection<string> TiposVehic
        {
            get { return tiposVehic; }
            set
            {
                tiposVehic = value;
                base.NotifyPropertyChanged("TiposVehic");
            }
        }
        public ObservableCollection<string> TiposCapac
        {
            get { return tiposCapac; }
            set
            {
                tiposCapac = value;
                base.NotifyPropertyChanged("TiposCapac");
            }
        }
        public ObservableCollection<string> TiposLate
        {
            get { return tiposLate; }
            set
            {
                tiposLate = value;
                base.NotifyPropertyChanged("TiposLate");
            }
        }
        private int tipoFrac = -1;
        public int TipoFrac
        {
            get { return tipoFrac; }
            set
            {
                tipoFrac = value;
                base.NotifyPropertyChanged("TipoFrac");
            }
        }
        private int tipoCarg = -1;
        public int TipoCarg
        {
            get { return tipoCarg; }
            set
            {
                tipoCarg = value;
                base.NotifyPropertyChanged("TipoCarg");
            }
        }
        private int tipoVehic = -1;
        public int TipoVehic
        {
            get { return tipoVehic; }
            set
            {
                tipoVehic = value;
                base.NotifyPropertyChanged("TipoVehic");
            }
        }
        private int tipoCapac = -1;
        public int TipoCapac
        {
            get { return tipoCapac; }
            set
            {
                tipoCapac = value;
                base.NotifyPropertyChanged("TipoCapac");
            }
        }
        private int tipoLate = -1;
        public int TipoLate
        {
            get { return tipoLate; }
            set
            {
                tipoLate = value;
                base.NotifyPropertyChanged("TipoLate");
            }
        }
        private string textKgCapac="";
        public string TextKgCapac
        {
            get { return textKgCapac; }
            set { base.SetProperty(ref textKgCapac, value, () => TextKgCapac); }
        }
        private string textDensCont="";
        public string TextDensCont
        {
            get { return textDensCont; }
            set { base.SetProperty(ref textDensCont, value, () => TextDensCont); }
        }
        private Visibility visTextDens = Visibility.Hidden;
        public Visibility VisTextDens
        {
            get { return visTextDens; }

            set
            {
                visTextDens = value;
                base.NotifyPropertyChanged("VisTextDens");
            }
        }
        private Visibility visCombLate = Visibility.Hidden;
        public Visibility VisCombLate
        {
            get { return visCombLate; }

            set
            {
                visCombLate = value;
                base.NotifyPropertyChanged("VisCombLate");
            }
        }
        private string toolTip_TextDensCont = Resource1.String_tooltip_textbox_denscont;
        public string ToolTip_TextDensCont
        {
            get { return toolTip_TextDensCont; }

            set
            {
                toolTip_TextDensCont = value;
                base.NotifyPropertyChanged("ToolTip_TextDensCont");
            }
        }
        private bool enabComboCapac = false;
        public bool EnabComboCapac
        {
            get { return CapaAbierta && enabComboCapacFrac; }
            set
            {
                enabComboCapac = value;
                base.NotifyPropertyChanged("EnabComboCapac");
            }
        }
        private bool enabComboCapacFrac = true;
        public bool EnabComboCapacFrac  
        {
            get { return enabComboCapacFrac; }
            set
            {
                enabComboCapacFrac = value;
                base.NotifyPropertyChanged("EnabComboCapacFrac");
                base.NotifyPropertyChanged("EnabComboCapac");
            }
        }
        private string textTVaci = "";
        public string TextTVaci
        {
            get { return textTVaci; }
            set { base.SetProperty(ref textTVaci, value, () => TextTVaci); }
        }
        private string lblCapaPlant = Resource1.String_selec_capa;
        public string LblCapaPlant
        {
            get { return lblCapaPlant; }
            set { base.SetProperty(ref lblCapaPlant, value, () => LblCapaPlant); }
        }
        /**
         * Coordenadas de la planta de descarga
         */
        public Coordinate2D CoordsPlanta { get; set; } = new Coordinate2D(0, 0);
        /**
         * kg de carga en cada contenedor. 
         * Si se cogen llenos, vale -1 (los kg son densidad_cont*capac). 
         * Si se lee el campo, es 0 (los kg son los leídos en el campo).
         * Si se pone a todos los cont lo mismo, vale esos kg
         */
        private int kgCont = -1; 
        public int KgCont
        {
            get { return kgCont; }
            set
            {
                kgCont = value;
                base.NotifyPropertyChanged("KgCont");
            }
        }
        #endregion

        public PaneRecogidaSub1ViewModel()
        {
            if (RecogidaDef.lleno)
            {
                KgCont = -1;
            }
            else if (RecogidaDef.kgrec_camp)
            {
                KgCont = 0;
            }
            else
            {
                KgCont = RecogidaDef.kgrec_cont;
            }
        }
        /**
         * Realiza las comprobaciones para cuando se ha abierto una capa
         */
        public bool AbiertaCapa(string capa)
        {
            CapaAbierta = false;
            CapaElems = string.Empty;
            TiposFrac.Clear();
            TiposCarg.Clear();
            TiposVehic.Clear();
            TiposCapac.Clear();
            OliviaGlob.AddFlagTipEjec(TiposEjecucion.Config); //lo reinicia, por si estaba después de planificar
            OliviaGlob.RemoveFlagTipEjec(TiposEjecucion.Config2);
            if (string.IsNullOrEmpty(capa))
                return false;

            //comprueba los campos de recogida
            int camp = recoServ.CompruebaCamposReco(capa);
            if (camp>1 || (camp==1 && RecogidaDef.kgrec_camp))
            {
                HelperGlobal.ponMsg(recoServ.ErrStr, System.Windows.MessageBoxImage.Warning);
                return false;
            }
            //lee qué fracciones hay en la gdb
            ObservableCollection<string> valores = recoServ.DameVals(capa, RecogidaDef.campos_def.cons_fracc);
            if (valores==null)
            {
                HelperGlobal.ponMsg(recoServ.ErrStr, System.Windows.MessageBoxImage.Warning);
                return false;
            }
            rellenaFrac(valores);

            //se rellena el array que se incorpora al desplegable relacionado con el tipo de basura
            valores = recoServ.DameVals(capa, RecogidaDef.campos_def.cons_nomrec);
            if (valores == null)
            {
                HelperGlobal.ponMsg(recoServ.ErrStr, System.Windows.MessageBoxImage.Warning);
                return false;
            }
            rellenaCarg(valores);

            if (RecogidaDef.lleno)
            {
                VisTextDens = Visibility.Visible;
            }
            else
            {
                VisTextDens = Visibility.Hidden;
            }
            TiposVehic.Clear();
            for (int i = 0; i < RecogidaDef.tipos_vehic_str.Length; i++)
            {
                TiposVehic.Add(RecogidaDef.tipos_vehic_str[i]);
            }
            TiposLate.Clear();
            for (int i = 0; i < RecogidaDef.tipos_lateralidad.Length; i++)
            {
                TiposLate.Add(RecogidaDef.tipos_lateralidad[i]);
            }
            TiposCapac.Clear();

            //hay elementos en la gdb            
            CapaElems = capa;
            CapaAbierta = true;
            return true;
        }
        public void rellenaFrac(ObservableCollection<string> valoresFrac)
        {
            //se redimensionan los arrays de nuevo por si se ha pinchado varias veces en el botón de leer tabla
            System.Array.Resize(ref RecogidaDef.tipos_fracc_str, (int)RecogidaDef.TiposFracción.N - 1);
            System.Array.Resize(ref tipos_fracc_bool, (int)RecogidaDef.TiposFracción.N - 1);
            bool encontrado = false;
            int i, j;
            for (i = 0; i < valoresFrac.Count; i++)
            {
                //para que ponga '-' si es un campo vacío
                if (valoresFrac[i] == "")
                    valoresFrac[i] = "-";

                encontrado = false;
                for (j = 0; j < (int)RecogidaDef.TiposFracción.N - 1; j++)
                {
                    if (RecogidaDef.tipos_fracc_str[j] == valoresFrac[i])
                    {
                        tipos_fracc_bool[j] = true;
                        encontrado = true;
                        break;
                    }
                }
                if (encontrado == false)
                {
                    System.Array.Resize(ref RecogidaDef.tipos_fracc_str, RecogidaDef.tipos_fracc_str.Length + 1);
                    System.Array.Resize(ref tipos_fracc_bool, tipos_fracc_bool.Length + 1);
                    RecogidaDef.tipos_fracc_str[RecogidaDef.tipos_fracc_str.Length - 1] = valoresFrac[i];
                    tipos_fracc_bool[tipos_fracc_bool.Length - 1] = true;
                }
            }
            for(i=0;i< RecogidaDef.tipos_fracc_str.Length;i++)
            {
                TiposFrac.Add(new EnabledComboBoxItem<string>(RecogidaDef.tipos_fracc_str[i]));
                TiposFrac.ElementAt(i).IsEnabled= tipos_fracc_bool[i];
            }
        }
        public void rellenaCarg(ObservableCollection<string> valores)
        {                        
            int i, j;
            bool encontrado;
            
            //se redimensionan los arrays de nuevo por si se ha pinchado varias veces en el botón de leer tabla
            System.Array.Resize(ref RecogidaDef.tipos_carg_str, (int)RecogidaDef.TiposCarga.N - 1);
            System.Array.Resize(ref tipos_carg_bool, (int)RecogidaDef.TiposCarga.N - 1);

            for (i = 0; i < valores.Count; i++)
            {
                //para que ponga '-' si es un campo vacío
                if (valores[i] == "")
                    valores[i] = "-";

                encontrado = false;
                for (j = 0; j < (int)RecogidaDef.TiposCarga.N - 1; j++)
                {
                    if (RecogidaDef.tipos_carg_str[j] == valores[i])
                    {
                        tipos_carg_bool[j] = true;
                        encontrado = true;
                        break;
                    }
                }
                if (encontrado == false)
                {
                    System.Array.Resize(ref RecogidaDef.tipos_carg_str, RecogidaDef.tipos_carg_str.Length + 1);
                    System.Array.Resize(ref tipos_carg_bool, tipos_carg_bool.Length + 1);
                    RecogidaDef.tipos_carg_str[RecogidaDef.tipos_carg_str.Length - 1] = valores[i];
                    tipos_carg_bool[tipos_carg_bool.Length - 1] = true;
                }
            }
            for (i = 0; i < RecogidaDef.tipos_carg_str.Length; i++)
            {
                TiposCarg.Add(new EnabledComboBoxItem<string>(RecogidaDef.tipos_carg_str[i]));
                TiposCarg.ElementAt(i).IsEnabled =tipos_carg_bool[i];
            }
        }
        /**
         * Realiza los cambios en los ámbitos cuando se ha seleccionado una fracción
         */
        public bool ComboFracSel(int tto)
        {
            if (tto < 0)
                return false;
            if (!tipos_fracc_bool[tto])
            {
                
                return false;
            }
            try
            {
                //cuando se selecciona un item pintado en gris (que no existe en la GDB) se actúa como si no se hubiera seleccionado item
                TipoFrac = tto;  
                if ((TipoVehic >= 0) && (TipoCarg >= 0))
                {
                    //si también se ha seleccionado tipo de carga y de vehículo, se rellena la lista de capacidades
                    rellena_capac();
                }
                if (RecogidaDef.lleno)
                {
                    if (TipoFrac < (int)RecogidaDef.TiposFracción.Otra)
                    {
                        TextDensCont = RecogidaDef.dens_frac_cont[TipoFrac].ToString();
                    }
                    else
                    {
                        TextDensCont = "";
                    }
                }
            }
            catch (Exception)
            {
                HelperGlobal.ponMsg("Error al seleccionar el tipo de fracción");
                return false;
            }
            return true;

        }
        /**
         * Rellena la lista de capacidades de vehículos disponibles
         */
        private void rellena_capac()
        {
            TiposCapac.Clear();
            TextKgCapac = "";
            if (TipoVehic >= 0 && TipoVehic < (int)RecogidaDef.TiposVehic.N &&
                TipoCarg >= 0 && TipoCarg < (int)RecogidaDef.TiposCarga.N)
            {
                TiposCapac.Clear();
                TextKgCapac="";
                if (RecogidaDef.cargas_max_vehic[TipoCarg, TipoVehic].n > 0)
                {
                    for (int i = 0; i < RecogidaDef.cargas_max_vehic[TipoCarg, TipoVehic].n; i++)
                        TiposCapac.Add(RecogidaDef.cargas_max_vehic[TipoCarg, TipoVehic].vol[i] + " m3");
                }

            }
            else if (TipoVehic >= 0 && TipoVehic < (int)RecogidaDef.TiposVehic.N &&
                TipoCarg >= (int)RecogidaDef.TiposCarga.N)
            {
                if (RecogidaDef.cargas_max_vehic[(int)RecogidaDef.TiposCarga.Otra, TipoVehic].n > 0)
                {
                    for (int i = 0; i < RecogidaDef.cargas_max_vehic[(int)RecogidaDef.TiposCarga.Otra, TipoVehic].n; i++)
                        TiposCapac.Add(RecogidaDef.cargas_max_vehic[(int)RecogidaDef.TiposCarga.Otra, TipoVehic].vol[i] + " m3");
                }
            }
        }

        /**
         * Rellena la caja de texto con la capacidad en kg máxima del vehículo seleccionado
         */
        private void rellena_kgmax()
        {
            int kgmax, off;

            if (TipoVehic >= 0 && TipoVehic < (int)RecogidaDef.TiposVehic.N &&
                TipoCarg >= 0 && TipoCarg < (int)RecogidaDef.TiposCarga.N &&
                TipoCapac >= 0 && TipoCapac < (int)RecogidaDef.cargas_max_vehic[TipoCarg, TipoVehic].n)
            {
                if ((RecogidaDef.cargas_max_vehic[TipoCarg, TipoVehic].offset != null) && (TipoFrac < (int)RecogidaDef.TiposFracción.N))
                    off = RecogidaDef.cargas_max_vehic[TipoCarg, TipoVehic].offset[TipoCapac, TipoFrac];
                else if ((RecogidaDef.cargas_max_vehic[TipoCarg, TipoVehic].offset != null) && (TipoFrac >= (int)RecogidaDef.TiposFracción.N))
                    off = RecogidaDef.cargas_max_vehic[TipoCarg, TipoVehic].offset[TipoCapac, (int)RecogidaDef.TiposFracción.Otra];
                else
                    off = 0;
                if (TipoFrac < (int)RecogidaDef.TiposFracción.N)
                    kgmax = RecogidaDef.cargas_max_vehic[TipoCarg, TipoVehic].vol[TipoCapac] * RecogidaDef.dens_frac_cami[TipoFrac] + off;
                else
                    kgmax = RecogidaDef.cargas_max_vehic[TipoCarg, TipoVehic].vol[TipoCapac] * RecogidaDef.dens_frac_cami[(int)RecogidaDef.TiposFracción.Otra] + off;
                TextKgCapac = kgmax.ToString();
            }

            else if (TipoVehic >= 0 && TipoVehic < (int)RecogidaDef.TiposVehic.N &&
                TipoCarg >= (int)RecogidaDef.TiposCarga.N &&
                TipoCapac >= 0 && TipoCapac < (int)RecogidaDef.cargas_max_vehic[(int)RecogidaDef.TiposCarga.Otra, TipoVehic].n)
            {
                if ((RecogidaDef.cargas_max_vehic[(int)RecogidaDef.TiposCarga.Otra, TipoVehic].offset != null) && (TipoFrac < (int)RecogidaDef.TiposFracción.N))
                    off = RecogidaDef.cargas_max_vehic[(int)RecogidaDef.TiposCarga.Otra, TipoVehic].offset[TipoCapac, TipoFrac];
                else if ((RecogidaDef.cargas_max_vehic[(int)RecogidaDef.TiposCarga.Otra, TipoVehic].offset != null) && (TipoFrac >= (int)RecogidaDef.TiposFracción.N))
                    off = RecogidaDef.cargas_max_vehic[(int)RecogidaDef.TiposCarga.Otra, TipoVehic].offset[TipoCapac, (int)RecogidaDef.TiposFracción.Otra];
                else
                    off = 0;
                if (TipoFrac < (int)RecogidaDef.TiposFracción.N)
                    kgmax = RecogidaDef.cargas_max_vehic[(int)RecogidaDef.TiposCarga.Otra, TipoVehic].vol[TipoCapac] * RecogidaDef.dens_frac_cami[TipoFrac] + off;
                else
                    kgmax = RecogidaDef.cargas_max_vehic[(int)RecogidaDef.TiposCarga.Otra, TipoVehic].vol[TipoCapac] * RecogidaDef.dens_frac_cami[(int)RecogidaDef.TiposFracción.Otra] + off;
                TextKgCapac = kgmax.ToString();
            }
        }
        /**
         * Realiza los cambios en los ámbitos cuando se ha seleccionado un tipo de carga
         */
        public bool ComboCargSel(int tto)
        {
            VisCombLate = Visibility.Hidden;
            if (tto < 0)
                return false;
            if (!tipos_carg_bool[tto])
            {
                return false;
            }
            try
            {
                TipoCarg=tto;
                
                if (TipoCarg == (int)RecogidaDef.TiposCarga.Lateral)
                    VisCombLate = Visibility.Visible;
                else
                    VisCombLate = Visibility.Hidden;
                if (TipoCarg >= 0 && TipoCarg < (int)RecogidaDef.TiposCarga.N - 1)
                {
                    //cuando se selecciona una carga contemplada en el listado origianl se habilita el comboBox de capacidad ya que sí habrá contemplado datos para tipos de cargas conocidos.
                    EnabComboCapacFrac = true;
                    TextTVaci = RecogidaDef.t_vaci[TipoCarg].ToString();
                    if (TipoVehic >= 0)
                    {
                        //si también se ha seleccionado tipo de vehículo, se rellena la lista de capacidades
                        rellena_capac();
                    }
                }
                else if (TipoCarg >= (int)RecogidaDef.TiposCarga.N - 1)
                {
                    //cuando se selecciona una carga no contemplada en el listado original se deshabilita el comboBox de capacidad porque no tendrá datos contemplado para ese caso
                    EnabComboCapacFrac = false;
                    TextTVaci = RecogidaDef.t_vaci[(int)RecogidaDef.TiposCarga.Otra].ToString();
                    if (TipoVehic >= 0)
                    {
                        //si también se ha seleccionado tipo de vehículo, se rellena la lista de capacidades
                        rellena_capac();
                    }
                }
            }
            catch (Exception)
            {
                HelperGlobal.ponMsg("Error al seleccionar la carga"); 
                return false;
            }
            return true;
        }
        /**
         * Realiza los cambios en los ámbitos cuando se ha seleccionado un tipo de vehículo
         */
        public void ComboVehicSel(int tto)
        {
            if (tto < 0)
                return;
            try
            {
                TipoVehic = tto;
                if (TipoVehic >= 0)
                {
                    //si también se ha seleccionado tipo de carga, se rellena la lista de capacidades
                    rellena_capac();
                }
            }
            catch (Exception)
            {
                HelperGlobal.ponMsg("Error al seleccionar el tipo de vehículo");
                return;
            }
        }
        /**
         * Realiza los cambios en los ámbitos cuando se ha seleccionado un tipo de capacidad
         */
        public void ComboCapacSel(int tto)
        {
            if (tto < 0)
                return;
            
            try
            {
                TipoCapac = tto;
                rellena_kgmax();
            }
            catch (Exception)
            {
                HelperGlobal.ponMsg("Error al seleccionar la capacidad");
                return;
            }
        }
        /**
         * Realiza los cambios en los ámbitos cuando se ha seleccionado el tipo de lateralidad
         */
        public void ComboLatSel(int tto)
        {
            if (tto < 0)
                return;
            try
            {
                TipoLate = tto;
            }
            catch (Exception)
            {
                HelperGlobal.ponMsg("Error al seleccionar el tipo de lateralidad");
                return;
            }
        }
    }
}
