using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Autodesk.AutoCAD.DatabaseServices;
using System.Collections.ObjectModel;
using GMLC01HerramientasCad.Logica;
using System.Globalization;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.ApplicationServices;

using COMUN = GMLC01HerramientasCad.Logica;

namespace GMLC01HerramientasCad.Acad
{
    public partial class ConsultaContainerCtl : UserControl, IConsultar
    {

        private bool disable;

        #region IConsultar Members

        private static ObjectId[] originalOIDs;
        private Extents3d originalExtent;


        public void Guardar(Collection<Elemento> elementos)
        {
            try
            {
                foreach (Elemento elemento in elementos)
                {
                    GuardarAtributos(elemento);
                }
            }
            catch (Exception ex)
            {
                Log.RegisterError(ex);
                throw new COMUN.ExcepcionGMLC("", ex);
            }
        }

        public void Centrar(Elemento elemento)
        {
            try
            {
                if (elemento != null)
                {
                    ObjectId[] finalOids = new ObjectId[1];
                    finalOids[0] = new ObjectId(new System.IntPtr(elemento.IdInterno));

                    //ObjectId[] finalOids = new ObjectId[1];
                    //finalOids[0] = new ObjectId((int)elemento.IdInterno);
                    ZoomToObjects(finalOids);
                }
                else
                {
                    ZoomToExtent(originalExtent);
                }
            }
            catch (Exception ex)
            {
                Log.RegisterError(ex);
                throw new COMUN.ExcepcionGMLC("", ex);
            }
        }

