using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;

using ESRI.ArcGIS.ArcMap;
using ESRI.ArcGIS.DataSourcesFile;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.GeoDatabaseUI;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.AnalysisTools;
using ESRI.ArcGIS.Geoprocessor;
using ESRI.ArcGIS.Geoprocessing;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Framework;
//using ESRI.ArcGIS.ArcMapUI;

namespace OliviaAddIn
{
    /**
     *	@file DatosGDB.cs
     *	Clase con funciones para lectura de GDB en general.
     *	Contiene definiciones y funciones necesarias para exportar los datos de GDB a SHP, y viceversa
     *	concretados con las opciones de configuración de la limpieza viaria.
     */
    public class DatosGDB
    {
        //*************************************************************************************        
        //Enums
        public enum ModsImport
        {
            ImportNo,
            ImportSec1, //capa secto
            ImportSec2, //capa secto con ambitos unidos por sector para maqueta
            ImportPlan1, //capa planif
            ImportPlan2, //capa ptos control
            ImportPlan3, //capa ruta
            ImportPlan4, //capa instalaciones  
            ImportPlan5, //capa ruta aux
            ImportPlan6,//capa planif con ámbitos unidos por sector para maqueta
        }
        //*************************************************************************************        
        //Variables      
        public string err_st = "";
        public string path_class = null;//path de la feature class que se ha elegido como datos de entrada
        public string path_import = null;//path donde se ha importado el resultado
        public string path_secto = null;//path de la feature class que contiene la sectorización que se va a emplear para planificar
        /////////////////////////////////

        public string giros = "giro";
        public string relaciones = "relacion";
        public string interseccion = "intersec";
        public string sector = "SECTOR";
        public string secuencia = "SECUENCIA";
        public string tipo_cont = "FRACCION";
        public string tipo_recog = "NOMB_TIP_R";
        public string tipo_entid = "NOM_TIPO_E";
        public string fid = "FID";
        public string[] campo_aux = { "Join_Count", "TARGET_FID", "JOIN_FID", "Join_Cou_1", "TARGET_F_1", "JOIN_FID_1", "Join_Cou_2", "TARGET_F_2" };
        public string carga_conten = "CARGA";
        public string name_export_amb = "data_";
        public string name_export_nw = "nw_";
        public string name_export_suf = "_ok";
        public string name_temp = "_tmp";
        public string name_temp1 = "_tmp1";
        public string name_temp2 = "_tmp2";
        public string name_control_out = "_Control";
        public string name_control = "_C";
        public string name_ruta_out = "_Ruta";
        public string name_ruta2_out = "_Viajes";
        public string name_ruta_aux = "_Raux";
        public string name_ruta = "_R";
        public string name_ruta2 = "_R2";
        public string name_sect = "_Sector";
        public string name_csv = "_L";
        public string name_aux = "_aux";
        public string ext_shp = ".shp";
        public string name_instal = "_I";
        public string name_inst_out = "_Instalacion";
        public string name_map = "mapa";
        public string union_espa = "Join_Count";
        public string union_id = "TARGET_FID";
        public string union_nivel = "NIVEL_LI_1";
        public string municip = "muni_";
        public string ambit = "SECTOR ";
        public string cap_calle = "CALLES";
        public string cap_sect = "Sectorizacion";
        public string municipio = "municipio"; 

        //*************************************************************************************
        //Métodos
        public DatosGDB()
        {

        }

        /**
         * Comprueba que haya una columna de sector y secuencia
         */
        public bool comp_campos_planif(string path_class)
        {
            ITable tabla = FunGDB.dame_tabla_clase(path_class);
            if (tabla == null)
                return false;

            return comp_campos_planif_(tabla);
        }
        /**
         * Comprueba que haya una columna de sector y secuencia
         */
        public bool comp_campos_planif(string path_gdb, string nomb_clas)
        {
            ITable tabla = FunGDB.dame_tabla_clase(path_gdb, nomb_clas);
            if(tabla==null)
                return false;

            return comp_campos_planif_(tabla);
        }
        /**
         * Comprueba que haya una columna de sector y secuencia
         */
        public bool comp_campos_planif_(ITable tabla)
        {
            if (tabla.FindField(sector) < 0 || tabla.FindField(secuencia) < 0)
                return false;
            return true;
        }

        /*
         * Dado un nombre de featureclass, una consulta y una geometría, interseca entre un poligono dado (geom) y una capa lineal (fc1)
         */
        public IQueryFilter dame_filt_inter(IFeatureClass fc, string consulta, IGeometry geom)
        {
            IQueryFilter filt = null;
            ISpatialFilter filtro_espacial = null;

            try
            {
                if (geom != null)
                {
                    //interseccion espacial entrew el poligono dado y la capa de ambitos o nw dependiendo de cual sea el ambito escogido en el dialogo
                    filtro_espacial = new SpatialFilterClass();
                    filtro_espacial.Geometry = geom;
                    filtro_espacial.GeometryField = fc.ShapeFieldName;
                    filtro_espacial.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                    //se incorpora filtro de atributos si se pasa como argumento. De este modo se hará la interseccion espacial sólo de aquellos elementos que cumplan el filtrado de atributos.
                    if ((consulta != null) || consulta != "")
                        filtro_espacial.WhereClause = consulta;
                    filt = (IQueryFilter)filtro_espacial;
                }
                else
                {
                    //se aplica filtro
                    filt = new QueryFilterClass();
                    filt.WhereClause = consulta;
                }

                return filt;
            }
            catch (Exception)
            {
               return null;
            }
        }

        /*
         * une las geometrías de una misma capa que cumplen la consulta de atributos indicada (filtro_clause)
         * de modo que trata los diversos polígonos como una única geometría (necesario para la intersección entre polígonos)
         * si no se hiciera así en la posterior interseccón entre polígonos sólo cogería uno de cada capa para intersecar y se perderían datos.
         * Se guarda la featureclass con las geometrías unidas
         * importación de la capa secotrizada, de modo que sólo haya una geometría por sector. 
         * Unificando todos los ámbitos que pertenecen al mismo sector.
         */
        public IGeometry une_poligonos(string ftclass, string filtro_clause)
        {
            string capa, copia = null;
            IFeatureClass fc1;
            IFeatureWorkspace ft_ws = null;
            IWorkspace ws = null;
            IQueryFilter filtro = null;
            IGeometry queryGeometry = null;
            IGeometryDef def_geom = null;
            bool mal=false;

            capa = ftclass;

            try
            {
                IWorkspaceFactory wsf = new ShapefileWorkspaceFactoryClass();
                ws = wsf.OpenFromFile(OliviaGlob.Paths.DirData, 0);
                ft_ws = (IFeatureWorkspace)ws;
            }
            catch (Exception)
            {
                err_st = "Error al recibir los datos de " + ftclass;
                return null;
            }

            try
            {
                if (filtro_clause != null)
                {
                    filtro = new QueryFilterClass();
                    filtro.WhereClause = filtro_clause;
                }

                fc1 = FunGDB.abre_ftclass(OliviaGlob.Paths.DirData, capa);
                if (fc1 == null)
                {
                    err_st = "Error al abrir la capa " + capa;
                    return null;
                }
                def_geom = FunGDB.dame_geom_coords(fc1, OliviaGlob.coorsys_in);
            }
            catch (Exception)
            {
                err_st = "Error al abrir la capa " + capa;
                return null;
            }

            try
            {
                if (fc1.ShapeType == esriGeometryType.esriGeometryPolyline)
                {
                    FunGDB.libera(fc1); 
                    copia = copia_capa(capa);
                    if (copia == null)
                    {
                        err_st = "Error al crear copia de la capa " + capa;
                        return null;
                    }

                    capa = System.IO.Path.GetFileNameWithoutExtension(copia);
                    fc1 = FunGDB.abre_ftclass(OliviaGlob.Paths.DirData, capa);
                    queryGeometry = FunGDB.une_geometria(fc1, filtro, out err_st);
                    if (queryGeometry == null)
                        mal = true;

                }
                else if (fc1.ShapeType == esriGeometryType.esriGeometryPoint)
                {
                    FunGDB.libera(fc1); 
                    capa = crea_aux_pto(ftclass, filtro, out queryGeometry);
                    if (capa == null)
                        mal = true;
                }
                else
                {
                    err_st = "El tipo de geometría de entrada no está permitido";
                    mal = true;
                }
                if (mal == true)
                {
                    err_st = "Error al convertir a geometría única. " + err_st;                    
                    return null;
                }

            }
            catch (Exception)
            {
                err_st = "Error al unir los polígonos que cumplen la consulta: " + filtro.WhereClause + ", de la capa " + ftclass;
                return null;
            }
            finally
            {
                FunGDB.libera(fc1);
            }


            if (queryGeometry.SpatialReference.FactoryCode != def_geom.SpatialReference.FactoryCode)
                queryGeometry.Project(def_geom.SpatialReference);

            return queryGeometry;
        }        

        /**
         * Recorre los ámbitos lineales del shp viendo qué longitud tienen dentro de la geometría, y si
         * es menos de un porcentaje, lo quitan
         **/
        public bool quita_amb_sobresalen(string shp_path, IGeometry geom_zon, double porc)
        {

            int[] ids = null;
            IFeature f = null;
            IFeatureClass fc = null;
            IGeometry geom_aux = null;
            ITopologicalOperator union = null;
            IPolyline poli = null;
            double longi_zon=0, longi_tot=0;
            List<int> quita = new List<int>();
            int j;

            try
            {
                ids = FunGDB.dame_ids_consulta(shp_path, ""); //consulta todos
                if (ids == null)
                   return false;      
                fc = FunGDB.abre_ftclass(shp_path);
                if (fc == null)
                    return false;      
                for (j = 0; j < ids.Length; j++)
                {
                    f = fc.GetFeature(ids[j]);
                    geom_aux = f.Shape;
                    poli = (IPolyline)geom_aux;
                    longi_tot = poli.Length;
                    union = (ITopologicalOperator)geom_zon;
                    if (geom_aux == null)
                        return false;                            
                    geom_aux = union.Intersect(geom_aux, esriGeometryDimension.esriGeometry1Dimension);//se realiza la interseccion entre ámbito (linea) y nivel (poligono)
                    poli = (IPolyline)geom_aux;
                    longi_zon = poli.Length;//se consigue la longitud de ámbito (linea) que interseca con el nivel)

                    if ((longi_zon / longi_tot) < porc)
                    {
                        //quita esa línea
                        quita.Add(ids[j]);
                    }
                    FunGDB.libera(f);
                }
                    
                
                FunGDB.libera(fc);
                FunGDB.libera(f);
                
                if (quita.Count>0)
                {
                    //borra las líneas que se han indicado
                    if (!FunGDB.quita_filas(shp_path, quita))
                        return false;
                }

                return true;
            }
            catch (Exception)
            {
                return false;
            }
            finally
            {
                FunGDB.libera(fc);
                FunGDB.libera(f);
            }
        }

        /**
         * Recorre los ámbitos lineales del shp viendo los que están en la zona de restricción
         * y los que caen dentro, los quita
         * is_lin ==true, interseca poligono con línea
         * is_lin ==false, interseca polígono con punto
         **/
        public bool quita_amb_restric(string shp_path, IGeometry geom_restr, bool is_lin)
        {

            int[] ids = null;
            IFeature f = null;
            IFeatureClass fc = null;
            IGeometry geom_aux = null;
            ITopologicalOperator union = null;
            List<int> quita = new List<int>();
            int j;
            esriGeometryDimension dim = esriGeometryDimension.esriGeometry1Dimension;

            try
            {
                ids = FunGDB.dame_ids_consulta(shp_path, ""); //consulta todos
                if (ids == null)
                    return false;
                fc = FunGDB.abre_ftclass(shp_path);
                if (fc == null)
                    return false;
                for (j = 0; j < ids.Length; j++)
                {
                    f = fc.GetFeature(ids[j]);
                    geom_aux = f.Shape;
                    union = (ITopologicalOperator)geom_restr;
                    if (geom_aux == null)
                        return false;
                    if (is_lin)
                        dim = esriGeometryDimension.esriGeometry1Dimension;//se realiza la interseccion entre ámbito (linea) y nivel (poligono)
                    else
                        dim = esriGeometryDimension.esriGeometry0Dimension;//se realiza la interseccion entre ámbito (punto) y nivel (poligono)
                    geom_aux = union.Intersect(geom_aux, dim);

                    if(!geom_aux.IsEmpty)
                    {
                        //quita esa línea
                        quita.Add(ids[j]);
                    }
                    FunGDB.libera(f);
                }


                FunGDB.libera(fc);
                FunGDB.libera(f);

                if (quita.Count > 0)
                {
                    //borra las líneas que se han indicado
                    if (!FunGDB.quita_filas(shp_path, quita))
                        return false;
                }

                return true;
            }
            catch (Exception)
            {
                return false;
            }
            finally
            {
                FunGDB.libera(fc);
                FunGDB.libera(f);
            }
        }
        
