using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Windows.Forms;

using GMLC01HerramientasCad.Logica;
using COMUN = GMLC01HerramientasCad.Logica;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System.Globalization;
using System.Runtime.Serialization;

namespace GMLC01HerramientasCad.Acad
{
    class BuscarElementos : IBuscar, IDisposable
    {
        #region IBuscar Members

        private static string myRecordName = "";
        SeleccionElementoForm frmElementos;

        public void Buscar(CriterioBusqueda criterio)
        {
            ObjectId[] oIds = SeleccionObjetosAutoCAD.GetEntitiesWithXData(myRecordName);

            if (oIds != null)
            {
                if (oIds.Length <= 0)
                {
                    MessageBox.Show(COMUN.Properties.Resources.ElDibujoNoContieneEntidadesDelTipoSeleccionado, COMUN.Properties.Resources.Inventario, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, 0);
                    return;
                }
            }
            else
            {
                MessageBox.Show(COMUN.Properties.Resources.ElDibujoNoContieneEntidadesDelTipoSeleccionado, COMUN.Properties.Resources.Inventario, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, 0);
                return;
            }

            Collection<ObjectId> reviewedOIds = new Collection<ObjectId>();

            //Collection<elemento> elementos = new Collection<elemento>();
            bool agegar = true;

            bool seleccionar = true;

            foreach (ObjectId oid in oIds)
            {
                Entidad ent = XData.GetXData(oid, myRecordName);

                // Por si no se hubiesen recuperado datos.
                if (ent == null)
                    continue;

                agegar = true;

                foreach (CriterioAtributo cricri in criterio.Criterios)
                {
                    if (cricri.Tipo != TiposCriterios.Nada) // && !String.IsNullOrEmpty(cricri.atributo.Valor))
                    {
                        // Si el atributo es numérico, se debe haber introducido un valor numérico.
                        if ((cricri.Atributo.TipoEdicion == TiposEdicion.Entero || cricri.Atributo.TipoEdicion == TiposEdicion.Doble) && !String.IsNullOrEmpty(cricri.Atributo.Valor))
                        {
                            if (!IsNumeric(cricri.Atributo.Valor))
                            {
                                // Si el valor introducido no es numérico, se cancela el proceso y se muestr un mensaje.
                                MessageBox.Show(System.String.Format(System.Globalization.CultureInfo.CurrentCulture, COMUN.Properties.Resources.ElAtributoDebeSerUnValorNumerico, cricri.Atributo.Nombre), COMUN.Properties.Resources.Inventario, MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, 0);
                                seleccionar = false;
                                break;
                            }
                        }
                        Atributo att = null;
                        foreach (Atributo at2 in ent.Atributos)
                        {
                            if (cricri.Atributo.Codigo == at2.Codigo) { att = at2;  break; }
                        }

                        if (att == null)
                            continue;

                        switch (cricri.Atributo.TipoEdicion)
                        {
                            case TiposEdicion.Texto:
                                // Cinco opciones: Es igual / No es igual / Comienza por / Termina en / Contiene
                                switch (cricri.Tipo)
                                {
                                    case TiposCriterios.EsIgualA:
                                        if (cricri.Atributo.Valor.ToLower(CultureInfo.CurrentCulture) != att.Valor.ToLower(CultureInfo.CurrentCulture)) { agegar = false; }
                                        break;
                                    case TiposCriterios.NoEsIgualA:
                                        if (cricri.Atributo.Valor.ToLower(CultureInfo.CurrentCulture) == att.Valor.ToLower(CultureInfo.CurrentCulture)) { agegar = false; }
                                        break;
                                    case TiposCriterios.EmpiezaPor:
                                        if (String.IsNullOrEmpty(cricri.Atributo.Valor) || String.IsNullOrEmpty(att.Valor))
                                        {
                                            agegar = false;
                                        }
                                        else
                                        {
                                            if (!att.Valor.ToLower(CultureInfo.CurrentCulture).StartsWith(cricri.Atributo.Valor.ToLower(CultureInfo.CurrentCulture), StringComparison.OrdinalIgnoreCase)) { agegar = false; }
                                        }
                                        break;
                                    case TiposCriterios.TerminaEn:
                                        if (String.IsNullOrEmpty(cricri.Atributo.Valor) || String.IsNullOrEmpty(att.Valor))
                                        {
                                            agegar = false;
                                        }
                                        else
                                        {
                                            if (!att.Valor.ToLower(CultureInfo.CurrentCulture).EndsWith(cricri.Atributo.Valor.ToLower(CultureInfo.CurrentCulture), StringComparison.OrdinalIgnoreCase)) { agegar = false; }
                                        }
                                        break;
                                    case TiposCriterios.Contiene:
                                        if (String.IsNullOrEmpty(cricri.Atributo.Valor) || String.IsNullOrEmpty(att.Valor))
                                        {
                                            agegar = false;
                                        }
                                        else
                                        {
                                            if (att.Valor.ToLower(CultureInfo.CurrentCulture).IndexOf(cricri.Atributo.Valor.ToLower(CultureInfo.CurrentCulture), StringComparison.OrdinalIgnoreCase) < 0) { agegar = false; }
                                        }
                                        break;
                                    default:
                                        break;
                                }
                                break;
                            case TiposEdicion.Entero:
                            case TiposEdicion.Doble:
                                // Cuatro opciones: Es igual / No es igual / Es mayor que / Es menor que
                                switch (cricri.Tipo)
                                {
                                    case TiposCriterios.EsIgualA:
                                        if (String.IsNullOrEmpty(cricri.Atributo.Valor) && !String.IsNullOrEmpty(att.Valor)) 
                                        { 
                                            agegar = false; 
                                        }
                                        else
                                        {
                                            if (PunComa(cricri.Atributo.Valor) != PunComa(att.Valor)) { agegar = false; }
                                        }
                                        break;
                                    case TiposCriterios.NoEsIgualA:
                                        if (String.IsNullOrEmpty(cricri.Atributo.Valor) && String.IsNullOrEmpty(att.Valor))
                                        {
                                            agegar = false; 
                                        }
                                        else
                                        {
                                            if (PunComa(cricri.Atributo.Valor) == PunComa(att.Valor)) { agegar = false; }
                                        }
                                        break;
                                    case TiposCriterios.EsMayorQue:
                                        if (String.IsNullOrEmpty(cricri.Atributo.Valor) || String.IsNullOrEmpty(att.Valor))
                                        {
                                            agegar = false;
                                        }
                                        else
                                        {
                                            if (PunComa(cricri.Atributo.Valor) >= PunComa(att.Valor)) { agegar = false; }
                                        }
                                        break;
                                    case TiposCriterios.EsMenorQue:
                                        if (String.IsNullOrEmpty(cricri.Atributo.Valor) || String.IsNullOrEmpty(att.Valor))
                                        {
                                            agegar = false;
                                        }
                                        else
                                        {
                                            if (PunComa(cricri.Atributo.Valor) <= PunComa(att.Valor)) { agegar = false; }
                                        }
                                        break;
                                    case TiposCriterios.EsMayorOIgualQue:
                                        if (String.IsNullOrEmpty(cricri.Atributo.Valor) || String.IsNullOrEmpty(att.Valor))
                                        {
                                            agegar = false;
                                        }
                                        else
                                        {
                                            if (PunComa(cricri.Atributo.Valor) > PunComa(att.Valor)) { agegar = false; }
                                        }
                                        break;
                                    case TiposCriterios.EsMenorOIgualQue:
                                        if (String.IsNullOrEmpty(cricri.Atributo.Valor) || String.IsNullOrEmpty(att.Valor))
                                        {
                                            agegar = false;
                                        }
                                        else
                                        {
                                            if (PunComa(cricri.Atributo.Valor) < PunComa(att.Valor)) { agegar = false; }
                                        }
                                        break;
                                    default:
                                        break;
                                }
                                break;
                            case TiposEdicion.Combo:
                                // Dos opciones: Es igual / No es igual
                                switch (cricri.Tipo)
                                {
                                    case TiposCriterios.EsIgualA:
                                        if (cricri.Atributo.Valor.ToLower(CultureInfo.CurrentCulture) != att.Valor.ToLower(CultureInfo.CurrentCulture)) { agegar = false; }
                                        break;
                                    case TiposCriterios.NoEsIgualA:
                                        if (cricri.Atributo.Valor.ToLower(CultureInfo.CurrentCulture) == att.Valor.ToLower(CultureInfo.CurrentCulture)) { agegar = false; }
                                        break;
                                    default:
                                        break;
                                }
                                break;
                        }
                    }

                    if (agegar == false) break;

                }

                if (!seleccionar) break;

                if (agegar) reviewedOIds.Add(oid);

            }

            // Si hubo algún problema con los criterios, no se hará la selección.
            if (seleccionar)
            {
                Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
                Autodesk.AutoCAD.ApplicationServices.TransactionManager tm = doc.TransactionManager;
                ObjectId[] finalOids;
                using (Transaction trx = doc.Database.TransactionManager.StartTransaction())
                {
                    using (DocumentLock docLoc = doc.LockDocument())
                    {
                        if (reviewedOIds.Count > 0)
                        {
                            finalOids = new ObjectId[reviewedOIds.Count];
                            for (int i = 0; i < reviewedOIds.Count; i++)
                            {
                                finalOids[i] = reviewedOIds[i];
                            }
                        }
                        else
                        {
                            finalOids = new ObjectId[0];
                        }
                        doc.Editor.SetImpliedSelection(finalOids);
                        tm.QueueForGraphicsFlush();
                        tm.FlushGraphics();
                        doc.Editor.UpdateScreen();
                        if (reviewedOIds.Count == 0) MessageBox.Show(COMUN.Properties.Resources.NoSeEncontraronCoincidentesConLosCriteriosIndicados, COMUN.Properties.Resources.Inventario, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, 0);
                    }
                    trx.Commit();
                }
            }

        }