        public static void ZoomToObjects(ObjectId[] oIds)
        {
            try
            {
                Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
                using (Transaction trx = doc.Database.TransactionManager.StartTransaction())
                {
                    using (DocumentLock dolo = doc.LockDocument())
                    {
                        int cvId = Convert.ToInt32((Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("CVPORT")), NumberFormatInfo.CurrentInfo);
                        using (Autodesk.AutoCAD.GraphicsSystem.Manager gm = doc.GraphicsManager)
                        using (Autodesk.AutoCAD.GraphicsSystem.View vw = gm.GetGsView(cvId, true))
                        {
                            Extents3d ext = new Extents3d(new Point3d(0, 0, 0), new Point3d(0, 0, 0)); // = ent.GeometricExtents;
                            for (int i = 0; i <= oIds.GetUpperBound(0); i++)
                            {
                                Entity ent = (Entity)trx.GetObject(oIds[i], OpenMode.ForRead);
                                if (ent.GetRXClass().DxfName == "POINT")
                                {
                                    DBPoint myent = (DBPoint)ent;
                                    Point3d puto1 = new Point3d(myent.Position.X - 0.5, myent.Position.Y - 0.5, myent.Position.Z);
                                    Point3d puto2 = new Point3d(myent.Position.X + 0.5, myent.Position.Y + 0.5, myent.Position.Z);
                                    if (i == 0)
                                        ext = new Extents3d(puto1, puto2);
                                    else
                                        ext.AddExtents(new Extents3d(puto1, puto2));
                                }
                                else if (ent.GetRXClass().DxfName == "INSERT")
                                {
                                    BlockReference myent = (BlockReference)ent;
                                    Point3d puto1 = new Point3d(myent.Position.X - 0.5, myent.Position.Y - 0.5, myent.Position.Z);
                                    Point3d puto2 = new Point3d(myent.Position.X + 0.5, myent.Position.Y + 0.5, myent.Position.Z);
                                    if (i == 0)
                                        ext = new Extents3d(puto1, puto2);
                                    else
                                        ext.AddExtents(new Extents3d(puto1, puto2));
                                }
                                else if (ent.GetRXClass().DxfName == "HATCH")
                                {
                                    Hatch htch = (Hatch)ent;

                                    double xMin = double.PositiveInfinity;
                                    double yMin = double.PositiveInfinity;
                                    double xMax = double.NegativeInfinity;
                                    double yMax = double.NegativeInfinity;

                                    for (int loo = 0; loo < htch.NumberOfLoops; loo++)
                                    {
                                        for (int j = 0; j < htch.GetLoopAt(loo).Curves.Count; j++)
                                        {
                                            if (xMin > htch.GetLoopAt(loo).Curves[j].StartPoint.X) xMin = htch.GetLoopAt(loo).Curves[j].StartPoint.X;
                                            if (xMax < htch.GetLoopAt(loo).Curves[j].StartPoint.X) xMax = htch.GetLoopAt(loo).Curves[j].StartPoint.X;
                                            if (yMin > htch.GetLoopAt(loo).Curves[j].StartPoint.Y) yMin = htch.GetLoopAt(loo).Curves[j].StartPoint.Y;
                                            if (yMax < htch.GetLoopAt(loo).Curves[j].StartPoint.Y) yMax = htch.GetLoopAt(loo).Curves[j].StartPoint.Y;
                                        }
                                    }
                                    if (i == 0)
                                        ext = new Extents3d(new Point3d(xMin, yMin, 0), new Point3d(xMax, yMax, 0));
                                    else
                                        ext.AddExtents(new Extents3d(new Point3d(xMin, yMin, 0), new Point3d(xMax, yMax, 0)));
                                }
                                else
                                {
                                    Polyline3d poli = (Polyline3d)ent;
                                    double xMin = double.PositiveInfinity;
                                    double yMin = double.PositiveInfinity;
                                    double xMax = double.NegativeInfinity;
                                    double yMax = double.NegativeInfinity;

                                    // Use foreach to get each contained vertex
                                    foreach (ObjectId vId in poli)
                                    {
                                        PolylineVertex3d v3d = (PolylineVertex3d)vId.GetObject(OpenMode.ForRead);
                                        if (xMin > v3d.Position.X) xMin = v3d.Position.X;
                                        if (xMax < v3d.Position.X) xMax = v3d.Position.X;
                                        if (yMin > v3d.Position.Y) yMin = v3d.Position.Y;
                                        if (yMax < v3d.Position.Y) yMax = v3d.Position.Y;
                                    }

                                    if (i == 0)
                                        ext = new Extents3d(new Point3d(xMin, yMin, 0), new Point3d(xMax, yMax, 0));
                                    else
                                        ext.AddExtents(new Extents3d(new Point3d(xMin, yMin, 0), new Point3d(xMax, yMax, 0)));
                                }
                            }

                            vw.ZoomExtents(ext.MinPoint, ext.MaxPoint);
                            // Se aleja un poco el zoom del objeto.
                            if (oIds.GetUpperBound(0) > 0)
                            {
                                //vw.Zoom(0.8);
                            }
                            else
                            {
                                Entity ent = (Entity)trx.GetObject(oIds[0], OpenMode.ForRead);
                                if (ent.GetRXClass().DxfName == "POINT" || ent.GetRXClass().DxfName == "INSERT")
                                {
                                    // En el caso de entodades puntuales el zoom será más alejado.
                                    vw.Zoom(0.05);
                                }
                                else
                                {
                                    vw.Zoom(0.8);
                                }
                            }

                            gm.SetViewportFromView(cvId, vw, true, true, false);
                        }
                        trx.Commit();
                    }
                }
            }
            catch (Exception ex)
            {
                Log.RegisterError(ex);
                throw new COMUN.ExcepcionGMLC("", ex);
            }
        }

        public static void ZoomToExtent(Extents3d extent)
        {
            try
            {
                Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
                using (Transaction trx = doc.Database.TransactionManager.StartTransaction())
                {
                    using (DocumentLock dolo = doc.LockDocument())
                    {
                        int cvId = Convert.ToInt32((Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("CVPORT")), NumberFormatInfo.CurrentInfo);
                        using (Autodesk.AutoCAD.GraphicsSystem.Manager gm = doc.GraphicsManager)
                        using (Autodesk.AutoCAD.GraphicsSystem.View vw = gm.GetGsView(cvId, true))
                        {
                            vw.ZoomExtents(extent.MinPoint, extent.MaxPoint);
                            gm.SetViewportFromView(cvId, vw, true, true, false);
                        }
                        trx.Commit();
                    }
                }
            }
            catch (Exception ex)
            {
                Log.RegisterError(ex);
                throw new COMUN.ExcepcionGMLC("", ex);
            }
        }