        /**
         * PARA DEBUG
         * Comprueba si hay locks, hay que llamarla antes de destruir o liberar fc, es solo para ver dónde se crean los locks
         */
        public bool check_locks(ISchemaLock sl)
        {
            int nlocks;
            ISchemaLock schemaLock;
            ISchemaLockInfo schemaLockInfo;
            IEnumSchemaLockInfo enumSchemaLockInfo;           

            //comprueba si hay locks
            schemaLockInfo = null;
            schemaLock = sl;
            schemaLock.GetCurrentSchemaLocks(out enumSchemaLockInfo);
            enumSchemaLockInfo.Reset();
            nlocks = 0;
            schemaLockInfo = enumSchemaLockInfo.Next();
            while (schemaLockInfo != null)
            {
                schemaLockInfo = enumSchemaLockInfo.Next();
                nlocks++;
            }
            if (nlocks > 0)
                return false;

            return true;
        }

        /**
         * Exportar la red navegable 
         * capa streets, intersección con geom_ambits que es donde están los ámbitos
         * (previamente se ha intersecado con zonas, niveles, etc, y ampliado para que contenga la instalación), 
         * ampliado un buffer, y quitándole la geometría de las restricciones
        */
        public bool exporta_nw(IGeometry geom_ambits, IGeometry geom_restric, bool restric, string fecha_hora, out IDatasetName shp_data_nw)
        {
            string name = "", err_str = "";
            ITopologicalOperator union = null;
            double buf = 0;
            IGeometry geom1 = null;
            string nomb_class = "";
            IQueryFilter filtro;
            IDatasetName shp_dsn = null;

            shp_data_nw = null;

            ///////////////////////////////////////////////////////////
            //prepara el shp donde va a exportar
            name = name_export_nw + fecha_hora + ext_shp;

            ///////////////////////////////////////////////////////////
            //se obtiene la geometría a intersecar con la red, que será la que contiene
            //a todos los ámbitos y la instalación, ampliada un buffer, mayor si hay
            //restricciones de circulación
            union = (ITopologicalOperator)geom_ambits;
            buf = OliviaGlob.buff_export;
            if (restric)
            {
                buf = buf * 2;
            }
            geom1 = union.Buffer(buf);

            ///////////////////////////////////////////////////////////
            //a la geometría resultante le quita las partes por donde no puede circular, 
            //que son las debidas a restricciones de circulación
            geom1 = FunGDB.diferencia_geoms(geom1, geom_restric);
            if (geom1 == null)
            {
                err_st = "Error al diferencias geometrías " + name;
                return false;
            }

            ///////////////////////////////////////////////////////////
            //crea el filtro espacial y el añadido de consulta de atributos si fuera necesario
            nomb_class = OliviaGlob.Capas.ftclass_ejes;
            IFeatureClass fc = FunGDB.abre_ftclass(OliviaGlob.Paths.PathGdbNw, nomb_class);
            filtro = dame_filt_inter(fc, null, geom1);
            if (filtro == null)
            {
                err_st = "Error al crear el filtro de exportación " + name;
                return false;
            }
            FunGDB.libera(fc);

            if (!FunGDB.exporta(OliviaGlob.Paths.PathGdbNw, nomb_class,
                OliviaGlob.Paths.DirData, name, filtro, out shp_dsn, out err_str))
            {
                err_st = err_str;
                return false;
            }

            shp_data_nw = (IDatasetName)shp_dsn;

            return true;
        }

        /*
         *  
         */
        public void inicia_coords(string dir, string nomb_class)
        {
            OliviaGlob.coorsys_in = FunGDB.dame_factory_code(dir, nomb_class);
            if (OliviaGlob.coorsys_in < 0)
                OliviaGlob.coorsys_in = OliviaGlob.coorsys;
            OliviaGlob.coorsys = OliviaGlob.coorsys_in;
        }

        //////////////////////////////////////
        //REVISAR
        
        /*
         * Abre la capa en el espacio de trabajo de ArcGIS y asigna a cada sector un color y un estilo en el pintado, según la simbología aplicada por VSM.
         * Todos los registros que tengan el mismo valor en el campo "sector" se pintarán con el mismo estilo
         * Modo = 0 para pintar según la simbología de VSM. Modo = 1 para pintar las rutas al finalizar el proceso de planificación, pintando las felchas que indican el sientido de la misma.
         */
        public bool pinta_sect_galeria(IFeatureLayer shape, int modo)
        {
            int indice1 = -1, indice2, indice = -1;
            string valor_clase, name_simbol;
            IGeoFeatureLayer geo_layer = null;
            IUniqueValueRenderer valor_unico = null;
            IDisplayTable tabla_disp = null;
            IFeatureCursor fcursor = null;
            IFeature feat = null;
            IFields campos = null;
            IStyleGallery styleGallery = null;
            
            if (!carga_capa_galeria(shape.Name, modo, out fcursor, out feat, out campos, out tabla_disp, out geo_layer, out styleGallery))
                return false;
            try
            {
                if ((shape.FeatureClass.ShapeType == esriGeometryType.esriGeometryPoint) || (shape.FeatureClass.ShapeType == esriGeometryType.esriGeometryMultipoint))
                {
                    //se pone un valor por defecto
                    predef_valunic(shape, modo, out valor_unico, campos, out indice, out indice1, out indice2);
                    while (feat != null)
                    {
                        //se identifican si son dos atributos los que hay que tener en cuenta para aplicar la simbología o sólo uno.
                        if (valor_unico.FieldCount == 1)
                            valor_clase = feat.get_Value(indice).ToString();
                        else
                        {
                            valor_clase = feat.get_Value(indice1).ToString();
                            valor_clase = valor_clase + "," + feat.get_Value(indice2).ToString();
                        }
                        //se identifica el nombre del simbolo VSM que debe ir asociado al elemento
                        name_simbol = decode_simbol(valor_clase, modo);
                        //Se analiza si el valor ha sido añadido como valor único. Si no, se añade.
                        if (!add_valunic_galeria(valor_unico, styleGallery, valor_clase, name_simbol, "Marker", modo))
                            return false;

                        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(feat);
                        feat = fcursor.NextFeature();
                    }
                }
                else if (shape.FeatureClass.ShapeType == esriGeometryType.esriGeometryPolyline)
                {
                    //se pone un valor por defecto
                    predef_valunic(shape, modo, out valor_unico, campos, out indice, out indice1, out indice2);
                    while (feat != null)
                    {
                        //se identifican los atributos que hay que tener en cuenta para aplicar la simbología o sólo uno.
                        valor_clase = feat.get_Value(indice).ToString();
                        //se identifica el nombre del simbolo VSM que debe ir asociado al elemento
                        name_simbol = decode_simbol(valor_clase, modo);
                        if (name_simbol == null)
                        {
                            err_st = string.Format("No se ha encontrado la simbología buscada para {0}", valor_clase);
                            return false;
                        }
                        //Se analiza si el valor ha sido añadido como valor único. Si no, se añade.
                        if (!add_valunic_galeria(valor_unico, styleGallery, valor_clase, name_simbol, "Line", modo))
                            return false;

                        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(feat);
                        feat = fcursor.NextFeature();
                    }
                    if (modo == 1)
                    {
                        asigna_color(valor_unico, 1, 1);
                    }
                }
                else if (shape.FeatureClass.ShapeType == esriGeometryType.esriGeometryPolygon)
                {
                    //se pone un valor por defecto
                    predef_valunic(shape, modo, out valor_unico, campos, out indice, out indice1, out indice2);
                    while (feat != null)
                    {
                        //se identifican los atributos que hay que tener en cuenta para aplicar la simbología o sólo uno.
                        valor_clase = feat.get_Value(indice1).ToString();
                        valor_clase = valor_clase + "," + feat.get_Value(indice2).ToString();
                        //se identifica el nombre del simbolo VSM que debe ir asociado al elemento
                        name_simbol = decode_simbol(valor_clase, modo);
                        //Se analiza si el valor ha sido añadido como valor único. Si no, se añade.
                        if (!add_valunic_galeria(valor_unico, styleGallery, valor_clase, name_simbol, "Fill", modo))
                            return false;

                        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(feat);
                        feat = fcursor.NextFeature();
                    }
                }
                else
                    return false;
                //Si no ha utilizado una rampa de color predefinida en un estilo, utilice "Custom".
                //De lo contrario, utilice el nombre de la rampa de color que ha seleccionado.
                actualiza_vista(valor_unico, tabla_disp, geo_layer, indice, indice1);
            }
            catch (Exception)
            {
                return false;
            }
            finally
            {
                if (feat != null)
                    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(feat);
                if (tabla_disp != null)
                    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(tabla_disp);
                if (fcursor != null)
                    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(fcursor);
                if (campos != null)
                    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(campos);
            }
            return true;
        }

