using System;
using System.Diagnostics;
using Consulenza.ReportCommon;
using Consulenza.ReportWriter.Business.Entity;
using Consulenza.ReportWriter.Business;
using Consulenza.ReportWriter.Business.OBJ_PDF;
using Consulenza.ReportWriter.Manager.Integration;
using System.Data;
using System.Collections.Generic;
using System.Linq;
using System.Configuration;
using System.Text.RegularExpressions;
using System.Text;

namespace Consulenza.ReportWriter.Manager.Section.Entity
{
    public abstract class Section : EntityBase
    {
      

        private Dictionary<string, string> _extendedproperties = new Dictionary<string, string>();

        /// <summary>
        /// Imposta o recupera l'id della sezione definita a livello database.
        /// Campo ID della tabella Sezioni
        /// </summary>
        protected int IdSection { get; set; }

        /// <summary>
        /// Imposta o recupera l'oggetto IntegrationLayout che contiene informazioni id integrazioni grafiche.
        /// Ad esempio: duplicazione di capitoli, paragrafi e sezioni...
        /// </summary>
        protected IntegrationLayout IntegrationLayout { get; set; }

        /// <summary>
        /// Imposta o recupera informazioni personalizzate della Section
        /// </summary>
        public Dictionary<string, string> ExtendedProperties
        {
            get { return _extendedproperties; }
            set { _extendedproperties = value; }
        }

        /// <summary>
        /// Costruttore
        /// </summary>
        /// <param name="environmentFacade"></param>
        /// <param name="idsection"></param>
        protected Section(EnvironmentFacade environmentFacade, int idsection)
            : base(environmentFacade)
        {
            IdSection = idsection;
            EntityType = EntityTypePdf.Section;

            if (Convert.ToBoolean(ConfigurationManager.AppSettings["WriteSectionName"]))
                WriteSectionName();
        }

        /// <summary>
        /// Disegna la sezione.
        /// </summary>
        protected abstract void Draw();

        /// <summary>
        /// Recupera i dati necessari alla Section restituendo un DataTable.
        /// </summary>
        /// <returns></returns>
        protected abstract DataSet GetDataSet();

        /// <summary>
        /// Recupera i dati necessari alla Section restituendo un DataSet.
        /// </summary>
        /// <returns></returns>
        protected abstract DataTable GetDataTable();



        /// <summary>
        /// Scrive in alto a destra il nome(assembly) e l'id della sezione stampata nella pagina corrente.
        /// </summary>
        /// <remarks>Utilizzato solo al fine di debug</remarks>
        protected void WriteSectionName()
        {
            var stack = new StackFrame(2, false);
            var assemblyName = stack.GetMethod().DeclaringType.AssemblyQualifiedName;
            var delimiter = assemblyName.IndexOf(",");
            var sectionName = assemblyName.Substring(0, delimiter);

            AddElement(new FormattedTextAreaPDF(string.Format("{0}-{1}", sectionName, IdSection), EnvironmentFacade.RendererFacade.XRightLimit - 250));
        }

        /// <summary>
        /// Recupera i testi definiti in tabella [ReportModeler2].[Testi] eseguendo la stored sp_RecuperaTesti.
        /// </summary>
        /// <returns></returns>
        protected DataTable GetText()
        {
            #region Definizione dei parametri

            var parametri = new List<Parametro>
            {
                new Parametro
                {
                    Direction = ParameterDirection.Input,
                    DbType = DbType.Int32,
                    ParameterName = "IdReport",
                    Value = EnvironmentFacade.ReportEnvironment.ReportId
                },
                new Parametro
                {
                    Direction = ParameterDirection.Input,
                    DbType = DbType.Int32,
                    ParameterName = "IdSezione",
                    Value = IdSection
                }
            };

            #endregion

            return DataAccess.ExecuteDataTableStoredProcedure(DBProvider.SqlServerReportModeler, "sp_RecuperaTesti", parametri);
        }