        public void Resaltar(Elemento elemento)
        {
            try
            {
                Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
                Autodesk.AutoCAD.ApplicationServices.TransactionManager tm = doc.TransactionManager;
                using (Transaction trx = doc.Database.TransactionManager.StartTransaction())
                {
                    using (DocumentLock dolo = doc.LockDocument())
                    {
                        ObjectId[] finalOids;
                        if (elemento != null)
                        {
                            //finalOids = new ObjectId[1];
                            //finalOids[0] = new ObjectId((int)elemento.IdInterno);
                            finalOids = new ObjectId[1];
                            finalOids[0] = new ObjectId(new System.IntPtr(elemento.IdInterno));
                        }
                        else
                        {
                            finalOids = new ObjectId[0];
                        }
                        disable = true; //Se deshabilita la actualización del control.
                        doc.Editor.SetImpliedSelection(finalOids);
                        tm.QueueForGraphicsFlush();
                        tm.FlushGraphics();
                        doc.Editor.UpdateScreen();
                        trx.Commit();
                        disable = false; //Se rehabilita la actualización del control.
                    }
                }
            }
            catch (Exception ex)
            {
                Log.RegisterError(ex);
                throw new COMUN.ExcepcionGMLC("", ex);
            }
        }
        #endregion

        private static void GuardarAtributos(Elemento elemento)
        {
            ObjectId oId = new ObjectId(new System.IntPtr(elemento.IdInterno));

            // REVISAR LA CAPA DEL OBJETO
            string newLayName = "";

            Entidad ent = ModComun.XSD.Entidades[elemento.CodigoEntidad];

            if (!String.IsNullOrEmpty(ent.CampoSubTipo))
            {
                if (!String.IsNullOrEmpty(elemento.Atributos[ent.CampoSubTipo].Valor))
                {
                    newLayName = ent.Codigo + "." + ent.CampoSubTipo + "." + elemento.Atributos[ent.CampoSubTipo].Valor; //GetName4DomainValue(elemento.Atributos[ent.CampoSubTipo].NombreDominio, elemento.Atributos[ent.CampoSubTipo].Valor);
                }
                else
                {
                    newLayName = ent.Codigo;
                }
            }
            else
            {
                newLayName = ent.Codigo;
            }

            if (ent.TipoGeometria == TiposGeometria.Punto)
            {
                oId = CheckEntity(elemento, newLayName, false);
            }
            else
            {
                Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
                Autodesk.AutoCAD.ApplicationServices.TransactionManager tm = doc.TransactionManager;
                using (Transaction tr = doc.TransactionManager.StartTransaction())
                {
                    using (DocumentLock docLoc = doc.LockDocument())
                    {
                        Entity enty = null;
                        enty = tr.GetObject(new ObjectId(new System.IntPtr(elemento.IdInterno)), OpenMode.ForWrite) as Entity;
                        enty.UpgradeOpen();
                        if (enty.Layer != newLayName)
                        {
                            LayerManagement.PrepareLayer(newLayName);
                            enty.Layer = newLayName;
                            tm.QueueForGraphicsFlush();
                            tm.FlushGraphics();
                            doc.Editor.UpdateScreen();
                        }
                        tr.Commit();
                    }
                }
            }

            // Por si no se pudo chequear el punto.
            if (oId.OldId == 0) return;
            elemento.IdInterno = oId.OldId;
            XData.SetXData(oId, elemento);
        }