        /*
        * Busca la capa en el espacio de trabajo de ArcGIS y asigna a cada sector un color y un estilo en el pintado.
        * Todos los registros que tengan el mismo valor en el campo "sector" se pintarán con el mismo estilo
         * Modo 0 para identificar los valores unicos pero no pintar la capa
         * Modo 1 para cargar la capa y pintarla en el visor cartográfico.
         * Modo 2 para cargar la capa de _Sectores de la GDB de capas importadas. Esto se hará para la maquetación.
         * Modo 3 para cargar la capa de sectores en el mapa de localizacion
         * Modo 4 para cargar la capa normal y poder editar la sectorización. Antes de la planificación.
         * Modo 5 para pintar la capa y no eliminar las ya cargada. Se hace en la recogida de residuos.
        */
        public IUniqueValueRenderer pinta_sectores(string path_gdb, string ftclass_nom, int modo)
        {
            bool encontrado = false;
            int indice, nmapas;
            string marco = null;
            IGeoFeatureLayer geo_layer = null;
            IUniqueValueRenderer valor_unico = null;
            IDisplayTable tabla_disp = null;
            IFeatureCursor fcursor = null;
            IFeatureClass f_clase = null;
            IFeatureLayer capa = null;
            IFields campos = null;
            ISpatialReferenceFactory3 spatialReferenceFactory;
            IProjectedCoordinateSystem coord_proy;
            ESRI.ArcGIS.ArcMapUI.IMxDocument mx_doc; 
            IApplication app;
            IMap map;

            try
            {
                f_clase = FunGDB.abre_ftclass(path_gdb, ftclass_nom);      //crea .sr.lock   
                if (f_clase == null)
                    return null;

                capa = new FeatureLayer();
                capa.FeatureClass = f_clase;

                if ((modo == 2) || (modo == 3))
                    capa.Name = cap_sect;
                else
                    capa.Name = ftclass_nom;

                geo_layer = (IGeoFeatureLayer)capa;
                //se recorre la tabla valor por valor para saber si ya se le ha asignado un color con su estilo de simbología úinico por valor (único por sector)
                tabla_disp = (IDisplayTable)geo_layer;
                fcursor = (IFeatureCursor)tabla_disp.SearchDisplayTable(null, false);//crea .rd.lock
                campos = fcursor.Fields;
                indice = campos.FindField(sector);

                add_valunic(fcursor, capa, out valor_unico, indice, modo);

                if (modo != 0)
                {
                    app = ArcMap.Application;
                    mx_doc = (ESRI.ArcGIS.ArcMapUI.IMxDocument)(app.Document);

                    if ((modo != 2) && (modo != 3) && (modo != 5))
                    {
                        //se eliminan las posibles capas que pueda haber abiertas, y si se ha hecho una mquetación anteriormente también se quitan las capas y los mapas
                        nmapas = mx_doc.Maps.Count;
                        for (int j = 0; j < nmapas; j++)
                        {
                            map = mx_doc.Maps.get_Item(j);
                            if ((map.Name == OliviaGlob.df_secund) || (map.Name == OliviaGlob.df_secund1))
                            {
                                map.ClearLayers();
                                //actuliza la vista del mapa para que se visualice 
                                mx_doc.UpdateContents();
                                mx_doc.ActiveView.Refresh();
                            }
                            else if (map.Name == OliviaGlob.df_princip)
                            {
                                map.ClearLayers();
                                //actuliza la vista del mapa para que se visualice 
                                mx_doc.Maps.Remove(map);
                            }
                        }
                        //se cambia de layout view (con la plantilla de maquetación) al data view (vista normal)
                        mx_doc.ActiveView = (IActiveView)mx_doc.FocusMap;
                    }

                    map = mx_doc.FocusMap;
                    spatialReferenceFactory = (ISpatialReferenceFactory3)new SpatialReferenceEnvironment();
                    coord_proy = spatialReferenceFactory.CreateProjectedCoordinateSystem(OliviaGlob.coorsys_in);//ETRS89_UTM30N
                    map.SpatialReference = (ISpatialReference)coord_proy;
                    if (mx_doc.Maps.Count > 1)
                    {
                        if (modo == 2)
                            marco = OliviaGlob.df_princip;
                        else if (modo == 3)
                            marco = OliviaGlob.df_secund;
                        for (int r = 0; r < mx_doc.Maps.Count; r++)
                        {
                            map = mx_doc.Maps.get_Item(r);
                            if (map.Name == marco)
                            {
                                encontrado = true;
                                break;
                            }
                        }
                        if ((modo == 3) && (encontrado == false))
                        {
                            marco = OliviaGlob.df_secund1;
                            for (int r = 0; r < mx_doc.Maps.Count; r++)
                            {
                                map = mx_doc.Maps.get_Item(r);
                                if (map.Name == marco)
                                    break;
                            }
                        }
                    }
                    if ((modo != 1) && (modo != 3) && (modo != 5))
                        map.ClearLayers();
                    map.AddLayer(capa);
                    actualiza_vista(valor_unico, tabla_disp, geo_layer, indice, -1);

                    if (modo == 3)
                    {
                        // hace zoom a losámbitos
                        IActiveView av = (IActiveView)map; //el mapa sigue siendo el del municipio
                        av.Extent = map.get_Layer(0).AreaOfInterest;
                        av.Refresh();

                        //Devuelve el foco al principal
                        mx_doc = (ESRI.ArcGIS.ArcMapUI.IMxDocument)(app.Document);
                        for (int r = 0; r < mx_doc.Maps.Count; r++)
                        {
                            map = mx_doc.Maps.get_Item(r);
                            if (map.Name == OliviaGlob.df_princip)
                            {
                                break;
                            }
                        }
                        mx_doc.ActiveView.FocusMap = map;
                        //actuliza la vista del mapa para que se visualice 
                        mx_doc.UpdateContents();
                        mx_doc.ActiveView.Refresh();

                    }
                }                

                return valor_unico;
            }
            catch (Exception)
            {
                return null;
            }
            finally
            {
                //libera
                FunGDB.libera(campos);
                FunGDB.libera(fcursor);
                FunGDB.libera(f_clase);
                FunGDB.libera(capa);
                FunGDB.libera(tabla_disp);
            }

        }

