using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.IO;

namespace classes
{
    /// <summary>
    /// En esta clase se realizan las consultas LINQ sobre los documentos XML en los que se guardan las transcripciones
    /// </summary>
    public class Consultas
    {
        /// <summary>
        /// Consulta
        /// </summary>
        /// <param name="consulta">La secuencua a consultar.</param>
        /// <param name="espacio">El espacio entre los elementos.</param>
        /// <param name="max">Numero maximo de resultados de la consulta.</param>
        /// <param name="ruta">La ruta a los docuemntos xml.</param>
        /// <returns>
        /// Lista de string[] donde: 
        /// [0]es la intervencion anterior 
        /// [1]es la intervencion que satisface la consulta
        /// [2]es la intervencion posterior
        /// [3]es la ruta al archivo xml donde se satisface la consulta
        /// [4]es el numero de la intervencion que satisface la consulta
        /// [5]es la posicion del ultimo elemento de la secuencia a consultar
        /// </returns>
        public List<string[]> consulta(string consulta, int espacio, int max, string ruta) 
        {
            List<string[]> resultado = new List<string[]>();
            List<string[]> parametros=tipar(consulta,espacio);
            resultado = consultar(parametros, max, ruta);
            //resultado = procesar_resultado(resultado);
            return resultado;
        }
        /// <summary>
        /// Procesar_resultado genera la lista resultado de la consulta
        /// </summary>
        /// <param name="lista">La lista incompleta.</param>
        /// <returns>Lista resultado</returns>
        private List<string[]> procesar_resultado(List<string[]> lista)
        {
            List<string[]> resultado = new List<string[]>();
            int i =0;
            foreach (string[] result in lista)
            {
                XElement root = XElement.Load(result[0]);
                var Query =
                        from l in root.Element("Lineas").Elements()
                        where (string)l.Attribute("Numero") == result[1] || (string)l.Attribute("Numero") == (int.Parse(result[1]) - 1).ToString() || (string)l.Attribute("Numero") == (int.Parse(result[1]) + 1).ToString()
                        select l.Attribute("Contenido").Value;
                string[] r = new string[6];
                foreach (string q in Query) 
                {
                    r[i]=q;
                    i++;
                }
                r[3]=result[0];
                r[4]=result[1];
                r[5]=result[2];
                i = 0;
                resultado.Add(r);               
            }         
            return resultado;
        }
        /// <summary>
        /// Tipar tokeniza y define el tipo de cada elemento de la consulta
        /// </summary>
        /// <param name="consulta">la consulta.</param>
        /// <param name="espacio">el espacio de separacion permitido entre elementos.</param>
        /// <returns></returns>
        private List<string[]> tipar(string consulta, int espacio) 
        {
            List<string[]> resultado=new List<string[]>();
            string[] tokens=consulta.Split(' ');
            string[] element=new string[2];
            foreach (string token in tokens) 
            {
                if (token.StartsWith('@'.ToString())) 
                {
                    element[0]=token.Substring(1,token.Length-1);
                    element[1]="etiqueta_gramatical";
                    element[2]=espacio.ToString();
                    resultado.Add(element);
                } else if(token.StartsWith('\\'.ToString()))
                {
                    element[0] = token.Substring(1, token.Length - 1);
                    element[1] = "simbolo";
                    element[2] = espacio.ToString();
                    resultado.Add(element);
                } else 
                {
                    element[0] = token;
                    element[1] = "literal";
                    element[2] = espacio.ToString();
                    resultado.Add(element);
                }
            }
            return resultado;
        }
        /// <summary>
        /// Consultar en que transcripciones se satisface la secuencia descrita en parametros.
        /// </summary>
        /// <param name="parametros">La secuencia a encontrar en los xml.</param>
        /// <param name="max">Numero maximo de resultados de la consulta.</param>
        /// <param name="ruta">La ruta a los docuemntos xml.</param>
        /// <returns></returns>
        public List<string[]> consultar(List<string[]> parametros, int max, string ruta) 
        {
            string[] files = Directory.GetFiles(ruta, "*.xml");
            List<string[]> resultado = new List<string[]>();
            string tipo="";
            if (!(parametros.Count == 0))
            {
                foreach(string[] s in parametros)
                {
                    if(tipo=="") tipo=s[1];
                    else if(!tipo.Equals(s[1]))
                    {
                        tipo="combinada";
                        break;
                    }
                }
            }
            switch(tipo)
            {
                case "": return resultado;
                case "combinada": resultado=combinada(parametros,max,files); break;
                case "literal": resultado=literal(parametros,max,files); break;
                case "simbolo": resultado=simbolos(parametros,max,files); break;
                case "etiqueta_gramatical": resultado=categoria(parametros,max,files); break;
            }
            resultado = procesar_resultado(resultado);
            return resultado;
        }
        /// <summary>
        /// Consulta el estado de los documentos xml.
        /// </summary>
        /// <param name="files">Las rutas de los documentos xml.</param>
        /// <returns>El nombre del documento y su estado</returns>
        public SortedList<string, string> consulta_estado(string[] files) 
        {
            SortedList<string, string> resultado = new SortedList<string, string>();
            foreach (string ruta in files)
            {
               XElement root = XElement.Load(ruta);
               XAttribute estado = root.Attribute("Estado");
                
                resultado.Add(ruta, estado.ToString());
            }
            return resultado;

        }
        /// <summary>
        /// Simbolos realiza una consulta en la que solo se busca coincidencia de simbolos.
        /// </summary>
        /// <param name="parametros">La secuencia a encontrar en los xml.</param>
        /// <param name="max">Numero maximo de resultados de la consulta.</param>
        /// <param name="files">Las rutas de los documentos xml.</param>
        /// <returns>Lista con la referencia a las coincidencias</returns>
        private List<string[]> simbolos(List<string[]> parametros, int max, string[] files) {

            List<string[]> resultado = new List<string[]>();
            SortedList<string, List<string>> query = new SortedList<string, List<string>>();
            foreach (string ruta in files)
            {
                SortedList<string, List<string>> primera_query = new SortedList<string, List<string>>();
                XElement root = XElement.Load(ruta);
                primera_query = simbolos_query_inicial(root, parametros);
                if (parametros.Count == 1)
                {
                    if (primera_query.Count > 0)
                    {
                        foreach (string s in primera_query.Keys)
                        {
                            string[] lin = new string[4];
                            lin[0] = ruta;
                            lin[1] = s;
                            List<string> ele = new List<string>();
                            primera_query.TryGetValue(s, out ele);
                            foreach (string el in ele)
                            {
                                //lin[2]=posicion ultimo elemento
                                lin[2] = el;
                                resultado.Add(lin);
                                if ((!(max == 0)) && (resultado.Count == max)) break;
                            }
                            if ((!(max == 0)) && (resultado.Count == max)) break;
                        }
                    }
                }
                else
                {
                    if (!(primera_query.Count() == 0))
                    {
                        query = primera_query;
                        for (int i = 1; i < parametros.Count; i++)
                        {
                            query = simbolos_query(root, query, parametros[i]);
                        }
                    }
                    if (query.Count > 0)
                    {
                        foreach (string s in query.Keys)
                        {
                            string[] lin = new string[4];
                            lin[0] = ruta;
                            lin[1] = s;
                            List<string> ele = new List<string>();
                            query.TryGetValue(s, out ele);
                            foreach (string el in ele)
                            {
                                //lin[2]=posicion ultimo elemento
                                lin[2] = el;
                                resultado.Add(lin);
                                if ((!(max == 0)) && (resultado.Count == max)) break;
                            } if ((!(max == 0)) && (resultado.Count == max)) break;
                        }
                    }
                    if ((!(max == 0)) && (resultado.Count == max)) break;
                }
                if ((!(max == 0)) && (resultado.Count == max)) break;
                query.Clear();
            }
            return resultado;

        }
        /// <summary>
        /// Literal realiza una consulta en la que solo se busca coincidencia literal.
        /// </summary>
        /// <param name="parametros">La secuencia a encontrar en los xml.</param>
        /// <param name="max">Numero maximo de resultados de la consulta.</param>
        /// <param name="files">Las rutas de los documentos xml.</param>
        /// <returns>Lista con la referencia a las coincidencias</returns>
        private List<string[]> literal(List<string[]> parametros, int max, string[] files)
        {
            List<string[]> resultado = new List<string[]>();
            SortedList<string, List<string>> query = new SortedList<string, List<string>>();
            foreach (string ruta in files)
            {
                    SortedList<string, List<string>> primera_query = new SortedList<string, List<string>>();
                    XElement root = XElement.Load(ruta);
                    primera_query=literal_query_inicial(root,parametros);
                    if (parametros.Count == 1)
                    {
                        if (primera_query.Count > 0)
                        {
                            foreach (string s in primera_query.Keys)
                            {
                                string[] lin = new string[4];
                                lin[0] = ruta;
                                lin[1] = s;
                                List<string> ele = new List<string>();
                                primera_query.TryGetValue(s, out ele);
                                foreach (string el in ele)
                                {
                                    //lin[2]=posicion ultimo elemento
                                    lin[2] = el;
                                    resultado.Add(lin);
                                    if ((!(max == 0)) && (resultado.Count == max)) break;
                                }
                                if ((!(max == 0)) && (resultado.Count == max)) break;
                            }
                        }
                    }
                    else
                    {
                        if (!(primera_query.Count() == 0))
                        {
                            query = primera_query;
                            for (int i = 1; i < parametros.Count; i++)
                            {
                                query = literal_query(root, query, parametros[i]);
                            }
                        }
                        if (query.Count > 0)
                        {
                            foreach (string s in query.Keys)
                            {
                                string[] lin = new string[4];
                                lin[0] = ruta;
                                lin[1] = s;
                                List<string> ele = new List<string>();
                                query.TryGetValue(s, out ele);
                                foreach (string el in ele)
                                {
                                    //lin[2]=posicion ultimo elemento
                                    lin[2] = el;
                                    resultado.Add(lin);
                                    if ((!(max==0))&&(resultado.Count == max)) break;
                                }
                                if ((!(max == 0)) && (resultado.Count == max)) break;
                            }
                        } 
                        if ((!(max == 0)) && (resultado.Count == max)) break;
                    }
                    if ((!(max == 0)) && (resultado.Count == max)) break;
                    query.Clear();
            }
            return resultado;

        }
        /// <summary>
        /// Categoria realiza una consulta en la que solo se busca coincidencia de etiqueta.
        /// </summary>
        /// <param name="parametros">La secuencia a encontrar en los xml.</param>
        /// <param name="max">Numero maximo de resultados de la consulta.</param>
        /// <param name="files">Las rutas de los documentos xml.</param>
        /// <returns>Lista con la referencia a las coincidencias</returns>
        private List<string[]> categoria(List<string[]> parametros, int max, string[] files)
        {
            List<string[]> resultado = new List<string[]>();
            SortedList<string, List<string>> query = new SortedList<string, List<string>>();
            foreach (string ruta in files)
            {
                SortedList<string, List<string>> primera_query = new SortedList<string, List<string>>();
                XElement root = XElement.Load(ruta);
                primera_query = gramatical_query_inicial(root, parametros);
                if (parametros.Count == 1)
                {
                    if (primera_query.Count > 0)
                    {
                        foreach (string s in primera_query.Keys)
                        {
                            string[] lin = new string[4];
                            lin[0] = ruta;
                            lin[1] = s;
                            List<string> ele = new List<string>();
                            primera_query.TryGetValue(s, out ele);
                            foreach (string el in ele)
                            {
                                //lin[2]=posicion ultimo elemento
                                lin[2] = el;
                                resultado.Add(lin);
                                if ((!(max == 0)) && (resultado.Count == max)) break;
                            }
                            if ((!(max == 0)) && (resultado.Count == max)) break;
                        }
                    }
                }
                else
                {
                    if (!(primera_query.Count() == 0))
                    {
                        query = primera_query;
                        for (int i = 1; i < parametros.Count; i++)
                        {
                            query = gramatical_query(root, query, parametros[i]);
                        }
                    }
                    if (query.Count > 0)
                    {
                        foreach (string s in query.Keys)
                        {
                            string[] lin = new string[4];
                            lin[0] = ruta;
                            lin[1] = s;
                            List<string> ele = new List<string>();
                            query.TryGetValue(s, out ele);
                            foreach (string el in ele)
                            {
                                //lin[2]=posicion ultimo elemento
                                lin[2] = el;
                                resultado.Add(lin);
                                if ((!(max == 0)) && (resultado.Count == max)) break;
                            }
                            if ((!(max == 0)) && (resultado.Count == max)) break;
                        }
                    }
                    if ((!(max == 0)) && (resultado.Count == max)) break;
                }
                if ((!(max == 0)) && (resultado.Count == max)) break;
                query.Clear();
            }
            return resultado;
        }
        /// <summary>
        /// Combinada realiza una consulta en la que no todos los elementos de la secuencia a buscar son del mismo tipo.
        /// </summary>
        /// <param name="parametros">La secuencia a encontrar en los xml.</param>
        /// <param name="max">Numero maximo de resultados de la consulta.</param>
        /// <param name="files">Las rutas de los documentos xml.</param>
        /// <returns>Lista con la referencia a las coincidencias</returns>
        private List<string[]> combinada(List<string[]> parametros, int max, string[] files) 
        {
            List<string[]> resultado = new List<string[]>();
            SortedList<string, List<string>> query = new SortedList<string, List<string>>();
            foreach (string ruta in files)
            {
                SortedList<string, List<string>> primera_query = new SortedList<string, List<string>>();
                XElement root = XElement.Load(ruta);

                switch(parametros[0][1])
                {
                    case "literal": primera_query=literal_query_inicial(root,parametros); break;
                    case "simbolo": primera_query=simbolos_query_inicial(root,parametros); break;
                    case "etiqueta_gramatical": primera_query = gramatical_query_inicial(root, parametros); break;
                    default: return null;
                }
                if (parametros.Count == 1)
                {
                    if (primera_query.Count > 0)
                    {
                        foreach (string s in primera_query.Keys)
                        {
                            string[] lin = new string[4];
                            lin[0] = ruta;
                            lin[1] = s;
                            List<string> ele = new List<string>();
                            primera_query.TryGetValue(s, out ele);
                            foreach (string el in ele)
                            {
                                //lin[2]=posicion ultimo elemento
                                lin[2] = el;
                                resultado.Add(lin);
                                if ((!(max == 0)) && (resultado.Count == max)) break;
                            }
                            if ((!(max == 0)) && (resultado.Count == max)) break;
                        }
                    }
                }
                else
                {
                    if (!(primera_query.Count() == 0))
                    {
                        query = primera_query;
                        for (int i = 1; i < parametros.Count; i++)
                        {
                            switch (parametros[i][1])
                            {
                                case "literal": query = literal_query(root, query, parametros[i]); break;
                                case "simbolo": query = simbolos_query(root, query, parametros[i]); break;
                                case "etiqueta_gramatical": query = gramatical_query(root, query, parametros[i]); break;
                                default: return null;
                            }
                            
                        }
                    }
                    if (query.Count > 0)
                    {
                        foreach (string s in query.Keys)
                        {
                            string[] lin = new string[4];
                            lin[0] = ruta;
                            lin[1] = s;
                            List<string> ele = new List<string>();
                            query.TryGetValue(s, out ele);
                            foreach (string el in ele)
                            {
                                //lin[2]=posicion ultimo elemento
                                lin[2] = el;
                                resultado.Add(lin);
                                if ((!(max == 0)) && (resultado.Count == max)) break;
                            }
                            if ((!(max == 0)) && (resultado.Count == max)) break;
                        }
                    }
                    if ((!(max == 0)) && (resultado.Count == max)) break;
                }
                if ((!(max == 0)) && (resultado.Count == max)) break;
                query.Clear();
            }
            return resultado;
        }
        /// <summary>
        /// Literal_query comprueba si coincide el siguiente elemento de una secuencia.
        /// </summary>
        /// <param name="root">El xml a comprobar</param>
        /// <param name="lista">Lista con la referencia a las coincidencias anteriores.</param>
        /// <param name="parametros">El elemento de la secuencia a comprobar.</param>
        /// <returns>Lista con la referencia a las coincidencias</returns>
        private SortedList<string, List<string>> literal_query(XElement root, SortedList<string, List<string>> lista, string[] parametros) 
        {
            SortedList<string, List<string>> resultado = new SortedList<string, List<string>>();
            foreach (string linea in lista.Keys)
            {
                List<string> list = new List<string>();
                lista.TryGetValue(linea, out list);
                string[] auxiliar = new string[2];
                foreach (string posicion in list)
                {
                    var Query =
                        from l in root.Element("Lineas").Elements()
                        where (string)l.Attribute("Numero") == linea
                        select new
                        {
                            pos_el =
                            from ele in l.Element("Elementos").Elements()
                            where
                            (int.Parse((string)ele.Attribute("Posicion")) > int.Parse(posicion)) && ((int.Parse((string)ele.Attribute("Posicion"))) <= int.Parse(posicion) + int.Parse(parametros[2])) && (parametros[0] == (string)ele.Attribute("Aparicion"))
                            select new
                            {
                                numero = l.Attribute("Numero").Value,
                                posicion = (string)ele.Attribute("Posicion")
                            }
                        };

                    if (!(Query.Count() == 0))
                    {
                        foreach (var l in Query)
                        {
                            foreach (var pos in l.pos_el)
                            {
                                auxiliar[0] = pos.numero;
                                auxiliar[1] = pos.posicion;                           
                             
                            }
                        }
                    }
                }
                if (!(auxiliar[0]==null))
                {
                    List<string> result = new List<string>();
                    if (!(resultado.Count == 0) && resultado.ContainsKey(auxiliar[0]))
                    {
                        resultado.TryGetValue(auxiliar[0], out result);
                        result.Add(auxiliar[1]);
                        resultado.Remove(auxiliar[0]);
                        resultado.Add(auxiliar[1], result);
                    }
                    else
                    {
                        result.Add(auxiliar[1]);
                        resultado.Add(auxiliar[0], result);
                    }
                    auxiliar[0] = null; auxiliar[1] = null;
                }
            }                
            return resultado;
        }
        /// <summary>
        /// simbolos_query comprueba si coincide el siguiente elemento de una secuencia.
        /// </summary>
        /// <param name="root">El xml a comprobar</param>
        /// <param name="lista">Lista con la referencia a las coincidencias anteriores.</param>
        /// <param name="parametros">El elemento de la secuencia a comprobar.</param>
        /// <returns>Lista con la referencia a las coincidencias</returns>
        private SortedList<string, List<string>> simbolos_query(XElement root, SortedList<string, List<string>> lista, string[] parametros) 
        {
            SortedList<string, List<string>> resultado = new SortedList<string, List<string>>();
            foreach (string linea in lista.Keys)
            {
                List<string> list = new List<string>();
                lista.TryGetValue(linea, out list);
                string[] auxiliar = new string[2];
                foreach (string posicion in list)
                {
                    var Query =
                        from l in root.Element("Lineas").Elements()
                        where (string)l.Attribute("Numero") == linea
                        select new
                        {
                            pos_el =
                            from ele in l.Element("Elementos").Elements()
                            where
                            (int.Parse((string)ele.Attribute("Posicion")) > int.Parse(posicion)) && ((int.Parse((string)ele.Attribute("Posicion"))) <= int.Parse(posicion) + int.Parse(parametros[2])) && ((string)ele.Attribute("Tipo")=="Simbolo") && (((string)ele.Attribute("Etiqueta")).Contains(parametros[0]))
                            select new
                            {
                                numero = l.Attribute("Numero").Value,
                                posicion = (string)ele.Attribute("Posicion")
                            }
                        };

                    if (!(Query.Count() == 0))
                    {
                        foreach (var l in Query)
                        {
                            foreach (var pos in l.pos_el)
                            {
                                auxiliar[0] = pos.numero;
                                auxiliar[1] = pos.posicion;

                            }
                        }
                    }
                }
                if (!(auxiliar[0] == null))
                {
                    List<string> result = new List<string>();
                    if (!(resultado.Count == 0) && resultado.ContainsKey(auxiliar[0]))
                    {
                        resultado.TryGetValue(auxiliar[0], out result);
                        result.Add(auxiliar[1]);
                        resultado.Remove(auxiliar[0]);
                        resultado.Add(auxiliar[1], result);
                    }
                    else
                    {
                        result.Add(auxiliar[1]);
                        resultado.Add(auxiliar[0], result);
                    }
                    auxiliar[0] = null; auxiliar[1] = null;
                }
            }
            return resultado;
        }
        /// <summary>
        /// gramatical_query comprueba si coincide el siguiente elemento de una secuencia.
        /// </summary>
        /// <param name="root">El xml a comprobar</param>
        /// <param name="lista">Lista con la referencia a las coincidencias anteriores.</param>
        /// <param name="parametros">El elemento de la secuencia a comprobar.</param>
        /// <returns>Lista con la referencia a las coincidencias</returns>
        private SortedList<string, List<string>> gramatical_query(XElement root, SortedList<string, List<string>> lista, string[] parametros) 
        {
            SortedList<string, List<string>> resultado = new SortedList<string, List<string>>();
            foreach (string linea in lista.Keys)
            {
                List<string> list = new List<string>();
                lista.TryGetValue(linea, out list);
                string[] auxiliar = new string[2];
                foreach (string posicion in list)
                {
                    var Query =
                        from l in root.Element("Lineas").Elements()
                        where (string)l.Attribute("Numero") == linea
                        select new
                        {
                            pos_el =
                            from ele in l.Element("Elementos").Elements()
                            where
                            (int.Parse((string)ele.Attribute("Posicion")) > int.Parse(posicion)) && ((int.Parse((string)ele.Attribute("Posicion"))) <= int.Parse(posicion) + int.Parse(parametros[2])) && ((string)ele.Attribute("Tipo") == "Palabra") && (parametros[0] == ((((string)ele.Attribute("Etiqueta")) as string).ElementAt(0).ToString()))
                            select new
                            {
                                numero = l.Attribute("Numero").Value,
                                posicion = (string)ele.Attribute("Posicion")
                            }
                        };
                    if (!(Query.Count() == 0))
                    {
                        foreach (var l in Query)
                        {
                            foreach (var pos in l.pos_el)
                            {
                                auxiliar[0] = pos.numero;
                                auxiliar[1] = pos.posicion;

                            }
                        }
                    }
                }
                if (!(auxiliar[0] == null))
                {
                    List<string> result = new List<string>();
                    if (!(resultado.Count == 0) && resultado.ContainsKey(auxiliar[0]))
                    {
                        resultado.TryGetValue(auxiliar[0], out result);
                        result.Add(auxiliar[1]);
                        resultado.Remove(auxiliar[0]);
                        resultado.Add(auxiliar[1], result);
                    }
                    else
                    {
                        result.Add(auxiliar[1]);
                        resultado.Add(auxiliar[0], result);
                    }
                    auxiliar[0] = null; auxiliar[1] = null;
                }
            }
            return resultado;
        }
        /// <summary>
        /// Literal_query_inicial comprueba si coincide el primer elemento de una secuencia.
        /// </summary>
        /// <param name="root">El xml a comprobar.</param>
        /// <param name="parametros">Los elementos de la secuencia a comprobar.</param>
        /// <returns>Lista con la referencia a las coincidencias</returns>
        private SortedList<string, List<string>> literal_query_inicial(XElement root, List<string[]> parametros)
        {
            SortedList<string, List<string>> result = new SortedList<string, List<string>>();
            var literalQuery =
            from l in root.Element("Lineas").Elements()
            select
            new
            {
                pos_el =
                from el in l.Element("Elementos").Elements()
                where parametros[0][0] == (string)el.Attribute("Aparicion")
                select
                new
                {
                    numero = l.Attribute("Numero").Value,
                    posicion = (string)el.Attribute("Posicion"),
                },
            };
            
            if (!(literalQuery.Count() == 0))
            {
                foreach (var l in literalQuery)
                {
                    foreach (var pos in l.pos_el)
                    {
                        List<string> list = new List<string>();
                        if (result.ContainsKey(pos.numero))
                        {
                            result.TryGetValue(pos.numero, out list);
                            list.Add(pos.posicion);
                            result.Remove(pos.numero);
                            result.Add(pos.numero, list);
                        }
                        else
                        {
                            list.Add(pos.posicion);
                            result.Add(pos.numero, list);
                        }
                    }
                }
            }
            return result;
        }
        /// <summary>
        /// simbolos_query_inicial comprueba si coincide el primer elemento de una secuencia.
        /// </summary>
        /// <param name="root">El xml a comprobar.</param>
        /// <param name="parametros">Los elementos de la secuencia a comprobar.</param>
        /// <returns>Lista con la referencia a las coincidencias</returns>
        private SortedList<string, List<string>> simbolos_query_inicial(XElement root, List<string[]> parametros)
        {
            SortedList<string, List<string>> result = new SortedList<string, List<string>>();
            var simbolosQuery =
            from l in root.Element("Lineas").Elements()
            select
            new
            {
                pos_el =
                from el in l.Element("Elementos").Elements()
                where ((string)el.Attribute("Tipo")=="Simbolo") && (((string)el.Attribute("Etiqueta")).Contains(parametros[0][0]))
                select
                new
                {
                    numero = l.Attribute("Numero").Value,
                    posicion = (string)el.Attribute("Posicion"),
                },
            };
            if (!(simbolosQuery.Count() == 0))
            {
                foreach (var l in simbolosQuery)
                {
                    foreach (var pos in l.pos_el)
                    {
                        List<string> list = new List<string>();
                        if (result.ContainsKey(pos.numero))
                        {
                            result.TryGetValue(pos.numero, out list);
                            list.Add(pos.posicion);
                            result.Remove(pos.numero);
                            result.Add(pos.numero, list);
                        }
                        else
                        {
                            list.Add(pos.posicion);
                            result.Add(pos.numero, list);
                        }
                    }
                }
            }
            return result;
        }
        /// <summary>
        /// gramatical_query_inicial comprueba si coincide el primer elemento de una secuencia.
        /// </summary>
        /// <param name="root">El xml a comprobar.</param>
        /// <param name="parametros">Los elementos de la secuencia a comprobar.</param>
        /// <returns>Lista con la referencia a las coincidencias</returns>
        private SortedList<string, List<string>> gramatical_query_inicial(XElement root, List<string[]> parametros)
        {
            SortedList<string, List<string>> result = new SortedList<string, List<string>>();
            var gramaticalQuery =
            from l in root.Element("Lineas").Elements()
            select
            new
            {
                pos_el =
                from el in l.Element("Elementos").Elements()
                where (((string)el.Attribute("Tipo"))=="Palabra") && parametros[0][0] == (((string)el.Attribute("Etiqueta")) as string).ElementAt(0).ToString()
                select
                new
                {
                    numero = l.Attribute("Numero").Value,
                    posicion = (string)el.Attribute("Posicion"),
                },
            };
            if (!(gramaticalQuery.Count() == 0))
            {
                foreach (var l in gramaticalQuery)
                {
                    foreach (var pos in l.pos_el)
                    {
                        List<string> list = new List<string>();
                        if (result.ContainsKey(pos.numero))
                        {
                            result.TryGetValue(pos.numero, out list);
                            list.Add(pos.posicion);
                            result.Remove(pos.numero);
                            result.Add(pos.numero, list);
                        }
                        else
                        {
                            list.Add(pos.posicion);
                            result.Add(pos.numero, list);
                        }
                    }
                }
            }
            return result;
        }
    }
}