        /// <summary>
        /// Costruisce la nota dinamica.
        /// Il placeholder "/%2/" indica il delimitatore della frase.[va messo anche se il testo della nota è costituito da una sola frase].
        /// Il placeholder "/%1/" indica il delimitatore all'interno della frase delimitata da "/%2/".
        /// Il placeholder (ad esempio) "[0-1-2]" indica che l'esistenza della stringa che lo contiene dipenderà dalla presenza (e diversità da 0) 
        /// dei valori con indice 0 o 1 o 2 contenuti Values e delimitati da "/%1/".
        /// Il numero di "/%1/" deve essere sempre uguale a quello di values e sValues.
        /// Il placeholder "|.|" e "|,|" indicano la presenza di una potenziale "," o ".".
        /// </summary>
        /// <param name="note">testo della nota</param>
        /// <param name="values">lista dei valori</param>
        /// <param name="sValues">lista dei valori in formato stringa</param>
        /// <param name="insertAsterisk">Se true inserisce all'inizio della nota un asterisco. Di default = True.</param>
        /// <returns></returns>
        protected string BuildDynamicNote(string note, List<decimal> values, List<string> sValues, bool insertAsterisk = true)
        {
            var returnString = new StringBuilder();

            string[] split2 = note.Split(new[] { "/%2/" }, StringSplitOptions.RemoveEmptyEntries);
            int counterSplit_global = 0; //contatore di split globale, non si azzera al cambio di split2

            foreach (var split_2 in split2)
            {
                if (split_2.Trim().ToString().Length == 0)
                    continue;

                var returnString_Split = new StringBuilder();
                string[] split1 = split_2.Split(new[] { "/%1/" }, StringSplitOptions.RemoveEmptyEntries);

                var dependenciesList = new List<int>();
                bool bDependenciesSatisfied = false; // dipendenza soddisfatta
                bool bDependenciesFound = false; // dipendenza trovata
                var dependenciesString = string.Empty; // la stringa che contiene la dipendenza

                int counterSplit_1 = 0;
                foreach (var split_1 in split1)
                {
                    var bSplitDependencies = split_1.Contains('[') && split_1.Contains(']'); // indica se lo split_1 corrente ha delle dipendenze a seconda della presenza delle []

                    // Dipendenze     
                    if (bSplitDependencies)
                    {
                        var cutted = split_1.Substring(split_1.IndexOf('[') + 1, (split_1.LastIndexOf(']') - split_1.IndexOf('[')) - 1);
                        var matchListDependences = Regex.Matches(cutted, "[0-9]+");
                        dependenciesList = matchListDependences.Cast<Match>().Select(match => match.Value).Select(s => int.Parse(s)).ToList();
                        dependenciesString = split_1.Replace(string.Format("[{0}]", cutted), string.Empty);
                    }

                    // Dipendenza trovata?
                    bDependenciesFound = dependenciesList.Any();

                    if (values[counterSplit_global] != 0)
                    {
                        if (bDependenciesFound)
                        {
                            if (dependenciesList.Contains(counterSplit_global))
                            {
                                if (!bSplitDependencies)
                                    returnString_Split.Append(string.Format(split_1, sValues[counterSplit_global]));
                                else
                                    dependenciesString = string.Format(dependenciesString, sValues[counterSplit_global]);

                                bDependenciesSatisfied = true;
                            }
                            else
                                returnString_Split.Append(string.Format(split_1, sValues[counterSplit_global]));
                        }
                        else
                            returnString_Split.Append(string.Format(split_1, sValues[counterSplit_global]));
                    }

                    if (split_1.Contains("|.|"))
                        returnString_Split.Append("|.|");

                    //Se c'è una dipendenza soddisfatta aggiungo all'inizio della stringa di ritorno la stringa con la dipendenza
                    if (bDependenciesSatisfied && counterSplit_1.Equals(split1.Length - 1))
                        returnString_Split.Insert(0, dependenciesString);

                    counterSplit_global++;
                    counterSplit_1++;
                }

                // Se sono state trovate dipendenze ma non sono state soddisfatte, la stringa di ritorno sarà vuota.
                if (bDependenciesFound && bDependenciesSatisfied == false)
                    returnString_Split.Clear();

                #region Sostizione dei caratteri speciali virgola "|,|" e punto "|.|"

                returnString_Split.Replace("|,|", ",");
                returnString_Split.Replace("|.|", ".");

                #endregion

                #region Replace ed eliminazione caratteri non ammessi

                // Elimino l'ultima "," se la stringa termina con ","
                if (returnString_Split.ToString().EndsWith(","))
                    returnString_Split.Remove(returnString_Split.Length - 1, 1);

                // Elimino l'ultima "," se la stringa termina con ",."
                if (returnString_Split.ToString().EndsWith(",."))
                    returnString_Split.Replace(",.", ".", returnString_Split.ToString().LastIndexOf(","), 2);

                // Elimino il primo "." se la stringa inizia con "."
                if (returnString_Split.ToString().Trim().StartsWith("."))
                    returnString_Split.Replace(".", string.Empty, returnString_Split.ToString().IndexOf("."), 1);

                // Elimino la primo "," se la stringa inizia con ","
                if (returnString_Split.ToString().Trim().StartsWith("."))
                    returnString_Split.Replace(",", string.Empty, returnString_Split.ToString().IndexOf(","), 1);

                #endregion

                returnString.Append(returnString_Split);

                // La stringa di ritorno terminerà sempre con il "."
                if (returnString.ToString().Trim().Length > 0 && !returnString.ToString().EndsWith("."))
                    returnString.Append(".");
            }

            if (returnString.ToString().Trim().Length > 0)
            {
                if (insertAsterisk)
                    returnString.Insert(0, "(*) ").ToString();
            }
            else
                return string.Empty;

            return returnString.ToString();
        }

        /// <summary>
        /// Recupera l' Opzione di visualizzazione a livello di Scheda a partire dal nome dell'Opzione della sezione.
        /// </summary>        
        /// <returns></returns>
        protected T GetOption<T>() where T : class
        {
            return EnvironmentFacade.ReportEnvironment.ReportStruct.GetOptionScheda<T>(IdSection);
        }
    }
}