        /*
         * Permite conocer el nombre del simbolo a aplicar según los atributos que tiene.
         * Modo 0 para la simbologia de VSM. Modo = 1 para la simbologia de la capa de rutas(sólo para elementos lineales).
         */
        public string decode_simbol(string atributos, int modo)
        {
            string name_simb = null, basura, tip_rec;
            int ind;
            ind = atributos.IndexOf(",");

            try
            {
                if (ind > 0)
                {
                    basura = atributos.Substring(0, ind);
                    ind++;
                    tip_rec = atributos.Substring(ind);

                    for (int i = 0; i < RecogidaDef.simb_rec_vsm.Length - 3; i++)
                    {
                        if (tip_rec == RecogidaDef.simb_rec_vsm[i])
                        {
                            name_simb = RecogidaDef.nombre_simbrec_vsm[i];
                            return name_simb;
                        }
                    }
                    for (int j = 6; j < RecogidaDef.simb_rec_vsm.Length; j++)
                    {
                        if (tip_rec == RecogidaDef.simb_rec_vsm[j])
                        {
                            for (int k = 0; k < RecogidaDef.simb_tipbasura.Length; k++)
                            {
                                if (basura == RecogidaDef.simb_tipbasura[k])
                                {
                                    if (j == 6)
                                    {
                                        name_simb = RecogidaDef.nombre_simbrec_vsm[j + k];
                                        return name_simb;
                                    }
                                    else if (j == 7)
                                    {
                                        name_simb = RecogidaDef.nombre_simbrec_vsm[(j + 4) + k];
                                        return name_simb;
                                    }
                                    if (k > 2)
                                        break;
                                    else
                                    {
                                        name_simb = RecogidaDef.nombre_simbrec_vsm[(j + 8) + k];
                                        return name_simb;
                                    }
                                }
                            }
                        }
                    }
                    if ((tip_rec == "") && (basura == ""))
                    {
                        name_simb = "Soterrados";
                        return name_simb;
                    }
                    if (name_simb == null)
                    {
                        MessageBox.Show("No se encuentra el simbolo en la contenerizacion");
                    }
                }
                else
                {
                    if (modo == 0)
                    {
                        for (int i = 0; i < LimpiezaDef.simb_tto.Length; i++)
                        {
                            if (atributos == LimpiezaDef.simb_tto[i])
                            {
                                name_simb = LimpiezaDef.nombre_simblimp_vsm[i];
                                return name_simb;
                            }
                        }
                    }
                    else if (modo == 1)
                    {
                        name_simb = "Arrow Right Middle";
                        return name_simb;
                    }
                    else
                        MessageBox.Show("No se reconoce la simbologíua que hay que aplicar");
                }                

                return null;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /*
        * Une las polilineas de una misma capa que pertenecen al mismo sector.
        * Así a posteriori se podrá realizar el datadriven pages dependiendo del sector. 
         * Habrá un elemento por sector y generará tantos mapas como sectores.
        */
        public bool une_sectores(string shape, IUniqueValueRenderer valor_unico)
        {
            string filtro_clause;
            IGeometry geom = null;

            for (int i = 0; i < valor_unico.ValueCount; i++)
            {
                filtro_clause = sector + "=" + valor_unico.Value[i];
                geom = une_poligonos(shape, filtro_clause);
                if (geom == null)
                    return false;
            }
            return true;
        }
        
        /*
         * Pone por defecto un valor unico extraido del primer valor de la tabla de campos
         */
        public void predef_valunic(IFeatureLayer capa, int modo, out IUniqueValueRenderer valor_unico, IFields campos, out int indice, out int indice1, out int indice2)
        {
            string campo;
            indice = -1;
            indice1 = -1;
            indice2 = -1;

            //Crea la clasificación de valor único
            valor_unico = new UniqueValueRendererClass();

            if (capa.FeatureClass.ShapeType == esriGeometryType.esriGeometryPoint)
            {
                indice1 = campos.FindField(tipo_cont);
                indice2 = campos.FindField(tipo_recog);
                if (indice1 < 0)
                {
                    indice = campos.FindField(tipo_entid);
                    campo = tipo_entid;
                    //se establecen estas propiedades antes de realizar la clasificación por valores únicos.
                    valor_unico.FieldCount = 1;
                    valor_unico.set_Field(0, campo);
                }
                else if (indice2 > 0)
                {
                    //se establecen estas propiedades antes de realizar la clasificación por valores únicos.
                    valor_unico.FieldCount = 2;
                    valor_unico.set_Field(0, tipo_cont);
                    valor_unico.set_Field(1, tipo_recog);
                    valor_unico.FieldDelimiter = ",";
                }
                else
                {
                    predef_valunic1(valor_unico, campos);
                }
	        }
            else if (capa.FeatureClass.ShapeType == esriGeometryType.esriGeometryPolyline)
            {
                if (modo == 0)
                    campo = tipo_entid;
                else if (modo == 1)
                    campo = sector;
                else
                    campo = null;
                indice = campos.FindField(campo);
                if (indice > 0)
                {
                    //se establecen estas propiedades antes de realizar la clasificación por valores únicos.
                    valor_unico.FieldCount = 1;
                    valor_unico.set_Field(0, campo);
                }
                else
                {
                    predef_valunic1(valor_unico, campos);
                }
            }
            else if (capa.FeatureClass.ShapeType == esriGeometryType.esriGeometryPolygon)
            {
                indice1 = campos.FindField(tipo_cont);
                indice2 = campos.FindField(tipo_recog);
                if (indice2 > 0)
                {
                    //se establecen estas propiedades antes de realizar la clasificación por valores únicos.
                    valor_unico.FieldCount = 2;
                    valor_unico.set_Field(0, tipo_cont);
                    valor_unico.set_Field(1, tipo_recog);
                    valor_unico.FieldDelimiter = ",";
                }
                else
                {
                    predef_valunic1(valor_unico, campos);
                }
            }
        }

        /*
        * Pone por defecto un valor unico extraido del primer valor de la tabla de campos
        */
        public void predef_valunic1(IUniqueValueRenderer valor_unico, IFields campos)
        {
            int indice;

            indice = campos.FindField(sector);
            if (indice > 0)
            {
                //se establecen estas propiedades antes de realizar la clasificación por valores únicos.
                valor_unico.FieldCount = 1;
                valor_unico.set_Field(0, sector);
            }
            else
                MessageBox.Show("No se encuentra referencia en las tablas para elementos puntuales");
        }

        /*
         * Crea un array con los valores únicos (en el campo ambito de trabajo) que se encuentran en la capa.
         * A esos valores les aplica la simbología correspondiente que aplica VSM en sus cartografias.
         * Modo = 0 para añadir a los valores unicos la simbologia de VSM. Modo = 1 para añadir a los valores únicos la simbología referente a la capa de rutas (linea de color con flecha de sentido).
         */
        public bool add_valunic_galeria(IUniqueValueRenderer valor_unico, IStyleGallery styleGallery, string valor_clase, string name_simbol, string tipo, int modo)
        {
            bool exist_valor;
            ISymbol symbol = null;
            IEnumStyleGalleryItem enumStyleGallery = null;
            IStyleGalleryItem estilo_gal = null;

            try
            {
                if (name_simbol == null)
                {
                    err_st = "No se ha encontrado el símbolo.";
                    return false;
                }
                exist_valor = false;
                for (int i = 0; i <= valor_unico.ValueCount - 1; i++)
                {
                    if (valor_unico.get_Value(i) == valor_clase)
                    {
                        exist_valor = true;
                        break; //Si el valor se encuentra se sale del bucle.
                    }
                }
                //Si el valor (numero de sector) no se ha encontrado como valor_unico, significa que es nuevo y se añade.
                if (exist_valor == false)
                {
                    if (modo == 0)
                    {
                        if (!File.Exists(OliviaGlob.Paths.PathSimbVSM))
                        {
                            err_st = string.Format("No se encuentra la galería de estilos de VSM en: {0}.\n Modifica el path en el archivo de configuración.", OliviaGlob.Paths.PathSimbVSM);
                            return false;
                        }
                        else
                            enumStyleGallery = styleGallery.get_Items(tipo + " Symbols", OliviaGlob.Paths.PathSimbVSM, "");
                    }
                    else if (modo == 1)
                    {
                        if (!File.Exists(OliviaGlob.Paths.PathSimbESRI))
                        {
                            err_st = string.Format("No se encuentra la galería de estilos de VSM en: {0}.\n Modifica el path en el archivo de configuración.", OliviaGlob.Paths.PathSimbESRI);
                            return false;
                        }
                        else
                            enumStyleGallery = styleGallery.get_Items(tipo + " Symbols", OliviaGlob.Paths.PathSimbESRI, "");
                    }
                    else
                        err_st = "No se reconoce la simbología a aplicar";
                    enumStyleGallery.Reset();
                    estilo_gal = enumStyleGallery.Next();
                    while (estilo_gal != null)
                    {
                        if (estilo_gal.Name == name_simbol)
                        {
                            break;
                        }
                        estilo_gal = enumStyleGallery.Next();
                    }
                    if (estilo_gal != null)
                    {
                        if (modo == 0)
                        {
                            symbol = (ISymbol)estilo_gal.Item;
                            valor_unico.AddValue(valor_clase, "", symbol);
                            valor_unico.set_Label(valor_clase, estilo_gal.Name);
                            valor_unico.set_Symbol(valor_clase, symbol);
                        }
                        else if (modo == 1)
                        {
                            symbol = (ISymbol)estilo_gal.Item;
                            valor_unico.AddValue(valor_clase, "", symbol);
                            valor_unico.set_Label(valor_clase, estilo_gal.Name);
                            valor_unico.set_Symbol(valor_clase, symbol);
                        }
                        return true;
                    }
                }
                return true;

            }
            catch (Exception)
            {
                return false;
            }
        }

        /*
         * Carga la capa sobre la que se va a aplicar la simbologia extraida de la galería de estilos
         * Modo = 0 para pintar según la simbología de VSM. Modo = 1 para pintar las rutas al finalizar el proceso de planificación.
         */
        public bool carga_capa_galeria(string shape, int modo, out IFeatureCursor fcursor, out IFeature feat, out IFields campos, out IDisplayTable tabla_disp, out IGeoFeatureLayer geo_layer, out IStyleGallery styleGallery)
        {
            IFeatureLayer capa = null;
            IStyleGalleryStorage styleStorage = null;
            ESRI.ArcGIS.ArcMapUI.IMxDocument mx_doc;
            IApplication app;
            IMap map;

            if (modo == 0)
            {
                try
                {
                    styleGallery = new ESRI.ArcGIS.Framework.StyleGalleryClass();
                    styleStorage = (IStyleGalleryStorage)styleGallery;
                    if (!File.Exists(OliviaGlob.Paths.PathSimbVSM))
                    {
                        err_st = string.Format("No se encuentra la galería de estilos de VSM en: {0}.\n Modifica el path en el archivo de configuración.", OliviaGlob.Paths.PathSimbVSM);
                        fcursor = null;
                        feat = null;
                        campos = null;
                        tabla_disp = null;
                        geo_layer = null;
                        styleGallery = null;
                        return false;
                    }
                    else
                        styleStorage.TargetFile = OliviaGlob.Paths.PathSimbVSM;
                }
                catch (Exception eexx)
                {
                    MessageBox.Show(eexx.Message);
                    fcursor = null;
                    feat = null;
                    campos = null;
                    tabla_disp = null;
                    geo_layer = null;
                    styleGallery = null;
                    return false;
                } 
            }
            else if (modo == 1)
            {
                try
                {
                    styleGallery = new ESRI.ArcGIS.Framework.StyleGalleryClass();
                    styleStorage = (IStyleGalleryStorage)styleGallery;
                    if (!File.Exists(OliviaGlob.Paths.PathSimbESRI))
                    {
                        err_st = string.Format("No se encuentra la galería de estilos de ESRI en: {0}.\n Modifica el path en el archivo de configuración.", OliviaGlob.Paths.PathSimbESRI);
                        fcursor = null;
                        feat = null;
                        campos = null;
                        tabla_disp = null;
                        geo_layer = null;
                        styleGallery = null;
                        return false;
                    }
                    else
                        styleStorage.TargetFile = OliviaGlob.Paths.PathSimbESRI;
                }
                catch (Exception eexx)
                {
                    MessageBox.Show(eexx.Message);
                    fcursor = null;
                    feat = null;
                    campos = null;
                    tabla_disp = null;
                    geo_layer = null;
                    styleGallery = null;
                    return false;
                }
            }
            else
            {
                err_st = "No se reconoce la simbología que hay que aplicar";
                fcursor = null;
                feat = null;
                campos = null;
                tabla_disp = null;
                geo_layer = null;
                styleGallery = null;
                return false;
            }
            try
            {
                app = ArcMap.Application;
                mx_doc = (ESRI.ArcGIS.ArcMapUI.IMxDocument)(app.Document);
                map = mx_doc.FocusMap;
                //busca la capa de interés shape en el espacio de trabajo de ArcGIS
                for (int i = 0; i < map.LayerCount; i++)
                {
                    if (map.get_Layer(i).Name == shape)
                    {
                        capa = (IFeatureLayer)map.get_Layer(i);
                        break;
                    }
                }
                geo_layer = (IGeoFeatureLayer)capa;
                //se recorre la tabla valor por valor para saber si ya se le ha asignado un color con su estilo de simbología úinico por valor (único por sector)
                tabla_disp = (IDisplayTable)geo_layer;
                fcursor = (IFeatureCursor)tabla_disp.SearchDisplayTable(null, false);
                feat = fcursor.NextFeature();
                campos = fcursor.Fields;
            }
            catch (Exception)
            {
                err_st = "Error al aplicar simbología a los valores únicos.";
                fcursor = null;
                feat = null;
                campos = null;
                tabla_disp = null;
                geo_layer = null;
                styleGallery = null;
                return false;
            }
            return true;
        }

        /*
         * Acrtualiza la vista cuando se aplica la simbología de representación de catografía
         */
        public void actualiza_vista(IUniqueValueRenderer valor_unico, IDisplayTable tabla_disp, IGeoFeatureLayer geo_layer, int indice, int indice1)
        {
            ITable tabl = null;
            bool es_txt;
            ESRI.ArcGIS.ArcMapUI.IMxDocument mx_doc;

            try
            {
                valor_unico.ColorScheme = "Custom";
                valor_unico.UseDefaultSymbol = false;
                tabl = (ITable)tabla_disp;
                if (indice1 != -1)
                    es_txt = tabl.Fields.get_Field(indice1).Type == esriFieldType.esriFieldTypeString;
                else
                    es_txt = tabl.Fields.get_Field(indice).Type == esriFieldType.esriFieldTypeString;
                valor_unico.set_FieldType(0, es_txt);
                geo_layer.Renderer = (IFeatureRenderer)valor_unico;
                //actuliza la vista del mapa para que se visualice 
                mx_doc =(ESRI.ArcGIS.ArcMapUI.IMxDocument)(ArcMap.Application.Document);
                mx_doc.UpdateContents();
                mx_doc.ActiveView.Refresh();
            }
            catch (Exception)
            {
                MessageBox.Show("Error al actualizar la vista del mapa", "Olivia", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        public void add_valunic(IFeatureCursor fcursor, IFeatureLayer capa, out IUniqueValueRenderer valor_unico, int indice, int modo)
        {
            IFeature feat = null;
            IColor color;
            IRgbColor my_color = null;
            ISymbol sym;

            try
            {
                feat = fcursor.NextFeature();
                valor_unico = new UniqueValueRendererClass();
                //se establecen estas propiedades antes de realizar la clasificación por valores únicos.
                valor_unico.FieldCount = 1;
                valor_unico.set_Field(0, sector);

                if (capa.FeatureClass.ShapeType == esriGeometryType.esriGeometryPolyline)
                {
                    ISimpleLineSymbol simbolo = null;
                    //se aplica una estilo en la simbología
                    simbolo = new SimpleLineSymbolClass();
                    if ((modo == 1) || (modo == 5))
                        simbolo.Style = esriSimpleLineStyle.esriSLSDash;
                    else
                        simbolo.Style = esriSimpleLineStyle.esriSLSSolid;
                    simbolo.Width = 1.2;
                    valor_unico.DefaultSymbol = (ISymbol)simbolo;
                    valor_unico.UseDefaultSymbol = true;

                    while (feat != null)
                    {
                        ISimpleLineSymbol simbologia = null;
                        simbologia = new SimpleLineSymbolClass();
                        //simbologia.Style = esriSimpleLineStyle.esriSLSSolid;
                        if ((modo == 1) || (modo == 5))
                            simbologia.Style = esriSimpleLineStyle.esriSLSDash;
                        else
                            simbologia.Style = esriSimpleLineStyle.esriSLSSolid;
                        simbologia.Width = 1;

                        sym = (ISymbol)simbologia;
                        check_valunic(feat, valor_unico, sym, indice);

                        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(feat);

                        feat = fcursor.NextFeature();
                    }
                    //Una vez que se sabe el número de valor únicos que existen en la tabla, se conoce el tamaño de la rampa de colores y se pueden asignar los colores a cada valor.
                    asigna_color(valor_unico, 1, 0);
                }
                else if ((capa.FeatureClass.ShapeType == esriGeometryType.esriGeometryPoint) || (capa.FeatureClass.ShapeType == esriGeometryType.esriGeometryMultipoint))
                {
                    ISimpleMarkerSymbol simbolo = null;
                    //se aplica una estilo en la simbología
                    simbolo = new SimpleMarkerSymbolClass();
                    simbolo.Style = esriSimpleMarkerStyle.esriSMSCircle;
                    simbolo.Size = 2;
                    valor_unico.DefaultSymbol = (ISymbol)simbolo;
                    valor_unico.UseDefaultSymbol = true;

                    while (feat != null)
                    {
                        ISimpleMarkerSymbol simbologia = null;
                        simbologia = new SimpleMarkerSymbolClass();
                        simbologia.Style = esriSimpleMarkerStyle.esriSMSCircle;
                        simbologia.Size = 4;
                        simbologia.OutlineSize = 1;
                        color = new RgbColorClass();
                        my_color = new RgbColor();
                        my_color.Red = 0;
                        my_color.Blue = 0;
                        my_color.Green = 0;
                        color.RGB = my_color.RGB;
                        simbologia.OutlineColor = color;

                        sym = (ISymbol)simbologia;
                        check_valunic(feat, valor_unico, sym, indice);

                        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(feat);

                        feat = fcursor.NextFeature();
                    }
                    //Una vez que se sabe el número de valor únicos que existen en la tabla, se conoce el tamaño de la rampa de colores y se pueden asignar los colores a cada valor.
                    asigna_color(valor_unico, 0, 0);
                }
                else
                {
                    return;
                }
            }
            catch (Exception)
            {
                MessageBox.Show("Error al asignar un color a cada valor único de la capa " + capa.Name, "Olivia", MessageBoxButtons.OK, MessageBoxIcon.Error);
                valor_unico = null;
            }
        }

        /*
         * Comprueba si el valor unico existe. Si no existe se añade al array de valores unicos.
         */
        public void check_valunic(IFeature feat, IUniqueValueRenderer valor_unico, ISymbol simbologia, int indice)
        {
            string valor_clase;
            bool exist_valor;

            try
            {
                valor_clase = feat.get_Value(indice).ToString();
                //Se analiza si el valor ha sido añadido como valor único. Si no, se añade.
                exist_valor = false;
                for (int i = 0; i <= valor_unico.ValueCount - 1; i++)
                {
                    if (valor_unico.get_Value(i) == valor_clase)
                    {
                        exist_valor = true;
                        break; //Si el valor se encuentra se sale del bucle.
                    }
                }
                //Si el valor (numero de sector) no se ha encontrado como valor_unico, significa que es nuevo y se añade.
                if (exist_valor == false)
                {
                    valor_unico.AddValue(valor_clase, sector, (ISymbol)simbologia);
                    valor_unico.set_Label(valor_clase, valor_clase);
                    valor_unico.set_Symbol(valor_clase, (ISymbol)simbologia);
                }
            }
            catch (Exception)
            {
                MessageBox.Show("Error al crear el listado de valores únicos.", "Olivia", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /*
         * Una vez se tiene todo el listado de valores únicos en el campo sectores, se aplica un color aleatorio a cada valor.
         * Modo = 0 para elementos puntuales. Modo = 1 para elementos lineales
         * Tipo = 0 para pintar aleatoriamente elementos puntuales y lineales. Tipo = 1 para pintar las capas de rutas con las flechas del sentido de la misma.
         */
        public void asigna_color(IUniqueValueRenderer valor_unico, int modo, int tipo)
        {
            string atribut;
            int color_val, seed = 0;
            List<int> color_list = null;
            IColor color = null;
            Random rnd = null;
            ISimpleMarkerSymbol simb_pto = null;
            ISimpleLineSymbol simb_line = null;
            ILineSymbol simb_linea = null;

            try
            {
                color_list = new List<int>();
                color = new RgbColorClass();
                for (int j = 0; j <= valor_unico.ValueCount - 1; j++)
                {
                    atribut = valor_unico.get_Value(j);
                    if (atribut != "")
                    {
                        if (modo == 0)
                        {
                            simb_pto = (ISimpleMarkerSymbol)valor_unico.get_Symbol(atribut);
                        }
                        else if (modo == 1 && tipo == 0)
                        {
                            simb_line = (ISimpleLineSymbol)valor_unico.get_Symbol(atribut);
                        }
                        else
                            simb_linea = (ILineSymbol)valor_unico.get_Symbol(atribut);

                        //Se crea un color aleatorio pos valor_unico.
                        color_val = 0;
                        while (true)
                        {
                            rnd = new Random(seed);
                            seed++;

                            color_val = rnd.Next(0x00000000, 0x00FFFFFF);
                            if (color_list.Contains(color_val) == false)
                            {
                                color_list.Add(color_val);
                                break;
                            }
                            else
                            {
                                err_st = "El color ya ha sido asignado a otro conjunto de registros";
                            }
                        }
                        //se aplica el color aleatorio al valor_unico correspondiente.
                        color.RGB = color_val;

                        if (modo == 0)
                        {
                            simb_pto.Color = color;
                            valor_unico.set_Symbol(atribut, (ISymbol)simb_pto);
                        }
                        else if (modo == 1 && tipo == 0)
                        {
                            simb_line.Color = color;
                            valor_unico.set_Symbol(atribut, (ISymbol)simb_line);
                        }
                        else
                        {
                            simb_linea.Color = color;
                            simb_linea.Width = 1.5;
                            valor_unico.set_Symbol(atribut, (ISymbol)simb_linea);
                        }
                    }
                }
            }
            catch (Exception)
            {
                err_st = "Error al asignar colores, para el pintado, al listado de valores únicos.";
            }
        }

        /*
         * Duplica la capa que se pasa como argumento (si existe) en el mismo directorio en el que se encuentra la capa origen
         */
        public string copia_capa(string capa)
        {
            string ext, copia;

            try
            {
                string[] list = Directory.GetFiles(OliviaGlob.Paths.DirData, capa + ".*");
                ext = System.IO.Path.GetExtension(list[0]);
                copia = System.IO.Path.GetDirectoryName(list[0]) + "\\" + System.IO.Path.GetFileNameWithoutExtension(list[0]) + name_aux + ext;
                if (!File.Exists(copia))
                {
                    foreach (string f in list)
                    {
                        if (System.IO.Path.GetExtension(f) == ".lock")
                            continue;
                        ext = System.IO.Path.GetExtension(f);
                        copia = System.IO.Path.GetDirectoryName(f) + "\\" + System.IO.Path.GetFileNameWithoutExtension(f) + name_aux + ext;
                        File.Copy(f, copia, false);
                    }
                    return copia;
                }
                return copia;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /*
         * Crea un shapefile de multipuntos. Cada registro contemplará todos los puntos que cumplen el filtro.
         */
        public string crea_aux_pto(string ftclass, IQueryFilter filtro, out IGeometry geom)
        {
            string campo, nueva_capa = null;
            int numm = 0, ind, val_campo;
            IPoint[] array_pts = new IPoint[1];
            IFeature dd = null, registo_act, graba;
            IFeatureCursor featureCursor;
            IPoint point;
            IPointCollection4 colec_ptos = new MultipointClass();
            IMultipoint puntos = new MultipointClass();
            IGeometryBridge geom_brid = new GeometryEnvironmentClass();
            ISpatialReference coor = null;
            IFeatureClass fc_shape = null;
            IFields campos = null;
            IField2 camp = null;
            IGeometryDef geom_def = null;
            IFeatureWorkspace featws_shp;
            IFieldsEdit campos_edit;
            IFieldEdit2 camp_edit;
            IGeometryDefEdit geom_defedit;
            IWorkspaceEdit ws_shape;
            IWorkspace ws;
            IFeatureClass fc;
            try
            {

                IWorkspaceFactory wsf = new ShapefileWorkspaceFactoryClass();
                ws = wsf.OpenFromFile(OliviaGlob.Paths.DirData, 0);
                fc = FunGDB.abre_ftclass(OliviaGlob.Paths.DirData, ftclass);

                featureCursor = fc.Search(filtro, false);
                registo_act = graba = featureCursor.NextFeature();
                //se recorren todos los puntos que cumplen la consulta de atributos y se van recolectando en un array de puntos "pointArray"
                while (registo_act != null)
                {
                    numm++;
                    if (numm != 1)
                        System.Array.Resize(ref array_pts, numm);
                    point = new PointClass();
                    point.PutCoords(registo_act.Shape.Envelope.XMin, registo_act.Shape.Envelope.YMin);
                    point.SpatialReference = registo_act.Shape.SpatialReference;
                    coor = registo_act.Shape.SpatialReference;
                    array_pts[numm - 1] = point;

                    FunGDB.libera(registo_act);

                    registo_act = featureCursor.NextFeature();
                }
                //el array de puntos se copia a la coleccion de puntos "pointCollection"
                geom_brid.AddPoints(colec_ptos, ref array_pts);

                featws_shp = (IFeatureWorkspace)ws;
                //de la consulta que se desea realizar se extrae el campo y el valor que va a tener el registro de la nueva capa (el multipunto que cumple la consulta del filtro)
                ind = filtro.WhereClause.IndexOf("=");
                campo = filtro.WhereClause.Substring(0, ind);
                val_campo = Convert.ToInt32(filtro.WhereClause.Substring(ind + 1));
                
                //libera
                FunGDB.libera(registo_act);
                FunGDB.libera(featureCursor);
                FunGDB.libera(graba);
                FunGDB.libera(geom_brid);

                nueva_capa = fc.AliasName + name_aux;
                try
                {
                    ws_shape = (IWorkspaceEdit)featws_shp;
                    ws_shape.StartEditing(true);
                    ws_shape.StartEditOperation();

                    if (!File.Exists(ws.PathName + "\\" + nueva_capa + ext_shp))
                    {
                        //la primera vez crea el campo de sector
                        campos = new FieldsClass();
                        campos_edit = (IFieldsEdit)campos;

                        camp = new FieldClass();
                        camp_edit = (IFieldEdit2)camp;
                        camp_edit.Name_2 = "Shape";
                        camp_edit.Type_2 = esriFieldType.esriFieldTypeGeometry;

                        geom_def = new GeometryDefClass();
                        geom_defedit = (IGeometryDefEdit)geom_def;

                        geom_defedit.GeometryType_2 = esriGeometryType.esriGeometryMultipoint;

                        geom_defedit.SpatialReference_2 = coor;
                        camp_edit.GeometryDef_2 = geom_def;
                        campos_edit.AddField(camp);

                        camp = new FieldClass();
                        camp_edit = (IFieldEdit2)camp;
                        camp_edit.Name_2 = campo;
                        camp_edit.Type_2 = esriFieldType.esriFieldTypeInteger;
                        camp_edit.Length_2 = 10;
                        campos_edit.AddField(camp);

                        fc_shape = featws_shp.CreateFeatureClass(nueva_capa, campos, null, null, esriFeatureType.esriFTSimple, "Shape", "");
                    }                
                    else
                        fc_shape = featws_shp.OpenFeatureClass(nueva_capa);
                    //se crea una nuevo campo al que se le añade la geometría de la coleccion de puntos y el campo con elvalor extraido del filtro
                    dd = fc_shape.CreateFeature();
                    puntos = (IMultipoint)colec_ptos;
                    puntos.SpatialReference = coor;
                    dd.Shape = puntos;
                    ind = fc_shape.FindField(campo);
                    dd.set_Value(ind, val_campo);
                    dd.Store();

                    ws_shape.StopEditOperation();
                    ws_shape.StopEditing(true);
                }
                catch (Exception cexp2)
                {
                    MessageBox.Show(cexp2.Message);
                    nueva_capa = null;
                }
                finally
                {
                    FunGDB.libera(camp);
                    FunGDB.libera(campos);
                    FunGDB.libera(dd);
                    FunGDB.libera(fc_shape);
                    FunGDB.libera(fc);
                    //libera variables                    
                }
                geom = (IGeometry)array_pts[0];
                return nueva_capa;

            }
            catch (Exception)
            {
                err_st = "Error a la hora de generar una capa de multipuntos a partir de la capa " + ftclass;
                throw;
            }
        }  

        /*
         * Abre la capa de puntos de control y los pinta de modo que el punto inicial queda representado 
         * con un color verde, el bocadillo en naranja y el punto final será rojo.
         */
        public void ptos_control(string path_capa)
        {
            int k = 0, ptos = -1, indice1;
            bool exist_valor = false;
            string dir_shp, shapefile, marco,  label = null, valor_clase;
            IFeatureWorkspace fw;
            IWorkspaceFactory wsf;
            IFeatureClass f_clase;
            IFeatureLayer capa;
            IGeoFeatureLayer geo_layer;
            IDisplayTable tabla_disp;
            IFeatureCursor fcursor;
            IFeature feat;
            IFields campos;
            IUniqueValueRenderer valor_unico;
            IColor color;
            IRgbColor my_color;
            ISimpleMarkerSymbol simb_pto, simbolo = null;
            ESRI.ArcGIS.ArcMapUI.IMxDocument mx_doc;
            IApplication app;
            IMap map;
            IStyleGalleryStorage styleStorage = null;
            IStyleGallery styleGallery =  new ESRI.ArcGIS.Framework.StyleGalleryClass();
            styleStorage = (IStyleGalleryStorage)styleGallery;

            IEnumStyleGalleryItem enumStyleGallery = null;
            IStyleGalleryItem estilo_gal = null;

            dir_shp = System.IO.Path.GetDirectoryName(path_capa);
            shapefile = System.IO.Path.GetFileNameWithoutExtension(path_capa);
            wsf = new FileGDBWorkspaceFactoryClass();
            fw = (IFeatureWorkspace)wsf.OpenFromFile(dir_shp, 0);
            //SE AÑADE AL MARCO DE DATOS PRINCIPAL LA CAPA DE ÁMBITOS PARA CREAR LA VISTA DEL MAPA.
            f_clase = fw.OpenFeatureClass(shapefile);//crea .sr.lock

            capa = new FeatureLayer();
            capa.FeatureClass = f_clase;
            capa.Name = shapefile;
            geo_layer = (IGeoFeatureLayer)capa;
            //se recorre la tabla valor por valor para saber si ya se le ha asignado un color con su estilo de simbología úinico por valor (único por sector)
            tabla_disp = (IDisplayTable)geo_layer;
            fcursor = (IFeatureCursor)tabla_disp.SearchDisplayTable(null, false);//crea .rd.lock
            campos = fcursor.Fields;
            indice1 = campos.FindField(secuencia);

            valor_unico = new UniqueValueRendererClass();
            simb_pto = new SimpleMarkerSymbolClass();
            simbolo = new SimpleMarkerSymbolClass();
            //se establecen estas propiedades antes de realizar la clasificación por valores únicos.
            valor_unico.FieldCount = 1;
            valor_unico.set_Field(0, secuencia);
            //se aplica una estilo en la simbología
            simbolo.Style = esriSimpleMarkerStyle.esriSMSCircle;
            simbolo.Size = 2;
            valor_unico.DefaultSymbol = (ISymbol)simbolo;
            valor_unico.UseDefaultSymbol = true;
            //se identifica el numero de pountos de control que se ha programado para que,
            //en lugar de recorrer todos los elementos de la tabla, vaya directamente al punto inicial, punto bocadillo y punto final.
            if (OliviaGlob.tip_oliv == OliviaDef.GeneralDef.TiposOliv.OlivLimp)
            {
                ptos = OliviaGlob.inidlg.lim.limp.n_ptsctrl;
            }
            else if (OliviaGlob.tip_oliv == OliviaDef.GeneralDef.TiposOliv.OlivResi)
            {
                ptos = OliviaGlob.inidlg.reco.reco.n_ptsctrl;
            }
            int repe = ptos - 3;

            feat = fcursor.NextFeature();

            bool exist_symbol=false;

            if (!File.Exists(OliviaGlob.Paths.PathSimbVSM))
            {
                err_st = string.Format("No se encuentra la galería de estilos de VSM en: {0}.\n Modifica el path en el archivo de configuración.", OliviaGlob.Paths.PathSimbVSM);
                return;
            }
            else
            {
                exist_symbol = true;
                styleStorage.TargetFile = OliviaGlob.Paths.PathSimbVSM;
                enumStyleGallery = styleGallery.get_Items("Marker Symbols", OliviaGlob.Paths.PathSimbVSM, "");
            }

            ISymbol symbol;
            string name_simbol;

            while (feat != null)
            {
                valor_clase = feat.get_Value(indice1).ToString();
                color = new RgbColorClass();

                for (int i = 0; i <= valor_unico.ValueCount - 1; i++)
                {
                    if (valor_unico.get_Value(i) == valor_clase)
                    {
                        exist_valor = true;
                        break; //Si el valor se encuentra se sale del bucle.
                    }
                }
                //Si el valor (numero de sector) no se ha encontrado como valor_unico, significa que es nuevo y se añade.
                if (exist_valor == false)
                {
                    simb_pto = new SimpleMarkerSymbolClass();
                    symbol=null;
                    if(exist_symbol && k!=1)
                    {
                        if (k == 0)
                        {
                            name_simbol = "inicio";
                            label = "Inicio";
                        }
                        else
                        {
                            name_simbol = "final";
                            label = "Fin";
                        }

                        enumStyleGallery.Reset();
                        estilo_gal = enumStyleGallery.Next();
                        while (estilo_gal != null)
                        {
                            if (estilo_gal.Name == name_simbol)
                            {
                                break;
                            }
                            estilo_gal = enumStyleGallery.Next();
                        }
                        if (estilo_gal != null)
                        {
                            symbol = (ISymbol)estilo_gal.Item;
                        }
                        else 
                            symbol=null;
                        if(symbol!=null && k!=0)
                            k=-1;                                               
                    }
                    if (symbol == null) //o no exist symbol o k==1 o ha dado fallo lo anterior
                    {
                        simb_pto.Style = esriSimpleMarkerStyle.esriSMSCircle;
                        simb_pto.Size = 4;
                        simb_pto.OutlineSize = 1;
                        color = new RgbColorClass();
                        my_color = new RgbColor();
                        //se asigna color al punto inicial
                        if (k == 0)
                        {
                            my_color.Red = 0;
                            my_color.Blue = 0;
                            my_color.Green = 255;
                            label = "Inicio";
                        }
                        //se asigna color al punto bocadillo
                        else if (k == 1)
                        {
                            my_color.Red = 0;
                            my_color.Blue = 255;
                            my_color.Green = 0;
                            label = "Bocadillo";
                        }
                        //se asigna color al punto final
                        else
                        {
                            my_color.Red = 255;
                            my_color.Blue = 0;
                            my_color.Green = 0;
                            label = "Fin";
                            k = -1;
                        }

                        color.RGB = my_color.RGB;
                        simb_pto.Color = color;
                        symbol = (ISymbol)simb_pto;
                    }                    

                    valor_unico.AddValue(valor_clase, secuencia, symbol);
                    valor_unico.set_Label(valor_clase, label);
                    valor_unico.set_Symbol(valor_clase, symbol);
                }
                //libera
                if (feat != null)
                    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(feat);
                //k será -1 cuando haya procesado un pto final, por loque se quiere ir al siguiente registro de la tabla sin hacer saltos
                //si repe >1 quiere decir que hay más de tres ptos de control por lo que se pasarán los registros intermedios entre en pto inicial y el bocadillo
                //y entre el pto bocadillo y el pto final. Así se evita procesar innecesariamente los ptos intermedios.
                //si repe no es >1 basta con ir al siguiente registro ya que significa que tiene 3 ptos de control y siempre irán inicio.bocadillo y fin, por lo que todos los registros interesan
                
                if ((k==1) && (repe > 0))
                {
                    for (int i = 0; i < repe; i++)
                    {
                        feat = fcursor.NextFeature();
                    }
                }
                feat = fcursor.NextFeature();

                k++;
            }
            app = ArcMap.Application;
            mx_doc = (ESRI.ArcGIS.ArcMapUI.IMxDocument)(app.Document);
            map = mx_doc.FocusMap;
            if (mx_doc.Maps.Count > 1)
            {
                marco = OliviaGlob.df_princip;

                for (int r = 0; r < mx_doc.Maps.Count; r++)
                {
                    map = mx_doc.Maps.get_Item(r);
                    if (map.Name == marco)
                        break;
                }
            }
            map.AddLayer(capa);
            //Si no ha utilizado una rampa de color predefinida en un estilo, utilice "Custom".
            //De lo contrario, utilice el nombre de la rampa de color que ha seleccionado.
            actualiza_vista(valor_unico, tabla_disp, geo_layer, indice1, -1);

            //libera
            if (campos != null)
                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(campos);
            if (fcursor != null)
                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(fcursor);
            if (f_clase != null)
                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(f_clase);
            if (capa != null)
                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(capa);
        }

        /**
         * Mira a ver si existe featureclass y pregunta si se quiere sobreescribir, en su caso
         */ 
        private bool comprueba_sobreescribe(string path_gdb, string ftclass_nomb, bool fuerza_sobreescribe)
        {
            /////////////////////////////////////////
            //mira a ver si existe y se quiere sobreescribir
            IWorkspace2 ws_gdb_;
            IFeatureWorkspace fws;
            IDataset data_delete;
            bool sal_mal = true;
            DialogResult dlg_result;

            ws_gdb_ = (IWorkspace2)FunGDB.abre_ws(path_gdb);
            dlg_result = DialogResult.Cancel;

            if (ws_gdb_.get_NameExists(esriDatasetType.esriDTFeatureClass, ftclass_nomb))
            {
                if (!fuerza_sobreescribe)//si no se fuerza desde fuera, se pregunta
                {
                    dlg_result = MessageBox.Show("Ya existe una capa con el mismo nombre, ¿desea sobreescribir? " +
                                    "En caso contrario, se perderá el nuevo cálculo", "Olivia", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                }
                if (fuerza_sobreescribe || (dlg_result == DialogResult.Yes))
                {
                    fws = (IFeatureWorkspace)ws_gdb_;
                    data_delete = (IDataset)fws.OpenFeatureClass(ftclass_nomb);
                    if (data_delete.CanDelete())
                    {
                        try
                        {
                            data_delete.Delete();
                            sal_mal = false;
                        }
                        catch
                        {
                            sal_mal = true;
                            err_st = "No se puede borrar la capa a sobreescribir";
                        }
                    }
                    else
                    {
                        sal_mal = true;
                        err_st = "No se puede borrar la capa a sobreescribir";
                    }
                }
                else
                {
                    sal_mal = true;
                    err_st = "Se ha cancelado la importación";
                }
                if (sal_mal)
                {
                    //no quiere sobreescribir o ha habido error, sale
                    return false;
                }
            }
            return true;
        }

        /**
        * Importa a una geodatabase existente el shapefile indicado. Descodificando el nombre de entrada del shapafile para asignarselo
        * a un grupo de la GDB según el tratamiento y añadiendo una capa con el nobre de los ámbitos que intervienen.
        */
        public bool importa(string path_shape, string path_gdb, out string name, out string dir_shp, int modo)
        {         
            int ind;
            string tratamiento = null, ambitos = null, shapefile, prefijo;           
            IWorkspaceFactory wsfact = null, wsf_shp = null;
            IWorkspaceName wsn_shp, wsn_gdb;
            IDataset data_shp, data_gdb = null;
            IDatasetName dn_shp = null, dn_gdb = null, dname_gdb;
            IWorkspace ws_shp, ws_gdb;
            IName n_shp, n_gdb;
            IFeatureClassName fcn_shp, fcn_gdb;
            IFeatureDatasetName fdn_gdb;
            IFeatureDataConverter convertidor = null;
            IEnumInvalidObject invalido = null;
            IUniqueValueRenderer valor_unico;
            bool reco_o_limp_con_instala = true;
            bool reco_tramos = false;
            IGeometryDef geom_dest = null;
            IFeatureClass fc = null;

            int NIMPORT;
            string[] noms_shp;
            string[] noms_gdb;
            int i;

            dir_shp = ""; 
            name = null;

            ////////////////////////////////
            //limpia la vista para poder pintar los resultados
            OliviaGlob.mapa.limpia_vista();

            /////////////////////////////////////////
            dir_shp = System.IO.Path.GetDirectoryName(path_shape);
            shapefile = System.IO.Path.GetFileNameWithoutExtension(path_shape);
            ind = shapefile.IndexOf("_", 0);
            prefijo = shapefile.Substring(ind + 1, 1);
            
            //decodifica el nombre del shapefile para asignarle el correspondiente nombre en la GDB a la que se importa el shape
            if (prefijo == "T")
            {
                OliviaGlob.gdb_limp.decode_gdb(shapefile, out tratamiento, out ambitos);
            }
            else if (prefijo == "F")
            {
                OliviaGlob.gdb_reco.decode_gdb(shapefile, out tratamiento, out ambitos);
            }
            else
            {
                err_st = string.Format("Nombre del archivo a importar erróneo. No se reconoce el prefijo introducido: {0}", prefijo);
                return false;
            }

            reco_o_limp_con_instala = (prefijo == "F") || 
                ((prefijo == "T") && ((OliviaGlob.inidlg.lim.limp.coords_instala[0] != 0) && (OliviaGlob.inidlg.lim.limp.coords_instala[1] != 0)));
            reco_tramos = File.Exists(System.IO.Path.Combine(dir_shp, shapefile + name_ruta2 + ext_shp));
            /////////////////////////////////////////
            //crea el dataset si no existe
            ISpatialReferenceFactory3 spatialReferenceFactory = (ISpatialReferenceFactory3)new SpatialReferenceEnvironment();
            ISpatialReference spref = (ISpatialReference)spatialReferenceFactory.CreateProjectedCoordinateSystem(OliviaGlob.coorsys_in);
            if(! FunGDB.crea_ftdataset(path_gdb, tratamiento, spref))
            {
                err_st = "Error al crear el Dataset " + tratamiento;
                return false;
            }

            /////////////////////////////////////////
            //pregunta a ver si se quiere ese nombre u otro
            bool replace = false;
            string ambitos_aux = FunGDB.save_ftcls("Guardar Feature Class como...",OliviaGlob.inidlg.Handle.ToInt32(),
                path_gdb + "\\" + tratamiento + "\\" + ambitos, out replace);
            if(ambitos_aux!=null)
                ambitos=System.IO.Path.GetFileNameWithoutExtension(ambitos_aux);
                        
            /////////////////////////////////////////
            //todo ok, se pone a importar
            name = ambitos;
            path_import = path_gdb + "\\" + tratamiento + "\\" + ambitos;
           
            if(modo==(int)ModsImport.ImportSec1) //sectoriza
            {
                NIMPORT=2;
                noms_shp = new string[NIMPORT];
                noms_gdb = new string[NIMPORT];
                noms_shp[0]=shapefile;
                noms_gdb[0]=ambitos;
                noms_shp[1]=shapefile + name_aux;
                noms_gdb[1]=ambitos + name_sect;
            }
            else if(modo==(int)ModsImport.ImportPlan1) //planifica
            {
                if (reco_o_limp_con_instala)
                    NIMPORT = 6;
                else
                    NIMPORT=5;
                if (reco_tramos)
                    NIMPORT = 7;
                noms_shp = new string[NIMPORT];
                noms_gdb = new string[NIMPORT];
                noms_shp[0]=shapefile;
                noms_gdb[0]=ambitos;
                noms_shp[1]=shapefile + name_aux;
                noms_gdb[1]=ambitos + name_sect;
                noms_shp[2]=shapefile + name_control;
                noms_gdb[2]=ambitos + name_control_out;
                noms_shp[3]=shapefile + name_ruta;
                noms_gdb[3] = ambitos + name_ruta_out;
                noms_shp[4] = shapefile + name_ruta_aux;
                noms_gdb[4] = ambitos + name_ruta_out + name_aux;
                if (reco_o_limp_con_instala)
                {
                    noms_shp[5] = shapefile + name_instal;
                    noms_gdb[5] = ambitos + name_inst_out;
                }
                if (reco_tramos)
                {
                    noms_shp[6] = shapefile + name_ruta2;
                    noms_gdb[6] = ambitos + name_ruta2_out;
                }
            }
            else 
            {
                name=null;
                return false;
            }           

            try
            {            
                /////////////////////////////////////////
                //para la capa _sector en la que están las entidades unidas, para la maquetación
                valor_unico = pinta_sectores(dir_shp, shapefile, 0);
                if (valor_unico == null)
                    return false;
                if (!une_sectores(shapefile, valor_unico))
                    return false;
                
                wsfact = new FileGDBWorkspaceFactoryClass();
                wsf_shp = new ShapefileWorkspaceFactoryClass();
                ws_shp = wsf_shp.OpenFromFile(dir_shp, 0);
                ws_gdb = wsfact.OpenFromFile(path_gdb, 0);

                //  castea espacios de trabajo a IDataset para poder conseguir el nombre del objeto.
                data_shp = (IDataset)ws_shp;
                data_gdb = (IDataset)ws_gdb;
                n_shp = data_shp.FullName;
                n_gdb = data_gdb.FullName;
                wsn_shp = (IWorkspaceName)n_shp;

                wsn_gdb = (IWorkspaceName)n_gdb;
                
                /////////////////////////////////////////
                //se embucla para hacer todas las importaciones necesarias
                for(i=0;i<NIMPORT;i++)
                {                    
                    //mira a ver si hay que borrar para reemplazar
                    if (replace)
                    {
                        if (!FunGDB.borra_ftclass(path_gdb, noms_gdb[i]))
                        {
                            err_st = "Error al sobreescribir la capa " + noms_gdb[i];
                            break;
                        }
                    }

                    /////////////////////////////////////////////
                    //coge la geom con las coordenadas las coordenadas origen coorsys_in                   
                    fc = FunGDB.abre_ftclass(dir_shp, noms_shp[i]);
                    if (fc == null)
                        return false;
                    geom_dest = FunGDB.dame_geom_coords(fc, OliviaGlob.coorsys_in);
                    if (geom_dest == null)
                    {
                        return false;
                    }
                    FunGDB.libera(fc);
                    /////////////////////////////////////////////

                    // nombra la geodatabase y castea a IDatasetName para saber su espacio de trabajo.
                    fcn_gdb = new FeatureClassNameClass();
                    dn_gdb = (IDatasetName)fcn_gdb;

                    // nombra el shapefile y castea a IDatasetName para saber su espacio de trabajo.
                    fcn_shp = new FeatureClassNameClass();
                    dn_shp = (IDatasetName)fcn_shp;

                    dn_shp.Name = noms_shp[i];
                    dn_gdb.Name = noms_gdb[i];
                    
                    dn_shp.WorkspaceName = wsn_shp;
                    dn_gdb.WorkspaceName = wsn_gdb;

                    //create source dataset name
                    fdn_gdb = new FeatureDatasetNameClass();
                    dname_gdb = (IDatasetName)fdn_gdb;
                    dname_gdb.WorkspaceName = wsn_gdb;
                    dname_gdb.Name = tratamiento;

                    try
                    {
                        //se crea el convertidor y se aplica la conversión.
                        convertidor = new FeatureDataConverterClass();
                        invalido = convertidor.ConvertFeatureClass(fcn_shp, null, fdn_gdb, fcn_gdb, geom_dest, null, "", 1000, 0);
                    }
                    catch
                    {
                        err_st = "Errores en la importación de la capa " + noms_gdb[i];
                        break;
                    }
                    finally
                    {
                        FunGDB.libera(fcn_gdb);
                        FunGDB.libera(fcn_shp);
                    }
                    
                }
                if(i<NIMPORT)
                {
                    return false;
                }
                
            }
            catch
            {
                err_st="Errores en la importación.";
                return false;
            }
            finally
            {
                FunGDB.libera(convertidor);
                FunGDB.libera(invalido);
                FunGDB.libera(wsfact);
                FunGDB.libera(wsf_shp);
            }
            return true;
        }

        /*
        * Importa el resultado de la sectorización
        */
        public bool import_secto_ini()
        {
            //ha recibido la planificación
            IUniqueValueRenderer uvr;
            //tiene que lanzar ventana para selección de gdb
            string text_reint = "¿Desea cancelar el proceso de imporación?";
            IWorkspace ws_gdb_import_secto = FunGDB.selec_gdb("Seleccionar GDB a la que importar los resultados", OliviaGlob.inidlg.Handle.ToInt32(), text_reint);
            if (ws_gdb_import_secto != null && Directory.Exists(ws_gdb_import_secto.PathName))
            {
                try
                {
                    //temp
                    string name;
                    if (!import_secto_fin(ws_gdb_import_secto, out name))
                    {
                        err_st = "Error al importar sectorización. " + err_st;
                        return false;
                    }
                    uvr = pinta_sectores(ws_gdb_import_secto.PathName , name, 4);
                    if(uvr==null)
                    {
                        err_st = "Error al pintar sectores. " + err_st;
                        return false;
                    }                    
                }
                catch (Exception)
                {
                    return false;
                }
            }
            return true;
        }        

        /*
        * Importa el resultado de la sectorización  
        */
        public bool import_secto_fin(IWorkspace ws_gdb_import_secto, out string name)
        {
            string capa, dir_shp;
            IWorkspaceFactory shp_wsf=null;
            IWorkspace shp_ws = null;
            IDataset shp_data = null;
            IName name_shp = null;
            IFeatureClassName shp_clase = null;
            IDatasetName shp_dat_name = null;
            IWorkspaceName name_shp_ws = null;
            name = "";

            if (ws_gdb_import_secto != null)
            {
                try
                {
                    //importa
                    shp_wsf = new ShapefileWorkspaceFactoryClass();
                    shp_ws = shp_wsf.OpenFromFile(OliviaGlob.Paths.DirData, 0);
                    // castea espacios de trabajo a IDataset para poder conseguir el nombre del objeto.
                    shp_data = (IDataset)shp_ws;
                    name_shp = shp_data.FullName;
                    name_shp_ws = (IWorkspaceName)name_shp;
                    shp_clase = new FeatureClassNameClass();
                    shp_dat_name = (IDatasetName)shp_clase;
                    capa = System.IO.Path.GetFileNameWithoutExtension(OliviaGlob.Paths.PathData);
                    shp_dat_name.Name = capa + ext_shp;
                    shp_dat_name.WorkspaceName = name_shp_ws;

                    if (!importa(shp_dat_name.WorkspaceName.PathName + "\\" + shp_dat_name.Name,
                        ws_gdb_import_secto.PathName,
                        out name, out dir_shp, (int)ModsImport.ImportSec1))
                    {
                        return false;
                    }     
                }
                catch (Exception)
                {
                    return false;
                }
                finally
                {
                    FunGDB.libera(shp_dat_name);
                    FunGDB.libera(shp_clase);
                    FunGDB.libera(shp_wsf);
                }
            }
            return true;
        }

        /**
         * Comprueba lo necesario para ver si hay campos para la planificación
         */
        public bool comprueba_planif(string path_class, string nomb_class_limp)
        {
            string path = null;
            bool comp = true;
            path_secto = null;

            if (path_import != null) //si ha importado anteriormente
            {
                path_secto = path_import;
            }
            else//si no ha importado se mira si hay campo de sectorización en los datos de entrada
            {
                if (nomb_class_limp == OliviaGlob.Capas.ftclass_ejes)
                    comp = false;
                else if (path_class == null) //como tradicionalmente, hay una gdb y los nombres de las feature classes del archivo de configuración
                    comp = comp_campos_planif(OliviaGlob.Paths.PathGdbGen, nomb_class_limp);
                else
                    comp = comp_campos_planif(path_class);
                if (!comp)
                {
                    MessageBox.Show("No existen en los datos de entrada columna de SECTOR y/o SECUENCIA, necesarias para planificar",
                        "Olivia", MessageBoxButtons.OK, MessageBoxIcon.Error);                

                    path = FunGDB.selec_ftcls("Seleccione la capa de donde se quiere exportar la sectorización", 
                        OliviaGlob.inidlg.Handle.ToInt32(), path);
                    if (path != null)
                    {
                        comp = comp_campos_planif(path);
                        if (!comp)
                        {
                            err_st = "No se ha seleccionado una capa con columna de SECTOR y/o SECUENCIA, necesarias para planificar";
                            return false;
                        }
                        path_secto = path;
                    }
                    else
                    {
                        err_st = "No se ha seleccionado una capa con columna de SECTOR y/o SECUENCIA, necesarias para planificar";
                        return false;
                    }
                }
            }
            return true;
        }

        /**
         * Realiza el join de la capa exportada sin sectorización con las columnas de sector y secuencia
         */ 
        public bool join_secto(ITable targetTable_shp, String key_oid, ITable joinTable_secto, String foreignKey_secto,
             IWorkspace outputWorkspace_shp, String outputName_shp)            
        {
            IMemoryRelationshipClassFactory mrClassFactory = null;
            IRelationshipClass relClass = null;
            IRelQueryTableFactory rqtFactory = null;
            ITable relQueryTable = null;
            IDataset inuptDataset = null;
            IDatasetName inputDatasetName = null;
            IExportOperation exportOperation = null;
            IDataset wsDataset = null;
            IFeatureClassName outputFClassName = null;
            IDatasetName outputDatasetName = null;


            try
            {
                esriRelCardinality relCardinality = esriRelCardinality.esriRelCardinalityOneToOne;
                
                // opens the memory relationship class specified by the given properties.
                mrClassFactory = new MemoryRelationshipClassFactoryClass();
                relClass = mrClassFactory.Open(outputName_shp, 
                    (IObjectClass)joinTable_secto, foreignKey_secto,
                    (IObjectClass)targetTable_shp, key_oid, 
                    "Forwards", "Backwards", relCardinality);
                                
                //Open the RelQueryTable as a feature class.
                rqtFactory = new RelQueryTableFactory();
                relQueryTable = (ITable)rqtFactory.Open(relClass, true, null,
                    null, "SECTOR;SECUENCIA", false, true);

                int c = relQueryTable.RowCount(new QueryFilterClass());
                if (c == 0)
                {
                    err_st = "No se encuentran las entidades para exportar su sectorización en la capa indicada";
                    return false;
                }

                if (relQueryTable == null)
                    return false;

                // prepare export
                inuptDataset = (IDataset)relQueryTable;
                inputDatasetName = (IDatasetName)inuptDataset.FullName;

                // exports the given feature class to a new feature class.
                exportOperation = new ExportOperationClass();

                // 1. defaults
                wsDataset = (IDataset)outputWorkspace_shp;
                outputFClassName = new FeatureClassNameClass();
                outputDatasetName = (IDatasetName)outputFClassName;
                outputDatasetName.Name = outputName_shp;
                outputDatasetName.WorkspaceName = (IWorkspaceName)wsDataset.FullName;

                exportOperation.ExportFeatureClass(inputDatasetName, null, null, null, outputFClassName, 0);                

            }
            catch
            {
                return false;
            }
            finally
            {
                FunGDB.libera(relClass);
                FunGDB.libera(relQueryTable);
                FunGDB.libera(mrClassFactory);
                FunGDB.libera(rqtFactory);
                FunGDB.libera(exportOperation);
            }
            return true;
        }     

        /**
         * En un shp dado actualiza la columna de sectorización desde la capa contenida en path_secto
         */
        public bool actualiza_secto(string path_shp, string path_secto)
        {
            String key_oid = null;
            String foreignKey_secto = null;
            IWorkspace outputWorkspace_shp = null;
            String outputName_shp = null;

            ITable targetTable_shp = null;
            ITable joinTable_secto = null;
            String toField_secto = sector;

            try
            {
                ////////////////////////////////////////////
                //inicializa nombres
                key_oid = "OBJECTID";
                foreignKey_secto = sector;

                outputName_shp = System.IO.Path.GetFileNameWithoutExtension(path_shp) + name_aux + ext_shp;
                outputWorkspace_shp = FunGDB.abre_ws(path_shp);

                ////////////////////////////////////////////
                //abre la tabla de la secto
                joinTable_secto = FunGDB.dame_tabla_clase(path_secto);
                if (joinTable_secto == null)
                    return false;
                ////////////////////////////////////////////
                //abre la tabla del shp
                targetTable_shp = FunGDB.dame_tabla_clase(path_shp);
                if (targetTable_shp == null)
                    return false;

                if (!join_secto(targetTable_shp, key_oid, joinTable_secto, foreignKey_secto,
             outputWorkspace_shp, outputName_shp))
                    return false;

            }
            catch
            {
                return false;
            }
            finally
            {
                FunGDB.libera(joinTable_secto);
                FunGDB.libera(targetTable_shp);
                FunGDB.libera(outputWorkspace_shp);
            }

            ////////////////////////////////////////////
            //renombra
            string[] listfiles;
            string file_aux;
            try
            {
                listfiles = Directory.GetFiles(System.IO.Path.GetDirectoryName(path_shp),
                    System.IO.Path.GetFileNameWithoutExtension(path_shp) + ".*");
                foreach (string f in listfiles)
                {
                    File.Delete(f);
                }
                listfiles = Directory.GetFiles(System.IO.Path.GetDirectoryName(path_shp),
                    System.IO.Path.GetFileNameWithoutExtension(path_shp) + name_aux + ".*");
                foreach (string f in listfiles)
                {
                    file_aux = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(f), System.IO.Path.GetFileNameWithoutExtension(path_shp)) + 
                        System.IO.Path.GetExtension(f);
                    File.Move(f, file_aux);
                }
            }
            catch (Exception)
            {
                return false;
            }

            return true;
        }


        /*
         * Importa el resultado de la planificación
         */
        public bool import_planif()
        {
            int nmapas;
            string shape = null, capa, dir_shp, path_gdb;
            IWorkspaceFactory wsf = null;
            IWorkspaceFactory shp_wsf = null;
            IWorkspace shp_ws = null;
            IDataset shp_data = null;
            IName name_shp = null;
            IFeatureClassName shp_clase=null;
            IDatasetName shp_dat_name = null;
            IWorkspaceName name_shp_ws = null;
            IFeatureLayer lyr = null, layr = null, lyr_ruta = null;
            IFeatureWorkspace feat_wrk = null;
            IFeatureClass clase = null, clase_ruta = null, f_class = null;
            IFeatureClass clase2 = null;
            IFeatureLayer lyr2 = null;
            ISpatialReferenceFactory3 spatialReferenceFactory;
            IProjectedCoordinateSystem coord_proy;
            ESRI.ArcGIS.ArcMapUI.IMxDocument mx_doc;
            IApplication app;
            IMap map;

            //ha recibido la planificación
            //tiene que lanzar ventana para selección de gdb
            IWorkspace ws_gdb_import=null;
            string text_reint = "¿Desea cancelar el proceso de imporación?";
            ws_gdb_import = FunGDB.selec_gdb("Seleccionar GDB a la que importar los resultados", OliviaGlob.inidlg.Handle.ToInt32(), text_reint);

            if (ws_gdb_import != null && Directory.Exists(ws_gdb_import.PathName))
            {
                try
                {
                    path_gdb = ws_gdb_import.PathName;
                    shp_wsf = new ShapefileWorkspaceFactoryClass();
                    shp_ws = shp_wsf.OpenFromFile(OliviaGlob.Paths.DirData, 0);
                    // castea espacios de trabajo a IDataset para poder conseguir el nombre del objeto.
                    shp_data = (IDataset)shp_ws;
                    name_shp = shp_data.FullName;
                    name_shp_ws = (IWorkspaceName)name_shp;
                    shp_clase = new FeatureClassNameClass();
                    shp_dat_name = (IDatasetName)shp_clase;
                    capa = System.IO.Path.GetFileNameWithoutExtension(OliviaGlob.Paths.PathData);
                    shp_dat_name.Name = capa + ext_shp;
                    shp_dat_name.WorkspaceName = name_shp_ws;
                    //importa
                    if (!importa(shp_dat_name.WorkspaceName.PathName + "\\" + shp_dat_name.Name, path_gdb,
                        out shape, out dir_shp, (int)ModsImport.ImportPlan1))
                    {
                        err_st = "Errores en la importación";
                        return false;
                    }
                    
                    //SE AÑADE AL MARCO DE DATOS PRINCIPAL LA CAPA DE ÁMBITOS PARA CREAR LA VISTA DEL MAPA.
                    //abre el archivo importado en el espacio de trabajo, al que se le aplica una simbología determinada                    
                    app = ArcMap.Application;
                    mx_doc = (ESRI.ArcGIS.ArcMapUI.IMxDocument)(app.Document);

                    //se eliminan las posibles capas que pueda haber abiertas, y si se ha hecho una mquetación anteriormente 
                    //también se quitan las capas y los mapas
                    nmapas = mx_doc.Maps.Count;
                    for (int j = 0; j < nmapas; j++)
                    {
                        map = mx_doc.Maps.get_Item(j);
                        if ((map.Name == OliviaGlob.df_secund) || (map.Name == OliviaGlob.df_secund1))
                        {
                            map.ClearLayers();
                            //actuliza la vista del mapa para que se visualice 
                            mx_doc.UpdateContents();
                            mx_doc.ActiveView.Refresh();
                        }
                        else if (map.Name == OliviaGlob.df_princip)
                        {
                            map.ClearLayers();
                            //actuliza la vista del mapa para que se visualice 
                            mx_doc.Maps.Remove(map);
                        }
                    }

                    map = mx_doc.FocusMap;
                    spatialReferenceFactory = (ISpatialReferenceFactory3)new SpatialReferenceEnvironment();
                    coord_proy = spatialReferenceFactory.CreateProjectedCoordinateSystem(OliviaGlob.coorsys_in);
                    map.SpatialReference = (ISpatialReference)coord_proy;

                    /////////////////////////////////////////////////////
                    //una vez borradas los diferentes mapas y capas de los mismos, se añaden la capas nuevas de la importación
                    wsf = new ESRI.ArcGIS.DataSourcesGDB.FileGDBWorkspaceFactoryClass();
                    feat_wrk = (IFeatureWorkspace)wsf.OpenFromFile(path_gdb, 0);
                    
                    /////////////////////////////////////////////////////
                    //la primera capa que se añade es la de ruta, se le quita la visualización porque lo que interesa 
                    //de esa capa es poder acceder si fuera necesario a la tabla de atributos.
                    clase_ruta = feat_wrk.OpenFeatureClass(shape + name_ruta_out);
                    lyr_ruta = new ESRI.ArcGIS.Carto.FeatureLayer();
                    lyr_ruta.FeatureClass = clase_ruta;
                    lyr_ruta.Name = shape + name_ruta_out;
                    lyr_ruta.Visible = false;
                    map.AddLayer(lyr_ruta);

                    /////////////////////////////////////////////////////
                    //la siguiente es la de ruta2, se le quita la visualización porque lo que interesa 
                    //de esa capa es poder acceder si fuera necesario a la tabla de atributos.
                    if (((IWorkspace2)ws_gdb_import).get_NameExists(esriDatasetType.esriDTFeatureClass, shape + name_ruta2_out))
                    {
                        clase2 = feat_wrk.OpenFeatureClass(shape + name_ruta2_out);
                        lyr2 = new ESRI.ArcGIS.Carto.FeatureLayer();
                        lyr2.FeatureClass = clase2;
                        lyr2.Name = shape + name_ruta2_out;
                        lyr2.Visible = false;
                        map.AddLayer(lyr2);
                    }

                    /////////////////////////////////////////////////////
                    //se añade la capa de ruta_aux
                    clase = feat_wrk.OpenFeatureClass(shape + name_ruta_out + name_aux);
                    layr = new ESRI.ArcGIS.Carto.FeatureLayer();
                    layr.FeatureClass = clase;
                    layr.Name = shape + name_ruta_out + name_aux;
                    //se pinta la capa de rutas con un color por sector y las flechas que indican el sentido de la ruta.
                    map.AddLayer(layr);
                    pinta_sect_galeria(layr, 1);
                    /////////////////////////////////////////////////////
                    //se añade la capa de contenedores original con la secto
                    f_class = feat_wrk.OpenFeatureClass(shape);
                    lyr = new ESRI.ArcGIS.Carto.FeatureLayer();
                    lyr.FeatureClass = f_class;
                    lyr.Name = shape;                    
                    map.AddLayer(lyr);
                    pinta_sect_galeria(lyr, 0);

                    /*if (!pinta_sect_galeria(layr, 1))
                        return false;
                    if (!pinta_sect_galeria(lyr, 0))
                        return false;*/

                    /////////////////////////////////////////////////////
                    //se añade la capa de la ruta a las instalaciones                    
                    if (OliviaGlob.tip_oliv == OliviaDef.GeneralDef.TiposOliv.OlivLimp)//para cuando se ha planificado la limpieza viaria
                    {
                        if ((OliviaGlob.inidlg.lim.limp.coords_instala[0] != 0))
                            OliviaGlob.gdb.pinta_sectores(path_gdb, shape + name_inst_out, 5);
                    }
                    
                    else if (OliviaGlob.tip_oliv == OliviaDef.GeneralDef.TiposOliv.OlivResi)//para cuando se ha planificado la recogida de residuos
                    {
                        if ((OliviaGlob.inidlg.reco.reco.coords_instala[0] != 0))
                            OliviaGlob.gdb.pinta_sectores(path_gdb, shape + name_inst_out, 5);
                    }

                    //se abre la capa de puntos de control y se pintan por el sector al que pertenecen.
                    ptos_control(path_gdb + "\\" + shape + name_control_out);
                }
                catch (Exception)
                {
                    return false;
                }
                finally
                {
                    //libera
                    FunGDB.libera(shp_dat_name);
                    FunGDB.libera(shp_clase);
                    FunGDB.libera(shp_wsf);
                    FunGDB.libera(shp_ws);
                    FunGDB.libera(feat_wrk);
                    FunGDB.libera(clase_ruta);
                    FunGDB.libera(lyr_ruta);
                    FunGDB.libera(clase2);
                    FunGDB.libera(lyr2);
                    FunGDB.libera(f_class);
                    FunGDB.libera(lyr);
                    FunGDB.libera(clase);
                    FunGDB.libera(layr);
                }
            }
            return true;
        }

    }
}