        private static ObjectId CheckEntity(Elemento elemento, string newLayName, bool omitLayerChack)
        {
            ObjectId oId = new ObjectId(new System.IntPtr(elemento.IdInterno));
            ObjectId oldId = new ObjectId(new System.IntPtr(elemento.IdInterno));
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Autodesk.AutoCAD.ApplicationServices.TransactionManager tm = doc.TransactionManager;
            using (Transaction tr = tm.StartTransaction())
            {
                using (DocumentLock docl = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.LockDocument())
                {
                    Entidad ent = ModComun.XSD.Entidades[elemento.CodigoEntidad];
                    Entity enty = null;
                    enty = tr.GetObject(new ObjectId(new System.IntPtr(elemento.IdInterno)), OpenMode.ForWrite) as Entity;
                    enty.UpgradeOpen();
                    if (omitLayerChack || enty.Layer != newLayName)
                    {
                        // En el caso de los bloques, se eliminan y se vuelven a insertar cuando cambian de capa.
                        if (ent.TipoGeometria == TiposGeometria.Punto)
                        {
                            LayerManagement.PrepareLayer(newLayName);
                            DibujarEnts dibi = new DibujarEnts();
                            dibi.ElementoSeleccionado = elemento;
                            dibi.BlockName = newLayName;
                            double x = 0;
                            double y = 0;
                            double z = 0;
                            switch (enty.GetRXClass().DxfName)
                            {
                                case "POINT":
                                    {
                                        DBPoint punto = (DBPoint)enty;
                                        x = punto.Position.X;
                                        y = punto.Position.Y;
                                        z = punto.Position.Z;
                                        break;
                                    }
                                case "INSERT":
                                    {
                                        BlockReference bloque = (BlockReference)enty;
                                        x = bloque.Position.X;
                                        y = bloque.Position.Y;
                                        z = bloque.Position.Z;
                                        break;
                                    }
                            }
                            enty.Erase();
                            oId = dibi.InsertBlockOrPoint(x, y, z);
                        }
                        else if (ent.TipoGeometria == TiposGeometria.Linea)
                        {
                            switch (enty.GetRXClass().DxfName)
                            {
                                case "LINE":
                                    {
                                        LayerManagement.PrepareLayer(newLayName);
                                        Line linea = (Line)enty;
                                        Point3dCollection p3dCol = new Point3dCollection();
                                        p3dCol.Add(linea.StartPoint);
                                        p3dCol.Add(linea.EndPoint);
                                        oId = DibujarEnts.Insert3DPolyline(p3dCol, false);
                                        enty.Erase();
                                        break;
                                    }
                                case "LWPOLYLINE":
                                    {
                                        LayerManagement.PrepareLayer(newLayName);
                                        Polyline poli = (Polyline)enty;
                                        Point3dCollection p3dCol = new Point3dCollection();
                                        for (int i = 0; i < poli.NumberOfVertices; i++)
                                        {
                                            p3dCol.Add(new Point3d(poli.GetPoint2dAt(i).X, poli.GetPoint2dAt(i).Y, 0));
                                        }
                                        oId = DibujarEnts.Insert3DPolyline(p3dCol, false);
                                        enty.Erase();
                                        break;
                                    }
                                case "POLYLINE":
                                    {
                                        //En este caso no se hace nada.
                                        break;
                                    }
                            }
                        }
                        else
                        {
                            enty.Layer = newLayName;
                        }
                        //tm.QueueForGraphicsFlush();
                        //tm.FlushGraphics();
                        //doc.Editor.UpdateScreen();
                        tr.Commit();
                    }
                }
            }
            if (oldId.OldId.ToString(System.Globalization.CultureInfo.InvariantCulture).Equals(oId.OldId.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.OrdinalIgnoreCase))
            {
                for (int i = 0; i <= originalOIDs.GetUpperBound(0); i++)
                {
                    if (originalOIDs[i].OldId.ToString(System.Globalization.CultureInfo.InvariantCulture).Equals(oldId.OldId.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.OrdinalIgnoreCase))
                    {
                        originalOIDs[i] = oId;
                    }
                }
                elemento.IdInterno = long.Parse(oId.OldId.ToString(System.Globalization.CultureInfo.InvariantCulture), System.Globalization.CultureInfo.InvariantCulture);
            }
            return oId;
        }

        public ConsultaContainerCtl()
        {
            try
            {
                InitializeComponent();
                lbTipoEl.Text = "";
            }
            catch (Exception ex)
            {
                Log.RegisterError(ex);
                throw new COMUN.ExcepcionGMLC("", ex);
            }
        }

        private EventHandler eh;
        private void CbEnableCheckedChanged(object sender, EventArgs e)
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            if (doc == null)
            {
                cbEnable.Checked = false;
                return;
            }
            if (cbEnable.Checked)
            {
                /////////////////////ConsultaDesactivada
                //Habilitar la auto-consulta de elementos.
                this.ctlConsultar1.isEnabled = true;
                eh = new EventHandler(DocImpliedSelectionChanged);
                doc.ImpliedSelectionChanged += eh;
                //Para que se comprueben los elementos seleccionados actualmente.
                DocImpliedSelectionChanged(null, null);
            }
            else
            {
                //Deshabilitar la auto-consulta de elementos.
                this.ctlConsultar1.isEnabled = false;
                doc.ImpliedSelectionChanged -= eh;
                eh = null;
                //Limpiar el contenido del control.
                this.ctlConsultar1.Clear();
            }
        }