        private static bool IsNumeric(string expression)
        {
            bool isNum;
            double retNum;

            isNum = Double.TryParse(Convert.ToString(expression, System.Globalization.CultureInfo.CurrentCulture), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retNum);
            return isNum;
        }

        private static double PunComa(string texNumero)
        {
            double functionReturnValue = 0;
            //Esta función, partiendo de un número en string (con un separador de decimales)
            // la evalúa según la configuración y devuelve el valor como un número de tipo Double.
            if (string.IsNullOrEmpty(texNumero) | !IsNumeric(texNumero))
            {
                functionReturnValue = 0;
                return functionReturnValue;
            }

            string tempStr = null;
            if (texNumero.IndexOf(".", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                if (Double.Parse("1.1", System.Globalization.CultureInfo.CurrentCulture) > Double.Parse("1,1", System.Globalization.CultureInfo.CurrentCulture))
                {
                    tempStr = texNumero.Replace(".", ",");
                    functionReturnValue = Double.Parse(tempStr, System.Globalization.NumberFormatInfo.CurrentInfo);
                }
                else
                {
                    functionReturnValue = Double.Parse(texNumero, System.Globalization.NumberFormatInfo.CurrentInfo);
                }
            }
            else
            {
                if (Double.Parse("1.1", System.Globalization.CultureInfo.CurrentCulture) > Double.Parse("1,1", System.Globalization.CultureInfo.CurrentCulture))
                {
                    functionReturnValue = Double.Parse(texNumero, System.Globalization.NumberFormatInfo.CurrentInfo);
                }
                else
                {
                    tempStr = texNumero.Replace(",", ".");
                    functionReturnValue = Double.Parse(tempStr, System.Globalization.NumberFormatInfo.CurrentInfo);
                }
            }
            return functionReturnValue;
        }

        public void ActivaBuscarElementos()
        {
            if (ModComun.XSD == null)
                throw new GMLCBuscarElementosException(COMUN.Properties.Resources.ElFicheroXSDNoHaSidoCargado);

            if (frmElementos == null)
                frmElementos = new SeleccionElementoForm(ModComun.XSD, false);

            frmElementos.ShowDialog();

            if (frmElementos.EntidadSeleccionada != null)
            {
                //---------------------------------------------------------------------------//
                // Estas dos llamadas son únicamente para que no aparezcan Warnings en FxCop.//
                myRecordName = frmElementos.CategoriaSeleccionada.Codigo;
                myRecordName = frmElementos.Nivel;
                //---------------------------------------------------------------------------//
                myRecordName = frmElementos.EntidadSeleccionada.Codigo;

                Form frm = ModComun.ActivarBuscar(this, frmElementos.EntidadSeleccionada);
                NativeMethods.SetParent(frm.Handle, NativeMethods.FindWindow("MstnTop", null));
            }
        }


        #endregion

        #region Miembros de IDisposable

        public void Dispose()
        {
            GC.SuppressFinalize(this);
            if (this.frmElementos != null)
                this.frmElementos.Dispose();
        }

        #endregion
    }

    [Serializable]
    public class GMLCBuscarElementosException : System.Exception
    {
        public GMLCBuscarElementosException()
        {
        }

        public GMLCBuscarElementosException(string message)
            : base(message)
        {
        }

        public GMLCBuscarElementosException(string message, System.Exception innerException)
            : base(message, innerException)
        {
        }

        protected GMLCBuscarElementosException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }
    }
    
}