        void DocImpliedSelectionChanged(object sender, EventArgs e)
        {
            //No se hará nada si el control está deshabilitado o el formulario de consulta está activo.
            if (disable) return;
            Autodesk.AutoCAD.ApplicationServices.Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            // Recuperación del conjunto de selección previo.
            using (DocumentLock docLoc = doc.LockDocument())
            {
                originalOIDs = SeleccionObjetosAutoCAD.GetSelectedEntities();
                if (originalOIDs != null)
                {
                    if (originalOIDs.Length > 0 && originalOIDs.Length <= GMLC01HerramientasCad.Logica.ModComun.MaxEntidadesAutoconsulta)
                    {
                        Collection<Elemento> elementos = new Collection<Elemento>();
                        for (int i = 0; i < originalOIDs.GetLength(0); i++)
                        {
                            string entLayer;
                            Transaction tr = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction();
                            using (tr)
                            {
                                Entity ent = null;
                                ent = originalOIDs[i].GetObject(OpenMode.ForWrite) as Entity; //tr.GetObject(originalOIDs[i], OpenMode.ForWrite) as Entity;
                                if (ent == null)
                                    continue;
                                entLayer = ent.Layer;
                            }

                            string enTip = entLayer.Split('.')[0];

                            // Si no está en un nivel reconocido como entidad se desestima
                            if (!MyPlugin.modelLayers.Contains(enTip.ToUpper(CultureInfo.CurrentCulture)))
                                continue;

                            Elemento elemento = new Elemento();
                            elemento.IdInterno = originalOIDs[i].OldId;
                            elemento.CodigoEntidad = enTip; // entLayer.Split('.')[0];

                            Entidad testEnt = XData.GetXData(originalOIDs[i], elemento.CodigoEntidad);

                            // Si la entidad no tiene atributos...
                            if (testEnt != null)
                            {
                                foreach (Atributo att in testEnt.Atributos)
                                {
                                    foreach (Atributo att2 in elemento.Atributos)
                                    {
                                        if (att.Codigo == att2.Codigo)
                                        {
                                            att2.Valor = att.Valor;
                                            break;
                                        }
                                    }
                                }
                                elementos.Add(elemento);
                            }
                        }

                        //Si hay elementos que mostrar, se abre la ventana
                        if (elementos.Count > 0)
                        {
  
                            //Recuperación de la extensión inicial de la ventana.
                            Point3d center = (Point3d)Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable(@"VIEWCTR");
                            double vhsize = (double)Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable(@"VIEWSIZE");
                            Autodesk.AutoCAD.Geometry.Point2d scsize = (Autodesk.AutoCAD.Geometry.Point2d)Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable(@"SCREENSIZE");

                            Point2d screenRes = new Point2d(scsize[0], scsize[1]);
                            double wd = 0.5 * vhsize * (screenRes.X / screenRes.Y);
                            double hg = 0.5 * vhsize;

                            originalExtent = new Extents3d(new Point3d(center.X - wd, center.Y - hg, 0), new Point3d(center.X + wd, center.Y + hg, 0));

                            // Carga de la ventana de propiedades
                            this.ctlConsultar1.Initialize(this, elementos);

                            //Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.SetImpliedSelection(originalOIDs);

                            // Recuperación de la vista inicial
                            //ZoomToExtent(originalExtent);

                        }
                        else
                        {
                            this.ctlConsultar1.Clear();
                        }

                    }
                    else
                    {
                        this.ctlConsultar1.Clear();
                    }
                }
                else
                {
                    this.ctlConsultar1.Clear();
                }
            }
        }

        public void ActualizarIdiomaInterfaz()
        {
            try
            {
                this.ctlConsultar1.ActualizarIdiomaInterfaz();
                this.cbEnable.Text = COMUN.Properties.Resources.Habilitar;
            }
            catch (System.Exception ex)
            {
                Log.RegisterError(ex);
                throw new COMUN.ExcepcionGMLC("", ex);
            }
        }

        private void CtlConsultar1onCurrentElementChange(object sender, EventArgs e)
        {
            this.lbTipoEl.Text = this.ctlConsultar1.Text;
        }
    }
}
