using System;
using System.Collections.Generic;
using ceTe.DynamicPDF.Merger;
using ceTe.DynamicPDF.PageElements;
using ceTe.DynamicPDF;
using System.Data;
using System.Collections;
using System.Linq;
using Consulenza.ReportCommon;
using Consulenza.ReportWriter.Business.CHART_PDF;
using Consulenza.ReportWriter.Business.OBJ_PDF;
using System.Configuration;
using Consulenza.ReportWriter.Business.Entity;
using RisorseEmbeddedRM;
using Consulenza.DataServices;
using ceTe.DynamicPDF.Text;
using Consulenza.ReportWriter.Business.Headers;

namespace Consulenza.ReportWriter.Business
{
    /// <summary>
    /// Implementa i metodi di assegnazione degli elementi ObjectPDF alla pagina.
    /// </summary>
    public class RendererPDF
    {
        # region Fields

        private int numberPageOnChapter = 0; // Numero della pagina aggiunta al singolo capitolo. Si resetta a 0 ad ogni cambio capitolo. (Evita di doppiare il titolo del capitolo aggiunto da WriteChapterTitle e dall'invocazione del capitolo stesso)

        private readonly Document _document;
        private readonly List<ObjectPDF> _elements = new List<ObjectPDF>();
        private List<EntityBase> _entities = new List<EntityBase>();
        private EntityBase _currentchapter; // puntatore al chapter correntetra quelli aggiunti alla collezione _entities.
        private ImportedPage _page;
        private readonly PdfDocument _generictemplate;
        private readonly PdfDocument _covertemplate;
        // Margini
        private readonly float _yendpage; // limite prefissato e non variabile, corrisponde alla linea di chiusura pagina.
        private readonly float _ylowerlimitoriginal; // non variabile in funzione della presenza delle note di piè di pagina. la differenza tra _ylowerlimitoriginal - _ylowerlimit indica lo spazio dell apagina in cui vengono scritte le note di fondo pagina.

        /// <summary>
        /// Y corrente su cui verrà disegnato ObjectPDF
        /// </summary>
        private float _ywritable;
        public float YWritable
        {
            get { return _ywritable; }
            set { _ywritable = value; }
        }
        /// <summary>
        /// Permette di accedere alle impostazioni di "ambiente" specifiche del Report corrente (chiavi di invocazione etc...).
        /// </summary>
        private readonly ReportEnvironment _reportEnvironment;

        private float _spacenotefooterpagePerpage;

        /// <summary>
        /// Indica se il prossimo elemento che sarà stampatoo sulla pagina, verrà stampato in una nuova pagina.
        /// </summary>
        private bool _printinginnewpage = true;

        /// <summary>
        /// Limite sinitro della pagina (è già considerato lo spazio necessario per le avvertenze.)
        /// Di default 37
        /// </summary>
        public float XLeftLimit { get; set; }

        /// <summary>
        /// Limite destro della pagina.
        /// Di default 560
        /// </summary>
        public float XRightLimit { get; set; }

        /// <summary>
        /// Limite massimo superiore della pagina (corrisponde alla linea rossa superiore)
        /// Di default 130
        /// </summary>
        public float YUpperLimit { get; set; }

        /// <summary>
        /// Limite massimo superiore della pagina (corrisponde alla linea rossa inferiore)
        /// Di default 750
        /// </summary>
        public float YLowerLimit { get; set; }



        private List<ObjectPDF> _repeaterElements;


        #endregion

        /// <summary>
        /// Costruttore.
        /// Imposta la il Template, la Page e passa una rappresentazione del DataModel all'implementazione estesa della classe corrente
        /// al fine di supportare l'invocazione dei metodi di rendering delle classi specifiche del Layout esteso di ciascuna pagina (vedere FrameClassMapperManager invocato dall'estensione RendererExtender.cs). 
        /// </summary>
        /// <param name="environment"></param>        
        public RendererPDF(ReportEnvironment environment)
        {
            _reportEnvironment = environment;

            _document = new Document();
            Document.AddLicense(ConfigurationManager.AppSettings["Licenza"]);

            #region Template

            // Imposto il documento per la copertina del report
            var fileCoverTemplate = RisorseEmbedded.GetResourceByName(_reportEnvironment.ResourceNameCover);
            _covertemplate = new PdfDocument(fileCoverTemplate);

            // Imposto il documento per le pagine generiche del report.
            var fileGenericTemplate = RisorseEmbedded.GetResourceByName(_reportEnvironment.ResourceNameTemplate);
            _generictemplate = new PdfDocument(fileGenericTemplate);

            #endregion

            #region Margini del documento

            switch (environment.ReportType)
            {
                case ReportType.Base_Proposta:
                    // Template A4 Verticale
                    XLeftLimit = 37;
                    XRightLimit = 560;
                    YUpperLimit = 105;
                    YLowerLimit = 745;
                    _yendpage = 766F;
                    _ylowerlimitoriginal = 745F;
                    break;
                case ReportType.Immobiliare_Diagnosi:
                case ReportType.Immobiliare_DiagnosiNucleo:
                case ReportType.Immobiliare_MappaturaPreliminare:
                case ReportType.Immobiliare_Finalita:
                    // Template A4 Orizzontale
                    XLeftLimit = 50;
                    XRightLimit = 805;
                    YUpperLimit = 35;
                    _yendpage = 510;
                    _ylowerlimitoriginal = 485;
                    YLowerLimit = 485;
                    break;
                case ReportType.Unica_Diagnosi:
                case ReportType.Unica_Monitoraggio:
                case ReportType.Unica_Proposta:
                case ReportType.Unica_Nucleo:
                    // Template A4 Verticale
                    XLeftLimit = 37;
                    XRightLimit = 560;
                    YUpperLimit = 122;
                    YLowerLimit = 745;
                    _yendpage = 740F;
                    _ylowerlimitoriginal = 740F;
                    break;
                case ReportType.Immobiliare_Monitoraggio:
                    // Template A4 Orizzontale
                    XLeftLimit = 14;
                    XRightLimit = 805;
                    YUpperLimit = 17;
                    _yendpage = 474;
                    _ylowerlimitoriginal = 480;
                    YLowerLimit = 490;
                    break;
                case ReportType.Immobiliare_MonitoraggioNuclei:
                    // Template A4 Orizzontale
                    XLeftLimit = 14;
                    XRightLimit = 805;
                    YUpperLimit = 17;
                    _yendpage = 474;
                    _ylowerlimitoriginal = 480;
                    YLowerLimit = 490;
                    break;
                default:
                    throw new Exception("ReportType da definire: [Consulenza.ReportWriter.Business.RendererPDF()]");
            }

            #endregion

            #region Compression Level
            _document.CompressionLevel = 9;
            #endregion

            #region Security
            // Create a standard security object 
            //var security = new StandardSecurity { AllowCopy = false, AllowEdit = false };
            //FC 26/01/2017
            //richiesta Casoli Abilitazione Copia e Modifica documenti
            var security = new StandardSecurity { AllowCopy = true, AllowEdit = true };

            
            // Add the security object to the document 
            _document.Security = security;
            #endregion

            #region Pdf Version

            _document.PdfVersion = PdfVersion.v1_7;
            _document.PdfXVersion = PdfXVersion.PDF_X_3_2003;

            #endregion

            #region ICCProfile
            var iccProfile = new IccProfile(RisorseEmbedded.GetResourceByName("RisorseEmbeddedRM.PDFTemplates.sRGB.icc"));

            const string configurationPath1 = "CGATS TR 001-1995 (SWOP)";
            const string configurationPath2 = "CGATS TR 001";
            const string configurationPath3 = "http://www.color.org";
            const string configurationPath4 = "U.S. Web Coated (SWOP) v2";

            var outputIntent = new OutputIntent(configurationPath1, configurationPath2, configurationPath3, configurationPath4, iccProfile);
            _document.OutputIntents.Add(outputIntent);
            _document.Trapped = Trapped.False;
            #endregion

            if (_ywritable == 0)
                _ywritable = YUpperLimit;

        }

        /// <summary>
        /// Ritorna la rappresentazione in array di byte[] del report.
        /// </summary>
        /// <returns></returns>
        public byte[] Render(List<EntityBase> entities)
        {
            _entities = entities;

            WriteElements();

            if (_reportEnvironment.ReportType == ReportType.Immobiliare_Monitoraggio || _reportEnvironment.ReportType == ReportType.Immobiliare_MonitoraggioNuclei)
            {
                ReplaceHeadersIndexes();
                ReplaceIndexPagePageNumbers();
            }


            return _document.Draw();
        }

        private void ReplaceIndexPagePageNumbers()
        {
            if (_document != null && _document.Pages != null)
            {
                foreach (Page page in _document.Pages)
                {
                    foreach (var element in page.Elements)
                    {
                        if (element is FormattedTextArea)
                        {
                            FormattedTextArea el = element as FormattedTextArea;
                            foreach (var tuple in MonitoraggioImmobiliarePageHeaderManager.IndexPagesPageNumbersToReplace)
                            {
                                if (el != null && (el.Text != null && el.Text.Contains(tuple.Item2)))
                                {
                                    el.Text = el.Text.Replace(tuple.Item2, (headers.IndexOf(headers.Where(x => x.Item1.BelongToIndex == tuple.Item1).First()) + 3).ToString());
                                }
                            }
                        }
                    }
                }
            }
            MonitoraggioImmobiliarePageHeaderManager.IndexPagesPageNumbersToReplace.Clear();
        }
        private void ReplaceHeadersIndexes()
        {
            if (_document != null & _document.Pages != null && headers.Count() > 0)
            {
                foreach (var header in headers)
                {
                    var sectionId = header.Item1;
                    var sameSectionHeaders = headers.Where(x => x.Item1 == sectionId).ToList();
                    if (sameSectionHeaders.Count() == 1)
                    {
                        var guid = sameSectionHeaders.FirstOrDefault().Item1.TextReplaceGuid;
                        var newHeaderText = sameSectionHeaders.FirstOrDefault().Item2.Text.Replace(
                            guid, string.Empty);
                        for (int i = 0; i < _document.Pages.Count; i++)
                        {
                            for (int j = 0; j < _document.Pages[i].Elements.Count; j++)
                            {
                                FormattedTextArea el = _document.Pages[i].Elements[j] as FormattedTextArea;
                                if (el != null && (el.Text != null & el.Text.Contains(guid)))
                                {
                                    el.Text = newHeaderText;
                                }
                            }
                        }
                    }
                    else if (sameSectionHeaders.Count() > 1)
                    {
                        int maxPages = sameSectionHeaders.Count();
                        int indexPage = 1;
                        for (int i = 0; i < maxPages; i++)
                        {
                            var guid = sameSectionHeaders[i].Item1.TextReplaceGuid;

                            for (int a = 0; a < _document.Pages.Count; a++)
                            {
                                for (int j = 0; j < _document.Pages[a].Elements.Count; j++)
                                {
                                    FormattedTextArea el = _document.Pages[a].Elements[j] as FormattedTextArea;
                                    if (el != null && (el.Text != null && el.Text.Contains(guid)))
                                    {
                                        var newHeaderText = sameSectionHeaders[i].Item2.Text.Replace(guid, string.Format(" ({0}/{1})", indexPage, maxPages));
                                        el.Text = newHeaderText;
                                        indexPage++;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        #region WriteElements

        /// <summary>
        /// Disegna sulla pagina tutti gli elementi aggiunti al documento.
        /// Riduce lo spazio scrivibile della pagina se ci sono note a piedipagina da stampare
        /// </summary>
        private void WriteElements()
        {
            foreach (var entity in _entities)
            {
                // puntatore al chapter corrente.                
                if (entity.EntityType == EntityTypePdf.Chapter)
                {
                    _currentchapter = entity;
                    numberPageOnChapter = 0;
                }
                // elementi Repeater
                var elementRepeater = entity.Elements.FirstOrDefault(o => o.ObjectType == ObjectTypePdf.REPEATER);
                if (elementRepeater != null)
                    _repeaterElements = ((RepeaterPDF)elementRepeater).Elements;

                // Disegno tutti gli elementi (Elements)
                foreach (var element in entity.Elements)
                {
                    _elements.Add(element);

                    #region switch ObjectType elemento

                    switch (element.ObjectType)
                    {
                        case ObjectTypePdf.FORMATTEDTEXTAREA:
                            WriteElement((FormattedTextAreaPDF)element);
                            break;

                        case ObjectTypePdf.LINE:
                            WriteElement((LinePDF)element);
                            break;

                        case ObjectTypePdf.IMAGE:
                            WriteElement((ImagePDF)element);
                            break;

                        case ObjectTypePdf.TABLE:
                            WriteElement((TablePDF)element);
                            break;

                        case ObjectTypePdf.SPACE:
                            WriteElement((SpacePDF)element);
                            break;

                        case ObjectTypePdf.RECTANGLE:
                            WriteElement((RectanglePDF)element);
                            break;

                        case ObjectTypePdf.UNORDEREDLIST:
                            WriteElement((UnorderedListPDF)element);
                            break;

                        case ObjectTypePdf.PAGE:
                            var page = (PagePDF)element;
                            switch (page.Type)
                            {
                                case PagePDF.PagePDFType.Generic:
                                    AddPage();
                                    numberPageOnChapter++;
                                    break;
                                case PagePDF.PagePDFType.Cover:
                                    AddPage(PagePDF.PagePDFType.Cover);
                                    break;
                            }
                            break;

                        case ObjectTypePdf.CIRCLE:
                            WriteElement((CirclePDF)element);
                            break;

                        case ObjectTypePdf.RESETTER_Y:
                            WriteElement((ResetterYPDF)element);
                            break;
                        case ObjectTypePdf.ACTIONPDF:
                            WriteElement((ActionPDF)element);
                            break;
                        case ObjectTypePdf.COMPOSITE:
                            WriteElement((CompositePDF)element);
                            break;

                        case ObjectTypePdf.CHART:

                            var chart = element as ChartPDF;

                            switch (chart.ChartType)
                            {
                                case ChartTypePdf.PIE:
                                    chart = element as PiePDF;
                                    break;
                                case ChartTypePdf.STACKED:
                                    chart = element as StackedPDF;
                                    break;
                                case ChartTypePdf.COMBINATION:
                                    chart = element as CombinationPDF;
                                    break;
                                default:
                                    throw new Exception("Grafico non esistente");
                            }


                            WriteElement(chart);

                            break;

                        case ObjectTypePdf.CIRCLEREAL:
                            WriteElement((CircleRealPDF)element);
                            break;
                        case ObjectTypePdf.CUSTOMCHART:
                            WriteElement((CustomChartPDF)element);
                            break;
                    }

                    #endregion
                }

                _repeaterElements = null;
            }
        }

        #endregion

        #region WriteElement

        private void WriteElement(ObjectPDF element)
        {
            //var genericElement = Activator.CreateInstance(element.GetType());

            switch (element.ObjectType)
            {
                case ObjectTypePdf.FORMATTEDTEXTAREA:
                case ObjectTypePdf.TABLENOTE:
                    WriteElement((FormattedTextAreaPDF)element);
                    break;
                case ObjectTypePdf.IMAGE:
                    WriteElement((ImagePDF)element);
                    break;
                case ObjectTypePdf.SPACE:
                    WriteElement((SpacePDF)element);
                    break;
                case ObjectTypePdf.LINE:
                    WriteElement((LinePDF)element);
                    break;
                case ObjectTypePdf.RECTANGLE:
                    WriteElement((RectanglePDF)element);
                    break;
                case ObjectTypePdf.CIRCLE:
                    WriteElement((CirclePDF)element);
                    break;
                case ObjectTypePdf.CIRCLEREAL:
                    WriteElement((CircleRealPDF)element);
                    break;
                case ObjectTypePdf.UNORDEREDLIST:
                    WriteElement((UnorderedListPDF)element);
                    break;
                case ObjectTypePdf.CHART:
                    WriteElement((ChartPDF)element);
                    break;
                case ObjectTypePdf.TABLE:
                    WriteElement((TablePDF)element);
                    break;
                case ObjectTypePdf.RESETTER_Y:
                    WriteElement((ResetterYPDF)element);
                    break;
                case ObjectTypePdf.ACTIONPDF:
                    WriteElement((ActionPDF)element);
                    break;
                case ObjectTypePdf.COMPOSITE:
                    WriteElement((CompositePDF)element);
                    break;
                case ObjectTypePdf.CUSTOMCHART:
                    WriteElement((CustomChartPDF)element);
                    break;
            }
        }

        /// <summary>
        /// Scrive l'elemento NotePDF nella pagina
        /// </summary>
        /// <param name="element"></param>
        private void WriteElement(TableNotePDF element)
        {
            if (element.Image == null)
            {
                var elementConverted = element as FormattedTextAreaPDF;
                if (element.TypeMarker != TableNotePDF.TableNoteTypemarker.Numeri)
                    elementConverted.Text = element.AsterisksNumber > 0 ? "(" + element.ToAsteriskString() + ") " + element.Text : element.Text;
                else
                    elementConverted.Text = element.AsterisksNumber > 0 ? "(" + element.ToNumberAsteriskString() + ") " + element.Text : element.Text;
                WriteElement(elementConverted);
            }
            else
            {
                var elements = new List<ObjectPDF>();

                // testo della nota
                var elementText = element as FormattedTextAreaPDF;
                elementText.Text = element.Text;
                elementText.X += 20;

                // immagine della nota
                var elementImage = element.Image;
                elementImage.AutoIncrementYWritable = false;

                elements.Add(elementImage);
                elements.Add(elementText);

                // disegno gli oggetti aggiunti
                foreach (var item in elements)
                    WriteElement(item);
            }
        }

        /// <summary>
        /// Scrive l'elemento RectanglePDF nella pagina
        /// </summary>
        /// <param name="element"></param>
        private void WriteElement(RectanglePDF element)
        {
            var color = new RgbColor((byte)element.Color.Red, (byte)element.Color.Green, (byte)element.Color.Blue);
            element.BaseElement = new Rectangle(element.X, element.Y, element.Width, element.Height, color, color);

            //element.BaseElement.X += element.DeltaX;
            // Imposto Y
            if (element.Y == 0)
                element.BaseElement.Y = _ywritable + element.DeltaY;

            // CornerRadius
            if (element.CornerRadius > 0)
                element.BaseElement.CornerRadius = element.CornerRadius;

            // Angle
            if (element.Angle != 0)
                element.BaseElement.Angle = element.Angle;

            // Disegno BaseElement
            if (_ywritable + element.Height <= YLowerLimit)
                _page.Elements.Add(element.ToElement());
            else
            {
                // aggiungere una pagina
                AddPage();
                element.BaseElement.Y = _ywritable + element.DeltaY;
                _page.Elements.Add(element.ToElement());

            }
            // Imposto Border
            if (element.BorderWidth > 0)
            {
                var colorBorder = new RgbColor((byte)element.BorderColor.Red, (byte)element.BorderColor.Green, (byte)element.BorderColor.Blue);
                element.BaseElement.BorderWidth = element.BorderWidth;
                element.BaseElement.BorderColor = colorBorder;
                element.BaseElement.BorderStyle = LineStyle.Solid;
            }

            // Incremento _ywritable
            if (element.AutoIncrementYWritable)
                _ywritable += element.Height;
        }

        /// <summary>
        /// Scrive l'elemento CirclePDF nella pagina
        /// </summary>
        /// <param name="element"></param>
        private void WriteElement(CirclePDF element)
        {
            WriteElement((RectanglePDF)element);
        }

        private void WriteElement(CircleRealPDF element)
        {
            var color = new RgbColor((byte)element.Color.Red, (byte)element.Color.Green, (byte)element.Color.Blue);
            element.BaseElement = new Circle(element.X, element.Y, element.Radius, color)
            {
                FillColor = color
            };

            element.BaseElement.X += element.DeltaX;
            // Imposto Y
            if (element.Y == 0)
                element.BaseElement.Y = _ywritable + element.DeltaY;

            // Disegno BaseElement
            if (_ywritable + element.Radius * 2 <= YLowerLimit)
                _page.Elements.Add(element.ToElement());
            else
            {
                // aggiungere una pagina
                AddPage();
                element.BaseElement.Y = _ywritable + element.DeltaY;
                _page.Elements.Add(element.ToElement());

            }

            // Incremento _ywritable
            if (element.AutoIncrementYWritable)
                _ywritable += element.Radius * 2;
        }

        /// <summary>
        /// Scrive l'elemento FormattedTextAreaPDF nella pagina
        /// </summary>
        /// <param name="element"></param>
        private void WriteElement(FormattedTextAreaPDF element)
        {
            // Style
            var color = new RgbColor((byte)element.FontColor.Red, (byte)element.FontColor.Green, (byte)element.FontColor.Blue);
            var styleFormattedTextArea = new FormattedTextAreaStyle(_reportEnvironment.FontFamily, element.FontSize, false) { Bold = element.FontBold };

            element.BaseElement = new FormattedTextArea(element.Text, element.X, element.Y, element.Width, element.Height, styleFormattedTextArea)
            {
                Style = styleFormattedTextArea
            };

            element.BaseElement.Style.Font.Color = color;

            element.BaseElement.Style.Paragraph.Align = element.TextHorizontalAlign;


            element.BaseElement.VAlign = element.TextVerticalAlign;

            // Imposto Height
            if (element.Width > 0 && !string.IsNullOrEmpty(element.Text))
            {
                element.SetHeight(element.FixedHeight > 0 ? element.FixedHeight : element.BaseElement.GetRequiredHeight());
            }
            //else
            //    element.Height = element.FixedHeight;

            element.BaseElement.Height = element.Height;

            // Imposto Y
            element.BaseElement.Y = element.Y == 0 ? _ywritable + element.DeltaY : element.Y + element.DeltaY;

            // Imposto X
            element.BaseElement.X += element.DeltaX;

            // Imposto testo in verticale.
            if (element.TextVerticalDirection)
            {
                element.BaseElement.Angle = -90;
            }


            #region BackGround

            if (element.BackGroundColor != null)
            {
                var rectangleBackColor = new RectanglePDF(element.BackGroundHeight, element.Width, element.BackGroundColor)
                {
                    X = element.X
                };
                rectangleBackColor.Y = element.BaseElement.Y - (rectangleBackColor.Height / 2) + (element.FontSize / 2);

                if (element.BaseElement.VAlign == VAlign.Top)
                    element.BaseElement.Y = _ywritable - (rectangleBackColor.Height / 2) + (element.FontSize / 2);

                rectangleBackColor.AutoIncrementYWritable = false;
                WriteElement(rectangleBackColor);

                // Margine sinistro dell'etichetta (BackGroundMarginLeft)
                element.BaseElement.X += element.BackGroundMarginLeft;
            }

            #endregion


            // Disegno BaseElement
            if (_ywritable + element.Height <= YLowerLimit || element.AbsolutePosition)
            {
                if (element.ID == "debug")
                    _page.Elements.Add(new Line(element.BaseElement.X, element.BaseElement.Y, element.BaseElement.X + element.Width, element.BaseElement.Y, RgbColor.Red));

                _page.Elements.Add(element.ToElement());

                if (element.ID == "debug")
                    _page.Elements.Add(new Line(element.BaseElement.X, element.BaseElement.Y + element.Height, element.BaseElement.X + element.Width, element.BaseElement.Y + element.Height, RgbColor.Yellow));
            }
            else
            {
                // aggiungere una pagina
                AddPage();
                element.BaseElement.Y = _ywritable + element.DeltaY;

                _page.Elements.Add(element.ToElement());
            }


            if (element.AutoIncrementYWritable && element.BackGroundColor == null)
                _ywritable += element.Height;

            if (element.AutoIncrementYWritable && element.BackGroundColor != null)
                _ywritable += element.BackGroundHeight - (element.BackGroundHeight / 2) + (element.FontSize / 2);

        }

        /// <summary>
        /// Scrive l'elemento LinePDF nella pagina
        /// </summary>
        /// <param name="element"></param>
        private void WriteElement(LinePDF element)
        {
            var color = new RgbColor((byte)element.Color.Red, (byte)element.Color.Green, (byte)element.Color.Blue);
            element.BaseElement = new Line(element.X1, element.Y1, element.X2, element.Y2, element.Width, color, element.BorderStyle);

            if (element.Y1 == 0)
            {
                element.BaseElement.Y1 = _ywritable;
                element.BaseElement.Y2 = _ywritable;
            }

            element.BaseElement.Y1 += element.DeltaY;

            element.BaseElement.Y2 += element.DeltaY;
            element.BaseElement.Y2 += element.DeltaY2ForVerticalLine;

            // Disegno il BaseElement
            _page.Elements.Add(element.ToElement());

            if (element.DeltaY2ForVerticalLine == 0 && element.AutoIncrementYWritable)
                _ywritable += element.Width;

        }

        /// <summary>
        /// Scrive l'elemento ImagePDF nella pagina
        /// </summary>
        /// <param name="element"></param>
        private void WriteElement(ImagePDF element)
        {
            var imageFound = true;
            try
            {
                // Imposto il sorgente dell'immagine
                element.BaseElement = string.IsNullOrEmpty(element.Path)
                    ? new Image(element.File, element.X + element.DeltaX, element.Y, element.Scale)
                    : new Image(element.Path, element.X + element.DeltaX, element.Y, element.Scale);
            }
            catch (Exception ex)
            {
                imageFound = false;
            }

            if (imageFound)
            {
                // Imposto Y
                element.BaseElement.Y = element.Y == 0 ? _ywritable : element.Y;
                element.BaseElement.Y += element.DeltaY;

                // Imposto dimensioni e allineamento
                element.BaseElement.Align = element.Align;

                if (element.Height > 0)
                    element.BaseElement.Height = element.Height;

                if (element.Width > 0)
                    element.BaseElement.Width = element.Width;

                // Disegno il BaseElement.
                _page.Elements.Add(element.ToElement());


                if (element.AutoIncrementYWritable)
                    _ywritable += element.BaseElement.Height;
            }
        }

        /// <summary>
        /// Scrive l'elemento TabellaPDF nella pagina
        /// La tabella è disegnata come un insieme di LabelPDF separate da LinePDF
        /// </summary>
        /// <param name="element"></param>
        private void WriteElement(TablePDF element)
        {
            _ywritable += element.YOffset;
            var originalYWritable = _ywritable;
            if (element.Y == 0)
                element.Y = _ywritable;

            var dataSourceInput = element.DataSource;
            var rowsHeightList = new List<float>();

            int columnIndex = 0;
            int rowIndex = 0;
            int rowIndexPerPage = 0; // è l'indice della riga che si azzera al saltopagina.           

            var columnsWidthOriginal = new List<int>(); // è la larghezza originale delle colonne non modificata se impostata la Cell.ColSpan
            columnsWidthOriginal.AddRange(element.Columns.Select(o => o.Width));

            // Imposto HeaderFontSize di tutte le colonne per cui non è stato impostato (=0) uguale a HeaderFontSize della relativa tabella.
            // Questo perché HeaderFontSize della tabella è variabile in funzione dello Style.
            element.Columns.FindAll(o => o.HeaderFontSize == 0).ToList().ForEach(c => c.HeaderFontSize = element.HeaderFontSize);

            #region Controllo dimensione della larghezza della tabella

            if (element.X + element.Width > XRightLimit)
                throw new Exception("La tabella è troppo grande in larghezza");

            #endregion

            // TABLE TITLE
            //if (element.TableTitle != null)
            //{
            //    FormattedTextAreaPDF title = new FormattedTextAreaPDF(element.TableTitle, element.X + element.TableTitleDeltaX, element.Width) { FontBold = element.TableTitleFontBold, FontSize = element.TableTitleFontSize, FontColor = element.TableTitleFontColor, AutoIncrementYWritable = true };
            //    WriteElement(title);
            //    WriteElement(new SpacePDF(5));
            //}


            #region Recupero colonne del datatable da stampare e imposto il Datasource
            // Recupera le colonne in base alla proprietà Colonne della tabella.
            // Vengono escluse le colonne che non hanno la proprietà Nome impostata.
            var arrList = new ArrayList();
            foreach (ColumnPDF c in element.Columns)
            {
                switch (c.TipoColonna)
                {
                    case ColumnType.Testo:
                    case ColumnType.Decimale:
                    case ColumnType.Intero:
                    case ColumnType.Percentuale:
                        if (!string.IsNullOrEmpty(c.Name))
                            arrList.Add(c.Name);
                        break;

                    case ColumnType.Immagine:
                    case ColumnType.Objectpdf:
                        if (!string.IsNullOrEmpty(c.Id))
                            arrList.Add(c.Id);
                        break;
                }

                // Imposto la colonna a visible=false se la larghezza è pari a 0
                c.Visibile = c.Width != 0;
            }
            var strArray = (string[])arrList.ToArray(typeof(string));

            #region Settaggio DataSource

            int numeroRigheInvisibili = 0;
            int numeroRigheTotali;
            if (element.DataSource == null)
            {
                #region Impostazione del datasource se non passato in input

                var dtDataSource = new DataTable("DataSource");

                // Creo le colonne del dtDataSource
                foreach (var colonnaDataSource in element.Columns)
                {
                    dtDataSource.Columns.Add(colonnaDataSource.Id);
                }

                for (int nRiga = 0; nRiga < element.RowsCount; nRiga++)
                {
                    var drToAdd = dtDataSource.NewRow();
                    for (int nColonna = 0; nColonna < element.Columns.Count; nColonna++)
                    {
                        if (!string.IsNullOrEmpty(element.Cells[nColonna, nRiga].Value))
                            drToAdd[nColonna] = element.Cells[nColonna, nRiga].Value;
                        else
                        {
                            try
                            {
                                var formattedtextareaToPrint = (FormattedTextAreaPDF)element.Cells[nColonna, nRiga].ValueObject;
                                if (formattedtextareaToPrint != null)
                                    drToAdd[nColonna] = formattedtextareaToPrint.Text;
                            }
                            catch (Exception)
                            {
                                drToAdd[nColonna] = string.Empty;
                            }
                        }
                    }

                    if (element.Row[nRiga].Visible)
                        dtDataSource.Rows.Add(drToAdd);
                }

                element.DataSource = dtDataSource;
                numeroRigheTotali = element.DataSource.Rows.Count;
                #endregion
            }
            else
            {
                #region Impostazione del datasource se passato in input

                #region Aggiunta manuale dei dati relativi alle colonne di tipo RISORSEEMBEDDED

                // Controllo se sono state aggiunte colonne di tipo IMMAGINE o OBJECTPDF.
                // Le colonne IMMAGINE con un "Name" impostato vengono escluse dall'aggiunta manuale. [In questo modo nella colonna verrà rendirizzata l'immagine definita del datasource, ad esempio "riseva.png, liquidita.png, etc"]
                var columnsEmbeddedOrObject = element.Columns.FindAll(col => col.TipoColonna == ColumnType.Objectpdf || (col.TipoColonna == ColumnType.Immagine && col.Name == string.Empty));

                if (columnsEmbeddedOrObject.Count > 0)
                {
                    foreach (ColumnPDF column in columnsEmbeddedOrObject)
                        element.DataSource.Columns.Add(column.Id);
                }
                #endregion

                // imposto il datasource
                element.DataSource = element.DataSource.DefaultView.ToTable(false, strArray);

                if (columnsEmbeddedOrObject.Count > 0)
                {
                    for (int nRiga = 0; nRiga < element.RowsCount; nRiga++)
                    {
                        for (int nColonna = 0; nColonna < element.Columns.Count; nColonna++)
                        {
                            if (!string.IsNullOrEmpty(element.Cells[nColonna, nRiga].Value))
                                element.DataSource.Rows[nRiga][nColonna] = element.Cells[nColonna, nRiga].Value;
                        }
                    }
                }

                numeroRigheTotali = element.DataSource.Rows.Count;

                // elimino le righe rese invisibili.                
                for (int nRiga = element.RowsCount - 1; nRiga >= 0; nRiga--)
                {
                    if (element.Row[nRiga].Visible == false)
                    {
                        element.DataSource.Rows[nRiga].Delete();
                        element.DataSource.AcceptChanges();
                        numeroRigheInvisibili++;
                    }
                }

                #endregion
            }

            #region Merge da Cell.Value
            // Tutto ciò che è impostato a livello di Cell deve essere riportato nel DataSource
            for (int col = 0; col < element.DataSource.Columns.Count; col++)
            {
                for (int row = 0; row < element.DataSource.Rows.Count; row++)
                {
                    if (!string.IsNullOrEmpty(element.Cells[col, row].Value))
                    {
                        element.DataSource.Rows[row][col] = element.Cells[col, row].Value;
                    }
                }
            }
            #endregion

            #endregion

            #endregion

            #region Righe alternate con sfondo bianco a sfondo grigio

            if (element.AlternateRow)
            {
                for (int i = 0; i < element.Row.Length; i++)
                {
                    if (i % 2 != 0)
                        element.Row[i].BackgroundGray = true;
                }
            }

            #endregion

            #region Recupero le note, associate alla tabella, da inserire sotto il footer della tabella e nel footer della pagina

            #region Note footer della pagina

            var notesFooterPage = element.Notes.FindAll(o => o.Position == TableNotePDF.TableNotePositionType.PièDiPagina);
            if (notesFooterPage.Count > 0)
                YLowerLimit -= _spacenotefooterpagePerpage + (notesFooterPage.Count * notesFooterPage[0].FontSize) * 2;
            else
                YLowerLimit -= _spacenotefooterpagePerpage;

            #endregion

            #region Note footer della tabella

            var notesFooterTable = element.Notes.FindAll(o => o.Position == TableNotePDF.TableNotePositionType.PièDiTabella);
            float variabileAltezzaTabellaPerPresenzaNote = element.AdditionalSpaceBelow;
 
            foreach (var note in notesFooterTable)
            {
                variabileAltezzaTabellaPerPresenzaNote += GetTextHeigth(note.Text, XRightLimit - XLeftLimit, note.FontSize);
                if (note.Image != null)
                    variabileAltezzaTabellaPerPresenzaNote += 10; // ulteriore 10 se la nota contiene immagine
            }
            #endregion

            var arrayAsterischiNote_Intestazione = new string[1, element.DataSource.Columns.Count]; // array di righe e colonne dell'intestazione della tabella dove sono contenuti gli asterischi            
            var arrayAsterischiNote_Corpo = new string[element.DataSource.Rows.Count, element.DataSource.Columns.Count]; // array di righe e colonne del dettaglio della tabella dove sono contenuti gli asterischi
            var arrayAsterischiNote_PieDiPagina = new string[1, element.FooterColumns.Count]; // array di righe e colonne del footer della tabella dove sono contenuti gli asterischi

            foreach (TableNotePDF note in element.Notes)
            {
                if (note.TypeMarker == TableNotePDF.TableNoteTypemarker.Asterisco)
                {
                    if (note.AsterisksPosition == TableNotePDF.TableNoteAsteriskPositionType.CorpoTabella)
                    {
                        #region Asterischi del dettaglio della tabella

                        var rowNoteFooterTable = dataSourceInput.Select(note.Condition); //element.DataSource.Select(note.Condition);

                        if (rowNoteFooterTable.Length.Equals(0))
                        {
                            notesFooterTable.Remove(note); //Rimuovo le note che non trovano corrispondenza.
                            continue;
                        }

                        if (note.MappingFields != null)
                        {
                            // ToLower di tutti gli elementi memorizzati in ListIdColumnsAssociatedNote.
                            for (int i = 0; i < note.MappingFields.Length; i++)
                                note.MappingFields[i] = note.MappingFields[i].ToLower();

                            foreach (var row in rowNoteFooterTable)
                            {
                                int indiceColonna = 0;
                                int indiceRiga;

                                foreach (ColumnPDF column in element.Columns)
                                {
                                    switch (note.MappingType)
                                    {
                                        case TableNotePDF.TableNoteMappingType.Fisso:

                                            indiceRiga = dataSourceInput.Rows.IndexOf(row);

                                            if (note.MappingFields.Contains(column.Id.ToLower()))
                                            {
                                                if (string.IsNullOrEmpty(arrayAsterischiNote_Corpo[indiceRiga, indiceColonna]))
                                                    arrayAsterischiNote_Corpo[indiceRiga, indiceColonna] = TableNotePDF.ToAsteriskString(GetAsterisksNumber(note));
                                                else
                                                    arrayAsterischiNote_Corpo[indiceRiga, indiceColonna] += " " + TableNotePDF.ToAsteriskString(GetAsterisksNumber(note));
                                            }
                                            break;

                                        case TableNotePDF.TableNoteMappingType.Dinamico:
                                            bool astericoPresente = false;

                                            indiceRiga = new DataView(dataSourceInput).ToTable(false, new[] { note.MappingKey })
                                                 .AsEnumerable()
                                                 .Select(riga => riga.Field<Int32>(note.MappingKey))
                                                 .ToList()
                                                 .FindIndex(o => o == Convert.ToInt32(row[note.MappingKey]));

                                            //Recupero la ConditionFields che ha il nome che inizia con column.Id
                                            var campo = note.ConditionFields.FirstOrDefault(o => o.ToLower().StartsWith(column.Id.ToLower()));

                                            if (campo != null)
                                                astericoPresente = Convert.ToInt32(dataSourceInput.Rows[indiceRiga][campo]) == note.ConditionValue;

                                            if (astericoPresente)
                                            {
                                                if (string.IsNullOrEmpty(arrayAsterischiNote_Corpo[indiceRiga, indiceColonna]))
                                                    arrayAsterischiNote_Corpo[indiceRiga, indiceColonna] = TableNotePDF.ToAsteriskString(GetAsterisksNumber(note));
                                                else
                                                    arrayAsterischiNote_Corpo[indiceRiga, indiceColonna] += " " + TableNotePDF.ToAsteriskString(GetAsterisksNumber(note));
                                            }
                                            break;
                                    }

                                    indiceColonna++;
                                }
                            }
                        }

                        #endregion
                    }
                    else if (note.AsterisksPosition == TableNotePDF.TableNoteAsteriskPositionType.IntestazioneTabella)
                    {
                        #region Asterischi dell'intestazione della tabella

                        if (note.MappingFields != null)
                        {
                            // ToLower di tutti gli elementi memorizzati in ListIdColumnsAssociatedNote.
                            for (int i = 0; i < note.MappingFields.Length; i++)
                                note.MappingFields[i] = note.MappingFields[i].ToLower();

                            int indiceColonna = 0;

                            foreach (ColumnPDF column in element.Columns)
                            {
                                if (note.MappingFields.Contains(column.Id.ToLower()))
                                    arrayAsterischiNote_Intestazione[0, indiceColonna] = TableNotePDF.ToAsteriskString(GetAsterisksNumber(note));

                                indiceColonna++;
                            }
                        }

                        #endregion
                    }
                    else if (note.AsterisksPosition == TableNotePDF.TableNoteAsteriskPositionType.PieDiTabella)
                    {
                        #region Asterischi del footer della tabella

                        if (note.MappingFields != null)
                        {
                            // ToLower di tutti gli elementi memorizzati in ListIdColumnsAssociatedNote.
                            for (int i = 0; i < note.MappingFields.Length; i++)
                                note.MappingFields[i] = note.MappingFields[i].ToLower();

                            int indiceColonna = 0;

                            foreach (ColumnPDF column in element.FooterColumns)
                            {
                                if (note.MappingFields.Contains(column.Id.ToLower()))
                                    arrayAsterischiNote_PieDiPagina[0, indiceColonna] = TableNotePDF.ToAsteriskString(GetAsterisksNumber(note));

                                indiceColonna++;
                            }

                        }

                        #endregion
                    }

                }
                else
                {
                    if (note.AsterisksPosition == TableNotePDF.TableNoteAsteriskPositionType.CorpoTabella)
                    {
                        #region Asterischi del dettaglio della tabella

                        var rowNoteFooterTable = dataSourceInput.Select(note.Condition); //element.DataSource.Select(note.Condition);

                        if (rowNoteFooterTable.Length.Equals(0))
                        {
                            notesFooterTable.Remove(note); //Rimuovo le note che non trovano corrispondenza.
                            continue;
                        }

                        if (note.MappingFields != null)
                        {
                            // ToLower di tutti gli elementi memorizzati in ListIdColumnsAssociatedNote.
                            for (int i = 0; i < note.MappingFields.Length; i++)
                                note.MappingFields[i] = note.MappingFields[i].ToLower();

                            foreach (var row in rowNoteFooterTable)
                            {
                                int indiceColonna = 0;
                                int indiceRiga;

                                foreach (ColumnPDF column in element.Columns)
                                {
                                    switch (note.MappingType)
                                    {
                                        case TableNotePDF.TableNoteMappingType.Fisso:

                                            indiceRiga = dataSourceInput.Rows.IndexOf(row);

                                            if (note.MappingFields.Contains(column.Id.ToLower()))
                                            {
                                                if (string.IsNullOrEmpty(arrayAsterischiNote_Corpo[indiceRiga, indiceColonna]))
                                                    arrayAsterischiNote_Corpo[indiceRiga, indiceColonna] = TableNotePDF.ToNumberAsteriskString(GetAsterisksNumber(note));
                                                else
                                                    arrayAsterischiNote_Corpo[indiceRiga, indiceColonna] += " " + TableNotePDF.ToNumberAsteriskString(GetAsterisksNumber(note));
                                            }
                                            break;

                                        case TableNotePDF.TableNoteMappingType.Dinamico:
                                            bool astericoPresente = false;

                                            indiceRiga = new DataView(dataSourceInput).ToTable(false, new[] { note.MappingKey })
                                                 .AsEnumerable()
                                                 .Select(riga => riga.Field<Int32>(note.MappingKey))
                                                 .ToList()
                                                 .FindIndex(o => o == Convert.ToInt32(row[note.MappingKey]));

                                            //Recupero la ConditionFields che ha il nome che inizia con column.Id
                                            var campo = note.ConditionFields.FirstOrDefault(o => o.ToLower().StartsWith(column.Id.ToLower()));

                                            if (campo != null)
                                                astericoPresente = Convert.ToInt32(dataSourceInput.Rows[indiceRiga][campo]) == note.ConditionValue;

                                            if (astericoPresente)
                                            {
                                                if (string.IsNullOrEmpty(arrayAsterischiNote_Corpo[indiceRiga, indiceColonna]))
                                                    arrayAsterischiNote_Corpo[indiceRiga, indiceColonna] = TableNotePDF.ToNumberAsteriskString(GetAsterisksNumber(note));
                                                else
                                                    arrayAsterischiNote_Corpo[indiceRiga, indiceColonna] += " " + TableNotePDF.ToNumberAsteriskString(GetAsterisksNumber(note));
                                            }
                                            break;
                                    }

                                    indiceColonna++;
                                }
                            }
                        }

                        #endregion
                    }
                    else if (note.AsterisksPosition == TableNotePDF.TableNoteAsteriskPositionType.IntestazioneTabella)
                    {
                        #region Asterischi dell'intestazione della tabella

                        if (note.MappingFields != null)
                        {
                            // ToLower di tutti gli elementi memorizzati in ListIdColumnsAssociatedNote.
                            for (int i = 0; i < note.MappingFields.Length; i++)
                                note.MappingFields[i] = note.MappingFields[i].ToLower();

                            int indiceColonna = 0;

                            foreach (ColumnPDF column in element.Columns)
                            {
                                if (note.MappingFields.Contains(column.Id.ToLower()))
                                    arrayAsterischiNote_Intestazione[0, indiceColonna] = TableNotePDF.ToNumberAsteriskString(GetAsterisksNumber(note));

                                indiceColonna++;
                            }
                        }

                        #endregion
                    }
                    else if (note.AsterisksPosition == TableNotePDF.TableNoteAsteriskPositionType.PieDiTabella)
                    {
                        #region Asterischi del footer della tabella

                        if (note.MappingFields != null)
                        {
                            // ToLower di tutti gli elementi memorizzati in ListIdColumnsAssociatedNote.
                            for (int i = 0; i < note.MappingFields.Length; i++)
                                note.MappingFields[i] = note.MappingFields[i].ToLower();

                            int indiceColonna = 0;

                            foreach (ColumnPDF column in element.FooterColumns)
                            {
                                if (note.MappingFields.Contains(column.Id.ToLower()))
                                    arrayAsterischiNote_PieDiPagina[0, indiceColonna] = TableNotePDF.ToNumberAsteriskString(GetAsterisksNumber(note));

                                indiceColonna++;
                            }

                        }

                        #endregion
                    }
                }
            }

            #endregion

            #region Recupero le altezze di ogni riga e popolo la rowsHeightList

            float rowHeight;  // altezza calcolata della riga corrente;
            foreach (DataRow dr in element.DataSource.Rows)
            {
                rowHeight = element.RowHeight;  // altezza calcolata della riga corrente;
                columnIndex = 0;

                foreach (DataColumn dc in element.DataSource.Columns)
                {
                    var testoCella = string.Format("{0}{1}", dr[dc], arrayAsterischiNote_Corpo[rowIndex, columnIndex] ?? string.Empty);
                    var fontBold = false;

                    if (element.DataSource.Columns.Contains("FontBold"))
                        fontBold = Convert.ToBoolean(dr["FontBold"]);

                    float tempRowHeight = GetTextHeigth(testoCella,
                        element.Columns[columnIndex].Width - element.Columns[columnIndex].PaddingLeft,
                        element.Columns[columnIndex].FontSize,
                        fontBold,
                        element.Columns[columnIndex].TipoColonna); // altezza calcolata della riga corrente;

                    rowHeight = tempRowHeight > rowHeight ? tempRowHeight : rowHeight;

                    if (element.MinimumRowHeight > 0)
                        rowHeight = rowHeight < element.MinimumRowHeight ? element.MinimumRowHeight : rowHeight;

                    columnIndex++;
                }
                if (element.SpecifiedRowHeights.Count > rowIndex)
                {
                    rowHeight = element.SpecifiedRowHeights[rowIndex];
                }


                //Aggiungo alla lista
                rowsHeightList.Add(rowHeight);
                rowIndex++;
            }

            rowIndex = 0;
            columnIndex = 0;

            #endregion

            float y = element.Y;
            float yTextToPrint = y + variabileAltezzaTabellaPerPresenzaNote;
            float xTextToPrint;

            bool autoincrementY = true;
            bool printedTitleRow = false; // il title row di una tabella deve essere stampato una sola volta, anche se la tabella effettuta un salto pagina
            _printinginnewpage = true;

            #region Stampo l'Header della tabella se sono state rese invisibili tutte le righe del datasource

            if (numeroRigheInvisibili == numeroRigheTotali) // in questo caso devo stampare comunque l'header della tabella.
            {
                TablePDF_DrawHeader(element, arrayAsterischiNote_Intestazione);
                y = _ywritable;
                y += element.HeaderHeight + element.HeaderMargin;
            }

            #endregion
            foreach (DataRow dr in element.DataSource.Rows) // Scorro tutte le righe del DataSource
            {
                float x = element.X;

                if (element.Y > YLowerLimit)
                    _ywritable = YUpperLimit;

                // --- Patryk: RowsIndexesThatCantEndPage
                // Ernesto Usare questo per Salto Pagina
                if (element.RowsIndexesThatCantEndPage.Count() > 0 &&
                    element.RowsIndexesThatCantEndPage.Contains(rowIndex) &&
                    yTextToPrint > element.RowsIndexesThatCantEndPageYLimit &&
                    element.RowsIndexesThatCantEndPageYLimit != 0)

                //if (element.RowsIndexesThatCantEndPage.Count() > 0 && 
                //    element.RowsIndexesThatCantEndPage.Contains(rowIndex) &&
                //    _ywritable > element.RowsIndexesThatCantEndPageYLimit &&
                //    element.RowsIndexesThatCantEndPageYLimit != 0)
                {
                    WriteElement(new LinePDF(element.X, y, element.X + element.Width, y, 0.5F, new ColorPDF(153, 148, 133))); // lineaOrizzontale 

                    WriteNoteFooterPage(notesFooterPage);
                    TablePDF_ContinuedOnNextPage();
                }
                // ---------------------------------------

                #region Recupero altezza massima della riga corrente e quella successiva (necessario per il salto pagina)

                rowHeight = rowsHeightList[rowIndex];

                float nextRowHeight = rowIndex == rowsHeightList.Count - 1 ? 0 : rowsHeightList[rowIndex + 1]; // altezza temporanea della riga successiva;              

                #endregion

                #region Salto pagina su ultime 2 righe della tabella

                // Se sto per stampare le ultime 2 righe, e la tabella contiene un footer, controllo che 
                // il footer sia contenuto comunque nella pagina corrente, altrimenti ne aggiungo 1 e
                // gli elementi restanti (2 righe + footer) vengono stampati nella nuova pagina.
                // Considero anche la possibilità che la tabella abbia note aggiuntive sotto al footer                
                float variabilePerPresenzaTitleRow = 0;
                float variabilePerPresenzaFooterDatasource = 0;

                if (rowIndex == element.DataSource.Rows.Count - 2 &&
                    element.Footer &&
                    element.PageBreak)
                {
                    //variabileAltezzaTabellaPerPresenzaNota = 10 * notesFooterTable.Count;
                    variabilePerPresenzaTitleRow = element.TitleRow ? element.TitleRowHeight + element.TitleRowSpace : 0;
                    variabilePerPresenzaFooterDatasource = element.FooterDatasource != null ? element.FooterHeight * element.FooterDatasource.Rows.Count : element.FooterHeight;

                    if (y + (rowHeight + nextRowHeight) + variabilePerPresenzaFooterDatasource + variabileAltezzaTabellaPerPresenzaNote + variabilePerPresenzaTitleRow + 10 > YLowerLimit) //+ 10: ulteriore margine di sicurezza per evitare sforamenti
                    {
                        if (element.ShowBorderLastLineInPageBreak)
                            WriteElement(new LinePDF(element.X, y, element.X + element.Width, y, 0.5F, new ColorPDF(153, 148, 133))); // lineaOrizzontale 

                        _ywritable = YLowerLimit;

                        // Controllo qui se la tabella ha solamente 2 righe. 
                        // In tal caso non disegno ne le note nel footer ne il salto pagina ma vado direttamente a pagina nuova.
                        if (!element.DataSource.Rows.Count.Equals(2))
                        {
                            WriteNoteFooterPage(notesFooterPage);
                            TablePDF_ContinuedOnNextPage();
                        }

                        y = _ywritable;
                        element.Y = y;
                        rowIndexPerPage = -1;
                    }
                }

                #endregion

                #region Disegno il TitleRow ( Titolo sopra l'Header della tabella )

                if (element.TitleRow && _printinginnewpage && printedTitleRow == false)
                {
                    if (_reportEnvironment.ReportType == ReportType.Base_Proposta)
                    {
                        printedTitleRow = TablePDF_DrawTitleRow(element);
                        y = _ywritable;
                    }
                    else
                    {
                        printedTitleRow = TablePDF_DrawTitleRow(element, true);
                        y = _ywritable;// +element.TitleRowHeight;
                    }
                }

                #endregion

                #region Disegno dell'Header della tabella

                if (element.Header && _printinginnewpage)
                {
                    TablePDF_DrawHeader(element, arrayAsterischiNote_Intestazione);
                    y = _ywritable;
                    y += element.HeaderHeight + element.HeaderMargin;
                }
                #endregion

                #region Disegno il BorderContent

                if (element.ShowBorderContent)
                {
                    if (rowIndex == 0) // Disegno il bordo sulla prima riga
                    {
                        if (element.ShowBorderFooter)
                        {
                            //bordoSuperiore
                            WriteElement(new LinePDF(element.X - 1, ((element.X - 1) + element.Width + 1)) { AutoIncrementYWritable = false, DeltaY = -1 });

                            //bordoSuperioreSinistro
                            WriteElement(new LinePDF(element.X - 1, element.X - 1) { AutoIncrementYWritable = false, DeltaY2ForVerticalLine = 10 });

                            //bordoSuperioreDestro
                            WriteElement(new LinePDF((element.X - 1) + (element.Width + 1) + 1, (element.X - 1) + (element.Width + 1) + 1) { AutoIncrementYWritable = false, DeltaY2ForVerticalLine = 10 });

                        }
                    }
                    else if (rowIndex == element.DataSource.Rows.Count - 1) // Disegno il bordo sull'ultima riga
                    {
                        //bordoInferiore
                        WriteElement(new LinePDF(element.X - 1, y + rowHeight, ((element.X - 1) + element.Width + 1), y + rowHeight) { AutoIncrementYWritable = false, DeltaY = -1 });

                        //bordoInferioreSinistro
                        WriteElement(new LinePDF(element.X - 1, y + rowHeight, element.X - 1, y + rowHeight) { AutoIncrementYWritable = false, DeltaY2ForVerticalLine = -10 });

                        //bordoInferioreDestro
                        WriteElement(new LinePDF((element.X - 1) + (element.Width + 1) + 1, y + rowHeight, (element.X - 1) + (element.Width + 1) + 1, y + rowHeight) { AutoIncrementYWritable = false, DeltaY2ForVerticalLine = -10 });

                    }
                }

                #endregion


                // -start
                foreach (DataColumn dc in element.DataSource.Columns) // Scorro tutte le colonne del DataSource
                {
                    // Il testo della cella è recuperato dalla relativa colonna del DataSource
                    var testoCella = string.Format("{0}{1}", dr[dc], arrayAsterischiNote_Corpo[rowIndex, columnIndex] ?? string.Empty);

                    // Recupero il testo della cella dalla collezione Cells se specificato un value.
                    if (!string.IsNullOrEmpty(element.Cells[columnIndex, rowIndex].Value))
                        testoCella = element.Cells[columnIndex, rowIndex].Value;

                    #region Gestione del ColSpan della cella e ridefinizione della larghezza della colonna.

                    if (element.Cells[columnIndex, rowIndex].ColSpan > 0)
                    {
                        int countcolumnspan = element.Cells[columnIndex, rowIndex].ColSpan;//quante colonne compongono il colspan inclusa la cella che ha la proprietà

                        if ((columnIndex + countcolumnspan) > element.Columns.Count)
                            throw new Exception("TablePDF: ColSpan non può essere maggiore del numero di colonne");

                        for (int f = 1; f < countcolumnspan; f++)
                        {
                            //aumento la larghezza della colonna corrente (columnIndex) con la somma delle altre colonne interessate da colspan
                            element.Columns[columnIndex].Width += element.Columns[columnIndex + f].Width;

                            // Azzero tutte le restanti interessate dal colspan
                            element.Columns[columnIndex + f].Width = 0;
                            element.Columns[columnIndex + f].Visibile = false;
                        }
                    }
                    #endregion

                    #region Allineamento orizzontale

                    // Allineamento preso a livello di colonna
                    var textHorizontalAlign = GetTextAlign(element.Columns[columnIndex].HorizontalAlignment);

                    // Allineamento preso a livello di cella
                    if (element.Cells[columnIndex, rowIndex].HorizontalAlignment != HorizontalAlignmentType.Nonimpostato)
                        textHorizontalAlign = GetTextAlign(element.Cells[columnIndex, rowIndex].HorizontalAlignment);

                    #endregion

                    #region Allineamento verticale e recupero della Y su cui scrivere la riga

                    switch (element.Columns[columnIndex].VerticalAlignment)
                    {
                        case VerticalAlignmentType.Alto:
                            yTextToPrint = y + element.Columns[columnIndex].DeltaYContent;
                            break;

                        case VerticalAlignmentType.Basso:
                            yTextToPrint = y + rowHeight - element.Columns[columnIndex].FontSize;
                            break;

                        case VerticalAlignmentType.Centrato:

                            var fontBold = false;

                            if (element.DataSource.Columns.Contains("FontBold"))
                                fontBold = Convert.ToBoolean(dr["FontBold"]);

                            float textHeight = GetTextHeigth(
                                testoCella,
                                element.Columns[columnIndex].Width - element.Columns[columnIndex].PaddingLeft,
                                element.Columns[columnIndex].FontSize,
                                fontBold,
                                element.Columns[columnIndex].TipoColonna);

                            float delta = textHeight == 0 ? 0 : rowHeight - textHeight;

                            yTextToPrint = y + (delta / 2) + element.Columns[columnIndex].DeltaYContent; // + incrementWidthSeparationLines;
                            break;
                    }

                    #endregion

                    var colorRectangleBackground = ColorPDF.Bianco; // Bianco di default

                    #region BackgroundGray della riga

                    if (element.Row[rowIndex].BackgroundColor != null)
                        colorRectangleBackground = element.Row[rowIndex].BackgroundColor;

                    if (element.Row[rowIndex].BackgroundGray)
                        colorRectangleBackground = ColorPDF.Standard_Grigio_SfondoColonnaTabella;

                    // Disegno lo sfondo grigio se impostata la proprietà BackgroundGray dell'oggetto Row. 
                    if (element.Row[rowIndex].BackgroundGray || element.Row[rowIndex].BackgroundColor != null)
                        WriteElement(new RectanglePDF(x, y, rowHeight + element.RowsPadding, element.Columns[columnIndex].Width, colorRectangleBackground) { AutoIncrementYWritable = false }); // x+1 per evitare che il riquadro grigio copra il testo

                    #endregion

                    //start2
                    #region BackgroundGray e BackgroundColor della colonna
                    // Aggiungo un rettangolo di sfondo (BackgroundGray o BackgroundColor) della COLONNA.
                    if (element.Columns[columnIndex].BackgroundGray || element.Columns[columnIndex].BackgroundColor != null)
                    {
                        colorRectangleBackground = element.Columns[columnIndex].BackgroundColor;

                        if (element.Columns[columnIndex].BackgroundGray)
                            colorRectangleBackground = ColorPDF.Standard_Grigio_SfondoColonnaTabella;
                        RectanglePDF rectangleBackground = null;
                        if (element.WhiteSpacesHorizontalSeparator)
                        {
                            rectangleBackground = new RectanglePDF(x, y, rowHeight - 3, element.Columns[columnIndex].Width, colorRectangleBackground) { AutoIncrementYWritable = false };
                        }
                        else
                        {
                            rectangleBackground = new RectanglePDF(x, y, rowHeight, element.Columns[columnIndex].Width, colorRectangleBackground) { AutoIncrementYWritable = false };
                        }

                        // Se è impostato un BackgroundColor sulla colonna, rectangleBackground avrà Height pari a Height + RowsPadding, 
                        // in modo da riempire completamente la colonna senza lasciare spazi bianchi.
                        if (element.Columns[columnIndex].BackgroundColor != null)
                        {
                            rectangleBackground.Height += element.RowsPadding + 1;
                        }
                        rectangleBackground.Height += element.RowsHeightOffset;
                        if (!element.RowsIndexesThatIgnoreColumnBackgroundColor.Contains(rowIndex))
                        {
                            WriteElement(rectangleBackground);
                        }
                    }
                    #endregion

                    #region BackgroundGray e BackgroundColor della cella
                    // Aggiungo un rettangolo di sfondo (BackgroundColor) della CELLA.
                    if (element.Cells[columnIndex, rowIndex].BackgroundColor != null)
                    {
                        colorRectangleBackground = element.Cells[columnIndex, rowIndex].BackgroundColor;
                        RectanglePDF rectangleBackground = null;
                        if (element.WhiteSpacesHorizontalSeparator)
                        {
                            // Quando è impostato un BackgroundColor sulla riga, rectangleBackground avrà Height pari a Height + RowsPadding, 
                            // in modo da riempire completamente la riga senza lasciare spazi bianchi.                        
                            rectangleBackground = new RectanglePDF(x, y, rowHeight + element.RowsPadding - 1, element.Columns[columnIndex].Width, colorRectangleBackground) { AutoIncrementYWritable = false };
                            var rectangleWhiteSpace = new RectanglePDF(x, y + rectangleBackground.Height, 1, element.Columns[columnIndex].Width, new ColorPDF(255, 255, 255)) { AutoIncrementYWritable = true };
                            WriteElement(rectangleBackground);
                            WriteElement(rectangleWhiteSpace);
                        }
                        else
                        {
                            rectangleBackground = new RectanglePDF(x, y, rowHeight + element.RowsPadding + element.RowsHeightOffset + (element.RowsHeightOffset != 0 ? +1 : 0), element.Columns[columnIndex].Width, colorRectangleBackground) { AutoIncrementYWritable = false };
                            WriteElement(rectangleBackground);
                        }

                    }
                    #endregion
                    //end2


                    #region Disegno cella

                    // Disegno la cella. La cella è una FormattedTextAreaPDF
                    if (element.Columns[columnIndex].Visibile)
                    {

                        if ((element.Columns[columnIndex].TipoColonna == ColumnType.Testo ||
                           element.Columns[columnIndex].TipoColonna == ColumnType.Decimale ||
                           element.Columns[columnIndex].TipoColonna == ColumnType.Intero ||
                           element.Columns[columnIndex].TipoColonna == ColumnType.Percentuale) &&
                           !(dr[dc].ToString().ToLower().Contains("flags") && dr[dc].ToString().ToLower().Contains(".png")))
                        {
                            #region TIPO DI COLONNA TESTO o DECIMALE o INTERO o PERCENTUALE

                            // FormattedTextAreaPDF testo della singola cella. 
                            var textToPrint = new FormattedTextAreaPDF();
                            var fontColor = ColorPDF.Nero;

                            switch (element.Style)
                            {
                                case Style.ConsulenzaBase:
                                case Style.ConsulenzaUnica:
                                    fontColor = ColorPDF.Nero;
                                    break;
                                case Style.Immobiliare:
                                    fontColor = ColorPDF.Immobiliare_Grigio_TestoStandard; // Grigio
                                    break;
                                default:
                                    break;
                            }

                            bool fontBold = false;
                            var fontSize = 0F;
                            bool forcestylerow_fontbold = false;
                            bool forcestylerow_fontcolor = false;
                            bool forcestylecolumn_fontbold = false;
                            bool forcestylecolumn_fontcolor = false;

                            #region Attributi FontSize, FontBold, FontColor della RIGA

                            if (element.Row != null)
                            {
                                if (element.Row[rowIndex].FontBold.HasValue) // grassetto dell'intera riga (se specificato)
                                    fontBold = element.Row[rowIndex].FontBold.Value;

                                if (element.Row[rowIndex].FontColor != null) // colore dell'intera riga (se specificato)
                                    fontColor = element.Row[rowIndex].FontColor;

                                forcestylerow_fontbold = element.Row[rowIndex].ForceStyleFontBold;
                                forcestylerow_fontcolor = element.Row[rowIndex].ForceStyleFontColor;
                            }

                            #endregion

                            #region Attributi FontSize, FontBold, FontColor della COLONNA

                            forcestylecolumn_fontbold = element.Columns[columnIndex].ForceStyleFontBold;
                            forcestylecolumn_fontcolor = element.Columns[columnIndex].ForceStyleFontColor;

                            if (!forcestylerow_fontcolor || forcestylecolumn_fontcolor)
                            {
                                if (element.Columns[columnIndex].FontColor != null)
                                    fontColor = element.Columns[columnIndex].FontColor;
                            }

                            if (!forcestylerow_fontbold || forcestylecolumn_fontbold)
                            {
                                if (element.Columns[columnIndex].FontBold.HasValue)
                                    fontBold = element.Columns[columnIndex].FontBold.Value;
                            }

                            #endregion

                            #region Attributi FontSize, FontBold, FontColor della CELLA

                            fontSize = element.Columns[columnIndex].FontSize; // eredito quello della colonna.                           

                            if (!forcestylerow_fontcolor)
                            {
                                if (element.Cells[columnIndex, rowIndex].FontColor != null)
                                    fontColor = element.Cells[columnIndex, rowIndex].FontColor;
                            }

                            if (!forcestylerow_fontbold)
                            {
                                if (element.Cells[columnIndex, rowIndex].FontBold.HasValue)
                                    fontBold = element.Cells[columnIndex, rowIndex].FontBold.Value;
                            }

                            #endregion

                            // Testo della singola cella.
                            var stringTextToPrint = string.Empty;

                            switch (element.Columns[columnIndex].TipoColonna)
                            {
                                case ColumnType.Testo:
                                    stringTextToPrint = testoCella;
                                    if (element.Cells[columnIndex, rowIndex].ReplaceIfZero != string.Empty)
                                        if (testoCella.Equals("0,00"))
                                            stringTextToPrint = testoCella.Replace("0,00", element.Cells[columnIndex, rowIndex].ReplaceIfZero);
                                    break;
                                case ColumnType.Decimale:
                                    stringTextToPrint = element.Cells[columnIndex, rowIndex].ReplaceIfZero != string.Empty
                                   ? Convert.ToDecimal(testoCella).Equals(0) ? element.Cells[columnIndex, rowIndex].ReplaceIfZero : Helper.FormatCurrency(testoCella)
                                   : Helper.FormatCurrency(testoCella);
                                    break;
                                case ColumnType.Intero:
                                    stringTextToPrint = element.Cells[columnIndex, rowIndex].ReplaceIfZero != string.Empty
                                   ? Convert.ToDecimal(testoCella).Equals(0) ? element.Cells[columnIndex, rowIndex].ReplaceIfZero : Helper.FormatInteger(testoCella)
                                   : Helper.FormatInteger(testoCella);
                                    break;
                                case ColumnType.Percentuale:
                                    stringTextToPrint = Helper.FormatPercentage(testoCella, 2);
                                    break;
                            }

                            // Incremento della X a livello di Colonna. 
                            // Se è impostato un allineamento a livello di Cella, l'incremento viene fatto solo se tale allineamento è Nonimpostato oppure Sinistra. 
                            if (element.Cells[columnIndex, rowIndex].HorizontalAlignment == HorizontalAlignmentType.Nonimpostato ||
                                element.Cells[columnIndex, rowIndex].HorizontalAlignment == HorizontalAlignmentType.Sinistra)
                                xTextToPrint = TablePDF_GetXTextContent(x + element.Columns[columnIndex].PaddingLeft, columnIndex, element);
                            else
                                xTextToPrint = x + element.Columns[columnIndex].PaddingLeft;

                            xTextToPrint += element.Cells[columnIndex, rowIndex].XContentOffset;

                            textToPrint = new FormattedTextAreaPDF(stringTextToPrint,
                                xTextToPrint,
                                element.Columns[columnIndex].Width - element.Columns[columnIndex].PaddingLeft - element.Columns[columnIndex].PaddingRight,
                                textHorizontalAlign)
                            {
                                Y = yTextToPrint + element.Cells[columnIndex, rowIndex].YContentOffset,
                                FontSize = fontSize,
                                FontColor = fontColor,
                                FontBold = fontBold,
                                AutoIncrementYWritable = autoincrementY
                            };

                            //Scrivo il testo.
                            WriteElement(textToPrint);

                            #endregion
                        }
                        else if (element.Columns[columnIndex].TipoColonna == ColumnType.Immagine ||
                            (dr[dc].ToString().ToLower().Contains("flags") && dr[dc].ToString().ToLower().Contains(".png")))
                        {
                            #region TIPO DI COLONNA IMMAGINE

                            ImagePDF imageToPrint;
                            if (dr[dc].ToString() != string.Empty)
                            {
                                #region Allineamento orizzontale dell'immagine

                                float xImmagine = x;

                                Align imageAlignX;
                                switch (textHorizontalAlign)
                                {
                                    case TextAlign.Center:
                                        imageAlignX = Align.Center;
                                        xImmagine = xImmagine + (element.Columns[columnIndex].Width / 2);
                                        break;
                                    case TextAlign.Left:
                                        imageAlignX = Align.Left;
                                        break;
                                    case TextAlign.Right:
                                        imageAlignX = Align.Right;
                                        xImmagine = xImmagine + element.Columns[columnIndex].Width;
                                        break;
                                    default:
                                        imageAlignX = Align.Left;
                                        break;
                                }
                                #endregion

                                

                                xTextToPrint = xImmagine + element.Columns[columnIndex].PaddingLeft;
                                imageToPrint = new ImagePDF(TablePDF_GetXTextContent(xTextToPrint, columnIndex, element), element.Columns[columnIndex].ScaleColumnTypeImage, dr[dc].ToString(), imageAlignX, yTextToPrint + element.Columns[columnIndex].PaddingTopImage);

                                //float deltaYOffset = 0;
                                //switch (element.Columns[columnIndex].VerticalAlignment)
                                //{
                                //    case VerticalAlignmentType.Centrato:
                                //        var testElement = new Image(imageToPrint.Path, 0, 0, imageToPrint.Scale);
                                //        deltaYOffset = (rowHeight - testElement.Height) / 2;
                                //        break;
                                //}
                                //imageToPrint.DeltaY += deltaYOffset;
                                WriteElement(imageToPrint);
                            }

                            #endregion
                        }
                        else if (element.Columns[columnIndex].TipoColonna == ColumnType.Objectpdf)
                        {
                            #region TIPO DI COLONNA OBJECTPDF

                            var itemsList = element.Cells[columnIndex, rowIndex].ValueObjectList;

                            if (!itemsList.Any())
                                if (element.Cells[columnIndex, rowIndex].ValueObject != null)
                                    itemsList.Add(element.Cells[columnIndex, rowIndex].ValueObject);

                            // Disegno l'oggetto PDF associato alla proprietà ValuePDF dell'oggetto Cella ( RectanglePDF o CirclePDF ).
                            // Per ora si possono aggiungere solo RectanglePDF, CirclePDF, FormattedTextAreaPDF se dovesse esserci necessità andrà migliorata la funzionalità.
                            if (itemsList.Any())
                            {
                                foreach (var item in itemsList)
                                {
                                    var parameterType = item.GetType();
                                    string name = parameterType.Name;

                                    switch (name.ToLower())
                                    {
                                        case "rectanglepdf":
                                            {
                                                var rectToPrint = (RectanglePDF)item;

                                                #region Allineamento orizzontale

                                                var xObjectPdf = 0F;

                                                switch (element.Columns[columnIndex].HorizontalAlignment)
                                                {
                                                    case HorizontalAlignmentType.Nonimpostato:
                                                    case HorizontalAlignmentType.Sinistra:
                                                        xObjectPdf = x + element.Columns[columnIndex].PaddingLeft;
                                                        break;
                                                    case HorizontalAlignmentType.Centrato:
                                                        xObjectPdf = ((x + element.Columns[columnIndex].Width / 2) - (rectToPrint.Width / 2)) + element.Columns[columnIndex].PaddingLeft;
                                                        break;
                                                    case HorizontalAlignmentType.Destra:
                                                        xObjectPdf = x + element.Columns[columnIndex].Width - rectToPrint.Width;
                                                        break;
                                                }

                                                #endregion

                                                rectToPrint.X = xObjectPdf;
                                                rectToPrint.X += rectToPrint.DeltaX;
                                                rectToPrint.Y = yTextToPrint + rectToPrint.DeltaY;
                                                rectToPrint.AutoIncrementYWritable = false;
                                                WriteElement(rectToPrint);
                                            }
                                            break;
                                        case "circlepdf":
                                            {
                                                var circleToPrint = (CirclePDF)item;

                                                #region Allineamento orizzontale

                                                var xObjectPdf = 0F;

                                                switch (element.Columns[columnIndex].HorizontalAlignment)
                                                {
                                                    case HorizontalAlignmentType.Nonimpostato:
                                                    case HorizontalAlignmentType.Sinistra:
                                                        xObjectPdf = x + element.Columns[columnIndex].PaddingLeft;
                                                        break;
                                                    case HorizontalAlignmentType.Centrato:
                                                        break;
                                                    case HorizontalAlignmentType.Destra:
                                                        xObjectPdf = x + element.Columns[columnIndex].Width - circleToPrint.Width;
                                                        break;
                                                }

                                                #endregion

                                                circleToPrint.X = xObjectPdf;
                                                circleToPrint.Y = yTextToPrint + circleToPrint.DeltaY;
                                                circleToPrint.AutoIncrementYWritable = false;
                                                WriteElement(circleToPrint);
                                            }
                                            break;
                                        case "formattedtextareapdf":
                                            {
                                                var formattedtextareaToPrint = (FormattedTextAreaPDF)item;

                                                #region Allineamento orizzontale

                                                var xObjectPdf = 0F;

                                                switch (element.Columns[columnIndex].HorizontalAlignment)
                                                {
                                                    case HorizontalAlignmentType.Nonimpostato:
                                                    case HorizontalAlignmentType.Sinistra:
                                                        xObjectPdf = x + element.Columns[columnIndex].PaddingLeft;
                                                        break;
                                                    case HorizontalAlignmentType.Centrato:
                                                        break;
                                                    case HorizontalAlignmentType.Destra:
                                                        xObjectPdf = x + element.Columns[columnIndex].Width - formattedtextareaToPrint.Width;
                                                        break;
                                                }

                                                #endregion

                                                formattedtextareaToPrint.X = xObjectPdf;
                                                formattedtextareaToPrint.Y = yTextToPrint + formattedtextareaToPrint.DeltaY;
                                                formattedtextareaToPrint.AutoIncrementYWritable = false;
                                                WriteElement(formattedtextareaToPrint);
                                            }
                                            break;
                                        case "imagepdf":
                                            {
                                                var imageToPrint = (ImagePDF)item;

                                                #region Allineamento orizzontale

                                                var xObjectPdf = 0F;

                                                switch (element.Columns[columnIndex].HorizontalAlignment)
                                                {
                                                    case HorizontalAlignmentType.Nonimpostato:
                                                    case HorizontalAlignmentType.Sinistra:
                                                        xObjectPdf = x + element.Columns[columnIndex].PaddingLeft;
                                                        break;
                                                    case HorizontalAlignmentType.Centrato:
                                                        xObjectPdf = ((x + element.Columns[columnIndex].Width / 2) - (imageToPrint.Width / 2)) + element.Columns[columnIndex].PaddingLeft;
                                                        break;
                                                    case HorizontalAlignmentType.Destra:
                                                        xObjectPdf = x + element.Columns[columnIndex].Width - imageToPrint.Width;
                                                        break;
                                                }

                                                #endregion

                                                imageToPrint.X = xObjectPdf;
                                                imageToPrint.X += imageToPrint.DeltaX;
                                                imageToPrint.Y = yTextToPrint + imageToPrint.DeltaY;
                                                imageToPrint.AutoIncrementYWritable = false;
                                                WriteElement(imageToPrint);
                                            }
                                            break;
                                    }
                                }

                            }

                            #endregion
                        }


                        #region Linee di separazione delle righe (ShowSeparationLines)

                        if (element.ShowSeparationLines)
                        {
                            if (!element.IndexesOfSeparatorsToIgnore.Contains(columnIndex))
                            {
                                if (!element.IndexesOfRowLinesToIgnoreSeparators.Contains(rowIndex))
                                {
                                    var colorSeparationLine = element.Columns[columnIndex].BackgroundGray ? ColorPDF.Bianco : ColorPDF.Standard_Grigio_SfondoColonnaTabella;
                                    if (element.Cells[columnIndex, rowIndex].HorizontalSeparatorColor != null)
                                    {
                                        colorSeparationLine = element.Cells[columnIndex, rowIndex].HorizontalSeparatorColor;
                                    }
                                    // linea separatrice                           
                                    var separationLine = new RectanglePDF(x, y + rowHeight, element.WidthSeparationLines, element.Columns[columnIndex].Width, colorSeparationLine) { AutoIncrementYWritable = false };

                                    if (y < YLowerLimit)
                                    {
                                        if (element.HideLastSeparationLine)
                                        {
                                            // Non viene disegnata la linea di separazione all'ultima riga
                                            if (rowIndex != element.DataSource.Rows.Count - 1)
                                                WriteElement(separationLine);
                                        }
                                        else if (element.HideFirstSeparationLine)
                                        {
                                            if (rowIndex != 0)
                                                WriteElement(separationLine);
                                        }
                                        else
                                            WriteElement(separationLine);
                                    }
                                }
                            }
                        }

                        #endregion

                        #region Border della riga

                        // Disegno una riga in alto e una in basso che fanno da bordo alla riga
                        if (element.Row[rowIndex].Border)
                        {
                            bool drawBorder = !element.Row[rowIndex].ShowBorderInColumnImage == false && element.Columns[columnIndex].TipoColonna == ColumnType.Immagine;

                            if (drawBorder)
                            {
                                var colorBorderLine = ColorPDF.Nero;
                                switch (element.Style)
                                {
                                    case Style.ConsulenzaBase:
                                    case Style.ConsulenzaUnica:
                                        colorBorderLine = ColorPDF.Nero;
                                        break;
                                    case Style.Immobiliare:
                                        colorBorderLine = ColorPDF.Immobiliare_Grigio_TitoloPiccolo;
                                        break;
                                    default:
                                        break;
                                }

                                if (element.Columns[columnIndex].BackgroundGray || element.Columns[columnIndex].BackgroundColor != null)
                                    colorBorderLine = ColorPDF.Bianco; //Bianco

                                if (element.Row[rowIndex].BorderType == BorderRowType.Entrambi || element.Row[rowIndex].BorderType == BorderRowType.Alto)
                                {
                                    // Linea superiore
                                    if (rowIndexPerPage > 0) // la prima riga, essendo poco stotto la linea di chiusura della header della tabella, non viene disegnata.
                                        WriteElement(new LinePDF(x, y - element.RowsPadding / 2, (float)(x + element.Columns[columnIndex].Width), y - element.RowsPadding / 2, 0.1F, colorBorderLine) { AutoIncrementYWritable = false });
                                }

                                if (element.Row[rowIndex].BorderType == BorderRowType.Entrambi || element.Row[rowIndex].BorderType == BorderRowType.Basso)
                                {
                                    //// Linea inferiore
                                    WriteElement(new LinePDF(x, y + rowHeight + (element.RowsPadding / 2), (float)(x + element.Columns[columnIndex].Width), y + rowHeight + (element.RowsPadding / 2), 0.1F, colorBorderLine) { AutoIncrementYWritable = false });
                                }
                            }
                        }

                        #endregion

                        x += element.Columns[columnIndex].Width;
                    }

                    #endregion

                    columnIndex++;
                    autoincrementY = false;
                }

                // -end

                columnIndex = 0;

                if (element.ID == "debug")
                    WriteElement(new LinePDF(element.X, y, element.X + element.Width, y, 1, ColorPDF.Rosso) { AutoIncrementYWritable = false });

                // ******************* INCREMENTO DELLA Y ***************************

                y += rowHeight + element.RowsPadding + (element.ShowSeparationLines ? element.WidthSeparationLines + 1 : 0);

                // ******************* FINE INCREMENTO DELLA Y **********************

                if (element.ID == "debug")
                    WriteElement(new LinePDF(element.X, y, element.X + element.Width, y, 1, ColorPDF.Giallo) { AutoIncrementYWritable = false });

                #region Salto pagina e Stampa delle Note associate alla tabella da stampare a piè di pagina

                #region Salto pagina forzato "CanLastRow"

                bool pageBreakForced = false;

                if (dataSourceInput != null && dataSourceInput.Columns.Contains("CanLastRow"))
                {
                    // indica se la prossima riga che sarà stampata può essere l'ultima.
                    var prossimaPuoEssereUltimaRiga = true;

                    if (rowIndex + 1 <= dataSourceInput.Rows.Count - 1)
                        prossimaPuoEssereUltimaRiga = Convert.ToBoolean(dataSourceInput.Rows[rowIndex + 1]["CanLastRow"]);

                    if (prossimaPuoEssereUltimaRiga == false)
                    {
                        // Se la prossima riga non può essere l'ultima nella pagina devo anticipare il salto pagina e renderlo "forzato". (pageBreakForced)
                        // Controllo dunque: 
                        // 1) la nextRowHeight abbia spazio a sufficienza per essere disegnata (*2 non è un calcolo corretto. Dovrei sapere quanto è alta la riga ancora successiva ma attualmente non è possibile.)
                        // 2) possibile salto pagina nel caso in cui le ultime 2 righe della tabella non entrino nella pagina corrente.

                        var altezzaProssimeRighe = rowsHeightList.Skip(rowIndex + 1).Take(2).Sum(); // Sommo l'altezza delle successive 2 righe (take 2) alla riga successiva a quella corrente (Skip rowIndex + 1)
                        var ySaltoPagina = y + altezzaProssimeRighe + variabilePerPresenzaFooterDatasource + variabileAltezzaTabellaPerPresenzaNote + variabilePerPresenzaTitleRow + 10;

                        pageBreakForced =
                            (ySaltoPagina > YLowerLimit) ||
                            ((rowIndex + 2 == element.DataSource.Rows.Count - 2) && ySaltoPagina + altezzaProssimeRighe > YLowerLimit);
                    }
                }

                #endregion

                // Verifico se l'altezza della prossima riga che dovrà essere scritta (nextRowHeight) supera il _ylowerlimit.
                // Se supera il limite aggiungo una nuova pagina al documento e il resto della tabella verrà disegnata nella nuova pagina.
                if ((y + nextRowHeight + 15 >= YLowerLimit && element.PageBreak) || pageBreakForced || 
                    (element.TableCantReachThisYPosition != 0 && y + nextRowHeight + 15 >= element.TableCantReachThisYPosition)) // +15 = spazio per scivere il testo di cambio pagina
                {
                    if (element.ShowBorderLastLineInPageBreak)
                        WriteElement(new LinePDF(element.X, y, element.X + element.Width, y, 0.5F, new ColorPDF(153, 148, 133))); // lineaOrizzontale 

                    if (element.ShowNotesFooterPageForAllPages)
                        WriteNoteFooterPage(notesFooterPage);

                    _ywritable = YLowerLimit;

                    // effettuo il saltopagina della tabella.
                    TablePDF_ContinuedOnNextPage();

                    y = _ywritable;
                    element.Y = y;
                    rowIndexPerPage = -1;
                }
                else if (rowIndex == element.DataSource.Rows.Count - 1) // sto stampando l'ultima riga e quindi stampo le Note associate alla tabella da stampare a piè di pagina
                {
                    WriteNoteFooterPage(notesFooterPage);
                    _ywritable = y;
                }

                #endregion

                #region Disegno il Border sull'ultima riga se richiesto e non è presente il footer

                if (element.ShowBorderLastLine && element.Footer == false && rowIndex == element.DataSource.Rows.Count - 1)
                {
                    switch (element.Style)
                    {
                        case Style.ConsulenzaBase:
                            WriteElement(new LinePDF(element.X, y, element.Width + element.X, y)); // lineaOrizzontale                         
                            WriteElement(new LinePDF(element.X, y, element.X, y) { DeltaY2ForVerticalLine = -10 }); //lineaVerticaleSinistra                         
                            WriteElement(new LinePDF(element.Width + element.X, y, element.Width + element.X, y) { DeltaY2ForVerticalLine = -10 }); // lineaVerticaleDestra
                            break;
                        case Style.Immobiliare:
                            WriteElement(new LinePDF(element.X, element.X + element.Width, 0.5F, new ColorPDF(153, 148, 133))); // lineaOrizzontale 
                            break;
                        case Style.ConsulenzaUnica:
                            WriteElement(new LinePDF(element.X, element.X + element.Width, 1F, ColorPDF.Standard_Grigio_SfondoColonnaTabella)); // lineaOrizzontale 
                            break;
                    }

                }
                else if (element.ShowBorderLastLine && element.Footer == true && rowIndex == element.DataSource.Rows.Count - 1)
                {
                    switch (element.Style)
                    {
                        case Style.ConsulenzaBase:
                            WriteElement(new LinePDF(element.X, y, element.Width + element.X, y)); // lineaOrizzontale                         
                            WriteElement(new LinePDF(element.X, y, element.X, y) { DeltaY2ForVerticalLine = -10 }); //lineaVerticaleSinistra                         
                            WriteElement(new LinePDF(element.Width + element.X, y, element.Width + element.X, y) { DeltaY2ForVerticalLine = -10 }); // lineaVerticaleDestra
                            break;
                        case Style.Immobiliare:
                            WriteElement(new LinePDF(element.X, element.X + element.Width, 0.5F, new ColorPDF(153, 148, 133))); // lineaOrizzontale 
                            break;
                        case Style.ConsulenzaUnica:
                            WriteElement(new SpacePDF(5));
                            WriteElement(new LinePDF(element.X, element.X + element.Width, 1F, ColorPDF.Standard_Grigio_SfondoColonnaTabella)); // lineaOrizzontale 
                            break;
                    }

                }
                #endregion

                #region Reset delle larghezza originale delle colonne. [Modificata se impostato ColSpan della Cella]

                int i = 0;
                foreach (var item in element.Columns)
                {
                    item.Width = columnsWidthOriginal[i];
                    item.Visibile = item.Width > 0 ? true : false;
                    i++;
                }

                #endregion

                rowIndex++;
                rowIndexPerPage++;
            }

            // Y iniziale su cui disegnare il testo del Footer
            yTextToPrint = y;

            #region Disegno il Footer della tabella.

            //#region Imposto il FooterDatasource

            if (element.FooterDatasource != null)
            {
                element.Footer = true;
                //var arrListFooter = new ArrayList();
                //foreach (ColumnPDF c in element.FooterColumns)
                //{
                //    switch (c.TipoColonna)
                //    {
                //        case ColumnType.Testo:
                //        case ColumnType.Decimale:
                //        case ColumnType.Intero:
                //        case ColumnType.Percentuale:
                //            if (!string.IsNullOrEmpty(c.Name))
                //                arrListFooter.Add(c.Name);
                //            break;

                //        case ColumnType.Immagine:
                //        case ColumnType.Objectpdf:
                //            if (!string.IsNullOrEmpty(c.Id))
                //                arrListFooter.Add(c.Id);
                //            break;
                //    }

                //    // Imposto la colonna a visible=false se la larghezza è pari a 0
                //    c.Visibile = c.Width != 0;
                //}
                //var strArrayFooter = (string[])arrListFooter.ToArray(typeof(string));

                //var columnsEmbeddedOrObject = element.FooterColumns.FindAll(col => col.TipoColonna == ColumnType.Objectpdf || (col.TipoColonna == ColumnType.Immagine && col.Name == string.Empty));

                //if (columnsEmbeddedOrObject.Count > 0)
                //{
                //    foreach (ColumnPDF column in columnsEmbeddedOrObject)
                //        element.DataSource.Columns.Add(column.Id);
                //}

                //// imposto il datasource
                //element.DataSource = element.DataSource.DefaultView.ToTable(false, strArrayFooter);

                //if (columnsEmbeddedOrObject.Count > 0)
                //{
                //    for (int nColonna = 0; nColonna < element.FooterColumns.Count; nColonna++)
                //    {
                //        if (!string.IsNullOrEmpty(element.FooterCells[nColonna, 0].Value))
                //            element.DataSource.Rows[0][nColonna] = element.FooterCells[nColonna, 0].Value;
                //    }
                //}
            }
            else
            {
                var footerDatasource = new DataTable();
                for (int i = 0; i < element.FooterColumns.Count(); i++)
                {
                    Type typeFooterColumn = typeof(string);

                    switch (element.FooterColumns[i].TipoColonna)
                    {
                        case ColumnType.Decimale:
                        case ColumnType.Intero:
                            typeFooterColumn = typeof(decimal);
                            break;
                        case ColumnType.Immagine:
                            typeFooterColumn = typeof(string);
                            break;
                        case ColumnType.Objectpdf:
                            typeFooterColumn = typeof(ImagePDF);
                            break;
                        default:
                            typeFooterColumn = typeof(string);
                            break;
                    }
                    footerDatasource.Columns.Add(element.FooterColumns[i].Id, typeFooterColumn);
                }

                var rowFooterDatasource = footerDatasource.NewRow();
                for (int i = 0; i < element.FooterColumns.Count(); i++)
                {
                    if (element.FooterCells[i, 0] != null)
                        rowFooterDatasource[i] = element.FooterCells[i, 0].Value;
                }
                footerDatasource.Rows.Add(rowFooterDatasource);

                element.FooterDatasource = footerDatasource;
            }

            #endregion

            if (element.Footer)
            {

                #region Style del Footer

                switch (element.Style)
                {
                    case Style.ConsulenzaBase:

                        if (element.ShowBorderFooter)
                        {
                            //Disegno un rettangolo in secondo piano che dia l'effetto cornice all'intestazione
                            var rectangleFrame = new RectanglePDF(element.X - 1, y + (element.FooterHeight / 2) + 1, (element.FooterHeight / 2), element.Width + 2, ColorPDF.ConsulenzaBase_Grigio_BordoColonnaHeaderFooterTabella) { AutoIncrementYWritable = false };
                            WriteElement(rectangleFrame);
                        }

                        // rettangolo contenitore grigio                
                        var rectangleFooter = new RectanglePDF(element.X, y, element.FooterHeight, element.Width, ColorPDF.ConsulenzaBase_Grigio_SfondoColonnaHeaderFooterTabella) { AutoIncrementYWritable = false };
                        WriteElement(rectangleFooter);

                        break;
                    case Style.Immobiliare:

                        //lineHeaderUp
                        WriteElement(new LinePDF(element.X, element.X + element.Width, 0.5F, new ColorPDF(153, 148, 133)));

                        //lineHeaderDown
                        WriteElement(new LinePDF(element.X, element.X + element.Width, 0.5F, new ColorPDF(153, 148, 133)) { DeltaY = element.FooterHeight });

                        break;
                    case Style.ConsulenzaUnica:

                        //Lo stile del rettangolo grigio è definito in FooterColumns e FooterCells. La gestione è diversa in quanto per ConsulenzaUnica le tabelle possono avre il FooterDatasource impostato.
                        break;
                }

                #endregion

                // Testo che sarà scritto sul footer
                var textToPrint = new FormattedTextAreaPDF();

                if (element.FooterColumns.Count > 0)
                {
                    y += element.FooterYOffset;

                    rowIndex = 0;
                    foreach (DataRow rigaFooter in element.FooterDatasource.Rows)
                    {
                        //patryk5
                        if (_ywritable + element.FooterHeight > YLowerLimit)
                        {
                            _ywritable = YLowerLimit;
                            TablePDF_ContinuedOnNextPage();
                            _ywritable = YUpperLimit + 15;
                            y = _ywritable;
                        }

                        float xLabelForCaptionFooter = element.X;
                        columnIndex = 0;

                        if (element.ShowFooterSeparationLines)
                        {
                            var colorSeparationLine = element.Columns[columnIndex].BackgroundGray ? ColorPDF.Bianco : ColorPDF.Standard_Grigio_SfondoColonnaTabella;

                            // linea separatrice                           
                            var separationLine = new RectanglePDF(xLabelForCaptionFooter, y + element.RowHeight, element.WidthSeparationLines, element.Width, colorSeparationLine) { AutoIncrementYWritable = false };

                            if (y < YLowerLimit)
                            {
                                if (element.HideLastSeparationLine)
                                {
                                    // Non viene disegnata la linea di separazione all'ultima riga
                                    if (rowIndex != element.FooterDatasource.Rows.Count - 1)
                                        WriteElement(separationLine);
                                }
                                else if (element.HideFirstSeparationLine)
                                {
                                    if (rowIndex != 0)
                                        WriteElement(separationLine);
                                }
                                else
                                    WriteElement(separationLine);
                            }
                        }

                        foreach (ColumnPDF colonnaFooter in element.FooterColumns)
                        {

                            var colorRectangleBackground = ColorPDF.Bianco;
                            var fontColor = ColorPDF.Nero;
                            float fontSize;
                            var fontBold = true;

                            TextAlign textAlignFooter = GetTextAlign(colonnaFooter.HorizontalAlignment);

                            #region Attributi della colonna [fontColor, fontSize, fontBold]

                            #region Attibuti impostati a livello COLONNA [FooterColumns]

                            // Colore
                            fontColor = element.FooterColumns[columnIndex].FontColor != null ? element.FooterColumns[columnIndex].FontColor : ColorPDF.Nero;

                            // Size
                            fontSize = colonnaFooter.FontSize;

                            // Grassetto
                            fontBold = colonnaFooter.FontBold.HasValue ? colonnaFooter.FontBold.Value : true;

                            #endregion

                            #region Attibuti impostati a livello CELLA [FooterColumns]

                            if (element.FooterCells[columnIndex, rowIndex].FontBold != null)
                                fontBold = element.FooterCells[columnIndex, rowIndex].FontBold.HasValue ? element.FooterCells[columnIndex, rowIndex].FontBold.Value : true;

                            #endregion

                            #endregion

                            #region Allineamento verticale e impostazione Y del testo

                            switch (element.FooterTextVerticalAlign)
                            {
                                case VerticalAlignmentType.Alto:
                                    yTextToPrint = y + element.FooterColumns[columnIndex].DeltaYContent;
                                    break;
                                case VerticalAlignmentType.Basso:
                                    yTextToPrint = y + (element.FooterHeight - element.FooterColumns[columnIndex].FontSize - (element.FooterColumns[columnIndex].FontSize / 2)) + element.FooterColumns[columnIndex].DeltaYContent;
                                    break;
                                case VerticalAlignmentType.Centrato:
                                    yTextToPrint = y + ((element.FooterHeight / 2) - (element.FooterColumns[columnIndex].FontSize / 2)) + element.FooterColumns[columnIndex].DeltaYContent;
                                    break;
                            }

                            #endregion

                            #region BackgroundGray e BackgroundColor della colonna
                            // Aggiungo un rettangolo di sfondo (BackgroundGray o BackgroundColor) della COLONNA.
                            if (element.FooterColumns[columnIndex].BackgroundGray || element.FooterColumns[columnIndex].BackgroundColor != null)
                            {
                                colorRectangleBackground = element.FooterColumns[columnIndex].BackgroundColor;

                                if (element.FooterColumns[columnIndex].BackgroundGray)
                                    colorRectangleBackground = ColorPDF.Standard_Grigio_SfondoColonnaTabella;

                                var rectangleBackground = new RectanglePDF(xLabelForCaptionFooter, y + 0.5F, element.FooterHeight - 0.5F, element.FooterColumns[columnIndex].Width, colorRectangleBackground) { AutoIncrementYWritable = false };

                                WriteElement(rectangleBackground);

                                if (element.FooterColumns[columnIndex].BackgroundColor != null)
                                {
                                    // Sovrascrivo le linee Up e Down del Footer nel caso in cui le colonne abbiano un BackgroundColor impostato. Le righe vengono impostate a bianco per maggiore leggibilità.
                                    var lineHeaderUp = new LinePDF(xLabelForCaptionFooter, y, xLabelForCaptionFooter + element.FooterColumns[columnIndex].Width, y, 0.5F, ColorPDF.Bianco) { AutoIncrementYWritable = false };
                                    WriteElement(lineHeaderUp);

                                    var lineHeaderDown = new LinePDF(xLabelForCaptionFooter, y, xLabelForCaptionFooter + element.FooterColumns[columnIndex].Width, y, 0.5F, ColorPDF.Bianco) { DeltaY = element.FooterHeight + 0.5F, AutoIncrementYWritable = false };
                                    WriteElement(lineHeaderDown);
                                }
                            }
                            #endregion

                            #region BackgroundColor della cella [Solo per ConsulenzaUnica]
                            // Aggiungo un rettangolo di sfondo (BackgroundColor) della CELLA.
                            if (element.FooterCells[columnIndex, rowIndex].BackgroundColor != null && element.Style == Style.ConsulenzaUnica)
                            {
                                colorRectangleBackground = element.FooterCells[columnIndex, rowIndex].BackgroundColor;

                                var rectangleBackground = new RectanglePDF(xLabelForCaptionFooter, y, element.FooterHeight, element.FooterColumns[columnIndex].Width, colorRectangleBackground) { AutoIncrementYWritable = false };
                                WriteElement(rectangleBackground);
                            }
                            #endregion

                            #region Testo del Footer

                            switch (colonnaFooter.TipoColonna)
                            {
                                case ColumnType.Percentuale:
                                case ColumnType.Intero:
                                case ColumnType.Decimale:
                                case ColumnType.Testo:
                                    if (string.IsNullOrEmpty(colonnaFooter.Name))
                                    {
                                        // Non è stata impostata la proprietà "nome" che mappa la colonna del FooterDatasource dalla quale prendere il dato da stampare. 
                                        // Viene quindi stampata il "Titolo" della colonna o se impostata la proprietà FooterCell, ne viene preso il rispettivo valore.   

                                        if (!string.IsNullOrEmpty(colonnaFooter.HeaderText))
                                        {
                                            textToPrint = new FormattedTextAreaPDF(colonnaFooter.HeaderText, xLabelForCaptionFooter, colonnaFooter.Width - colonnaFooter.PaddingLeft - colonnaFooter.PaddingRight, textAlignFooter) { Y = yTextToPrint, AutoIncrementYWritable = false, FontBold = fontBold, FontSize = fontSize, FontColor = fontColor };
                                        }
                                        else if (element.FooterCells != null)
                                        {
                                            string stringTextToPrint = string.Empty;

                                            if (colonnaFooter.TipoColonna == ColumnType.Testo)
                                                stringTextToPrint = rigaFooter[columnIndex].ToString();
                                            else if (colonnaFooter.TipoColonna == ColumnType.Decimale)
                                                stringTextToPrint = Helper.FormatCurrency(rigaFooter[columnIndex].ToString());
                                            else if (colonnaFooter.TipoColonna == ColumnType.Intero)
                                                stringTextToPrint = Helper.FormatInteger(rigaFooter[columnIndex].ToString());
                                            else if (colonnaFooter.TipoColonna == ColumnType.Percentuale)
                                                stringTextToPrint = Helper.FormatPercentage(rigaFooter[columnIndex].ToString(), 2);

                                            // ReplaceIfZero
                                            if (element.FooterCells[columnIndex, rowIndex].ReplaceIfZero != string.Empty)
                                                if (stringTextToPrint.Equals("0,00"))
                                                    stringTextToPrint = stringTextToPrint.Replace("0,00", element.FooterCells[columnIndex, rowIndex].ReplaceIfZero);


                                            stringTextToPrint += arrayAsterischiNote_PieDiPagina[0, columnIndex] ?? string.Empty;

                                            textToPrint = new FormattedTextAreaPDF(stringTextToPrint, TablePDF_GetXTextFooter(xLabelForCaptionFooter, columnIndex, element), colonnaFooter.Width - colonnaFooter.PaddingLeft - colonnaFooter.PaddingRight, textAlignFooter)
                                            {
                                                Y = yTextToPrint,
                                                AutoIncrementYWritable = false,
                                                FontBold = fontBold,
                                                FontSize = fontSize,
                                                FontColor = fontColor
                                            };
                                        }
                                    }
                                    //else // è stata impostata la proprietà "nome" che mappa la colonna del FooterDatasource dalla quale prendere il dato da stampare. Stampo il valore della colonna.
                                    //{
                                    //    if (element.FooterDatasource == null)
                                    //        throw new Exception("Proprietà FooterDatasource della tabella non impostata");

                                    //    string stringColumnValueFooter = element.FooterDatasource.Rows[0][colonnaFooter.Name].ToString();

                                    //    textToPrint = new FormattedTextAreaPDF(stringColumnValueFooter, TablePDF_GetXTextFooter(xLabelForCaptionFooter, columnIndex, element), colonnaFooter.Width, textAlignFooter)
                                    //    {
                                    //        Y = yTextToPrint,
                                    //        AutoIncrementYWritable = false,
                                    //        FontSize = colonnaFooter.FontSize
                                    //    };
                                    //}

                                    WriteElement(textToPrint);

                                    break;
                                case ColumnType.Immagine:
                                case ColumnType.Objectpdf:
                                    {
                                        #region TIPO DI COLONNA FOOTER IMMAGINE

                                        ImagePDF imageToPrint;
                                        if (element.FooterCells[columnIndex, 0].Value != string.Empty)
                                        {
                                            #region Allineamento orizzontale dell'immagine

                                            float xImmagine = xLabelForCaptionFooter;

                                            Align imageAlignX;
                                            switch (textAlignFooter)
                                            {
                                                case TextAlign.Center:
                                                    imageAlignX = Align.Center;
                                                    xImmagine = xImmagine + (element.FooterColumns[columnIndex].Width / 2);
                                                    break;
                                                case TextAlign.Left:
                                                    imageAlignX = Align.Left;
                                                    xImmagine = xLabelForCaptionFooter;
                                                    break;
                                                case TextAlign.Right:
                                                    imageAlignX = Align.Right;
                                                    xImmagine = xLabelForCaptionFooter + element.FooterColumns[columnIndex].Width;
                                                    break;
                                                default:
                                                    imageAlignX = Align.Left;
                                                    xImmagine = xLabelForCaptionFooter;
                                                    break;
                                            }
                                            #endregion

                                            imageToPrint = new ImagePDF(TablePDF_GetXTextFooter(xImmagine + element.FooterColumns[columnIndex].PaddingLeft, columnIndex, element), element.FooterColumns[columnIndex].ScaleColumnTypeImage, element.FooterCells[columnIndex, 0].Value, imageAlignX, yTextToPrint);
                                            WriteElement(imageToPrint);
                                        }


                                        #endregion
                                    }
                                    break;
                            }


                            #endregion

                            columnIndex++;
                            xLabelForCaptionFooter += colonnaFooter.Width;
                        }
                        rowIndex++;

                        y += element.FooterHeight;
                        yTextToPrint += element.FooterHeight;


                        //int rowsCountLeft = element.FooterDatasource.Rows.Count - element.FooterDatasource.Rows.IndexOf(rigaFooter) + 1;
                        //float restOfFooter = rowsCountLeft * element.FooterHeight;
                        //if (y >= YLowerLimit - 100)
                        //{
                        //    //_ywritable = YLowerLimit;
                        //    //TablePDF_ContinuedOnNextPage();
                        //    //_ywritable = 100;
                        //    //y = _ywritable;
                        //    int test = 2;
                        //}
                    }
                }

                // Incremento _ywritable con l'altezza del footer
                _ywritable += (element.FooterHeight * element.FooterDatasource.Rows.Count);
            }

            #endregion

            #region Stampo le note,associate alla tabella, da inserire sotto il footer della tabella.


            foreach (TableNotePDF note in notesFooterTable)
            {
                WriteElement(new SpacePDF(5));
                note.X = element.X;
                note.AsterisksNumber = GetAsterisksNumber(note);
                note.Width = element.Width;
                note.AutoIncrementYWritable = true;
                WriteElement(note);
            }

            #endregion

            _printinginnewpage = false;

            // AutoIncrementYWritable = false : la _ywritable è quella originale
            if (!element.AutoIncrementYWritable)
                _ywritable = originalYWritable;

        }

        /// <summary>
        /// Scrive l'elemento SpacePDF sul documento
        /// </summary>
        /// <param name="element"></param>
        private void WriteElement(SpacePDF element)
        {
            _ywritable += element.Height;

            if (_ywritable > YLowerLimit)
                AddPage();
        }

        /// <summary>
        /// Scrive l'elemento UnorderedListPDF sul documento
        /// </summary>
        /// <param name="element"></param>
        private void WriteElement(UnorderedListPDF element)
        {
            element.BaseElement = new UnorderedList(element.X, element.Y, element.Width, element.Height, _reportEnvironment.FontFamily.Regular, element.FontSize)
            {
                ListItemTopMargin = element.Margin,
                ListItemBottomMargin = element.Margin,
                TextAlign = element.TextAlign
            };

            foreach (string item in element.Items)
                element.BaseElement.Items.Add(item);

            if (element.Y == 0)
                element.BaseElement.Y = _ywritable;

            if (element.Height == 0)
            {
                element.Height = element.BaseElement.GetRequiredHeight();
                element.BaseElement.Height = element.Height;
            }

            // Tipo di bullet
            if (element.BulletType == BulletType.Pallino)
                element.BaseElement.BulletStyle = UnorderedListStyle.Disc;

            else if (element.BulletType == BulletType.Trattino)
                element.BaseElement.BulletStyle = UnorderedListStyle.Dash;


            if (_ywritable <= YLowerLimit)
                _page.Elements.Add(element.ToElement());
            else
            {
                // aggiunge una pagina                
                AddPage();
                element.BaseElement.Y = _ywritable;
                _page.Elements.Add(element.ToElement());
            }

            if (element.AutoIncrementYWritable)
                _ywritable += element.Height;
        }

        /// <summary>
        /// Scrive l'elemento ResetterYPDF.
        /// Se Y = 0 _ywritable = _yupperlimit altrimenti _ywritable= Y
        /// </summary>
        /// <param name="element"></param>
        private void WriteElement(ResetterYPDF element)
        {
            _ywritable = element.Y.Equals(0) ? YUpperLimit : element.Y;
        }

        private void WriteElement(ActionPDF element)
        {
            if (element.YPositionAction != null)
            {
                foreach (ObjectPDF obj in element.YPositionAction.Invoke(_ywritable))
                {
                    if (obj is PagePDF)
                    {
                        AddPage(((PagePDF)obj).Type);
                    }
                    else
                    {
                        WriteElement(obj);
                    }
                }
            }            
        }

        /// <summary>
        /// Scrive l'elemento CompositePDF sul documento.
        /// </summary>
        /// <param name="element"></param>
        /// <remarks>
        /// DA IMPLEMETARE
        /// </remarks>       
        private void WriteElement(CompositePDF element)
        {
            const float totalHeight = 0F;

            if (_ywritable + totalHeight > YLowerLimit)
                AddPage();

            foreach (var item in element.Elements)
            {
                WriteElement(item);
            }
        }

        /// <summary>
        /// Disegna tutti gli Elements (List di ObjectPDF) di cui si compone un ChartPDF.
        /// Se la somma di tutti i punti delle serie è 0, il grafico non sarà disegnato.
        /// </summary>
        /// <param name="element"></param>
        private void WriteElement(ChartPDF element)
        {
            var originalYWritable = _ywritable;

            //Se tutti i Point.Value aggiunti a tutte le serie sono = 0 non stampo il grafico
            var print = element.SeriesCollection.FindAll(o => o.Points.Sum(p => p.Value) > 0).Any();

            // Se tutti i Point.Values.X o Point.Values.Y aggiunti a tutte le serie sono = 0 non stampo il grafico
            if (!print)
                print = element.SeriesCollection.FindAll(o => o.Points.Sum(p => p.Values.X) > 0 || o.Points.Sum(p => p.Values.Y) > 0).Any();

            if (!print) return;

            #region Grafico Stacked con salto pagina

            bool stackedChartWithPageBreak = false;

            try
            {
                var stackedChart = element as StackedPDF; // grafico Stacked
                stackedChartWithPageBreak = stackedChart.PageBreak;
            }
            catch
            {
                stackedChartWithPageBreak = false;
            }

            #endregion

            if (stackedChartWithPageBreak)
            {
                #region Disegno con salto pagina per i grafici Stacked

                var stackedChart = element as StackedPDF; // grafico Stacked
                stackedChart.MaximumValueAxisY = stackedChart.GetMaximumValuePoints();

                var pointsCopy = new List<Point>(stackedChart.SeriesCollection[0].Points);
                List<Point> pointsCopy2 = null;
                if (stackedChart.SeriesCollection.Count > 1)
                    pointsCopy2 = new List<Point>(stackedChart.SeriesCollection[1].Points);
                int rowsIncrement = 0;
                int remainingRows = stackedChart.SeriesCollection[0].Points.Count; //Righe restanti

                do
                {
                    element.ChartBase.Series.Clear();
                    element.SeriesCollection[0].Points.Clear();
                    element.Elements.Clear();

                    var remainingSpace = YLowerLimit - _ywritable;
                    switch (_reportEnvironment.ReportType)
                    {
                        case ReportType.Unica_Diagnosi:
                        case ReportType.Unica_Monitoraggio:
                        case ReportType.Unica_Nucleo:
                        case ReportType.Unica_Proposta:
                            //   stackedChart.HeightSingleBar = pointsCopy.Count < 3 ? 40 : 25;
                            break;
                        default:
                            stackedChart.HeightSingleBar = stackedChart.HeightSingleBar;
                            break;
                    }
                    int rowsInPage = Convert.ToInt32((remainingSpace / stackedChart.HeightSingleBar)) - 5;

                    //                    aggiunto il reverse perchè con il salto di pagine scombina l'ordinamento. 



                    element.SeriesCollection[0].Points = pointsCopy.Skip(rowsIncrement).Take(rowsInPage).ToList();
                    if (element.SeriesCollection.Count > 1)
                        element.SeriesCollection[1].Points = pointsCopy2.Skip(rowsIncrement).Take(rowsInPage).ToList();
                    int i = 0;
                    foreach (var item in element.SeriesCollection)
                    {
                        element.SeriesCollection[i].Points.Reverse();
                        i++;
                    }
                    // Popola la Elements di tutti gli oggetti di cui si compone il grafico.
                    element.ToElement();

                    // Disegna tutti gli Elements
                    foreach (ObjectPDF item in element.Elements)
                        WriteElement(item);

                    rowsIncrement += rowsInPage;
                    remainingRows -= rowsInPage;

                    if (remainingRows > 0)
                    {

                        StackedPDF_ContinuedOnNextPage();
                        //AddPage();
                        //AddSpace(20);
                    }
                }
                while (remainingRows > 0);

                #endregion
            }
            else
            {
                // Popola la Elements di tutti gli oggetti di cui si compone il grafico.
                int i = 0;
                foreach (var item in element.SeriesCollection)
                {
                    element.SeriesCollection[i].Points.Reverse();
                    i++;
                }
                element.ToElement();

                // Salto pagina nel caso in cui il grafico non possa essere contenuto in pagina.
                if (_ywritable + element.TotalHeight > YLowerLimit)
                    AddPage(); // aggiungere una pagina

                // Disegna tutti gli Elements
                float _ywritableTmp = _ywritable;

                foreach (ObjectPDF item in element.Elements)
                    WriteElement(item);

                float yWritableTmp2 = _ywritable;

                _ywritable = _ywritableTmp;

                foreach (Marker m in element.Markers)
                {
                    WriteElement(new ImagePDF(((m.X < 0 ? 0 : m.X) * element.Width / (float)element.ChartBase.ChartAreas[0].AxisX.Maximum) + element.X - (m.Width * m.Scale / 2), m.Scale, m.Image)
                    {
                        Width = m.Width,
                        Height = m.Height,
                        Y = _ywritable + element.Height - (element.Height * m.Y / (float)element.ChartBase.ChartAreas[0].AxisY.Maximum) - (m.Height * m.Scale / 2),
                        AutoIncrementYWritable = false
                    });
                }

                _ywritable = yWritableTmp2;
            }
            try
            {
                var stackedChart = element as StackedPDF;
                var max = stackedChart.GetMaximumValuePoints();
                var valoreeperintervallo = Helper.Round(max) / stackedChart.IntervalNumberAxisY;
                var valoreultimoAsseX = (valoreeperintervallo * stackedChart.IntervalNumberAxisY);
                float _x = stackedChart.X;
                float TotalHeight = stackedChart.GetHeight();
                float y1Linea = originalYWritable;
                float y2Linea = y1Linea + TotalHeight;

                foreach (VerticalMarkerWithLine marker in stackedChart.VerticalMarkersWithLines)
                {
                    var valorePatrimoni = (marker.XValue * stackedChart.Width) / valoreultimoAsseX;
                    WriteElement(new LinePDF((float)valorePatrimoni + _x, y1Linea, (float)valorePatrimoni + _x, y2Linea) { AutoIncrementYWritable = false, Color = marker.Color });
                    var img = new ImagePDF((float)valorePatrimoni + _x + 6, 0.50F/*0.30F*/, marker.ImagePath, ceTe.DynamicPDF.Align.Right, y1Linea) { AutoIncrementYWritable = false, DeltaY = -15 };
                    img.Y += marker.ImageYOffset;
                    WriteElement(img);
                }
            }
            catch
            {

            }

            // AutoIncrementYWritable = false : la _ywritable è quella originale
            if (!element.AutoIncrementYWritable)
                _ywritable = originalYWritable;
        }


        private void WriteElement(CustomChartPDF element)
        {
            var originalYWritable = _ywritable;

            // Popola la Elements di tutti gli oggetti di cui si compone il grafico.
            element.ToElement();

            // Disegna tutti gli Elements
            foreach (ObjectPDF item in element.Elements)
            {
                WriteElement(item);
            }
            // AutoIncrementYWritable = false : la _ywritable è quella originale
            if (!element.AutoIncrementYWritable)
                _ywritable = originalYWritable;
        }

        /// <summary>
        /// Ritorna l'altezza della FormattedTextArea contenente il testo passato in input.
        /// </summary>
        /// <param name="texttoprint">testo da scrivere</param>
        /// <param name="width">larghezza della FormattedTextArea contenente il testo</param>
        /// <param name="fontsize">font size della FormattedTextArea contenente il testo </param>
        /// <param name="fontbold">bold della FormattedTextArea contenente il testo</param>
        /// <param name="tipocolonna">tipo di colonna contenente il testo. Di default = TESTO</param>
        /// <returns></returns>
        private float GetTextHeigth(string texttoprint, float width, float fontsize, bool fontbold = false, ColumnType tipocolonna = ColumnType.Testo)
        {
            if (tipocolonna == ColumnType.Immagine || width == 0 || texttoprint.Length == 0) return 0;

            var formattedTextArea = new FormattedTextArea(texttoprint, 0, 0, width - 3, 0, _reportEnvironment.FontFamily, fontsize, true) // sottraggo - 3 alla width per un valore più preciso dell'altezza di ritorno.
            {
                Style = { Bold = fontbold }
            };

            return formattedTextArea.GetRequiredHeight();
        }

        /// <summary>
        ///  Recupera l'allineamento TextAlign a partire dal TipoAllineamentoOrizzontale della colonna.
        /// </summary>
        /// <param name="allineamentoOrizzontaleColonna">allineamento orizzontale della colonna</param>
        /// <returns></returns>
        private TextAlign GetTextAlign(HorizontalAlignmentType allineamentoOrizzontaleColonna)
        {
            var textAlign = new TextAlign();

            switch (allineamentoOrizzontaleColonna)
            {
                case HorizontalAlignmentType.Destra:
                    textAlign = TextAlign.Right;
                    break;
                case HorizontalAlignmentType.Sinistra:
                    textAlign = TextAlign.Left;
                    break;
                case HorizontalAlignmentType.Centrato:
                    textAlign = TextAlign.Center;
                    break;
            }

            return textAlign;
        }

        /// <summary>
        /// Recupera il numero di asterischi più basso disponibile tra quelli gia inseriti nel documento.
        /// Ogni volta che nel documento è aggiunta una ObjectTypePDF.PAGE, il numero di asterischi viene resettato.
        /// </summary>
        /// <returns></returns>
        private int GetAsterisksNumber(TableNotePDF currentNote)
        {
            int result = 1;

            // Indice dell'elemento corrente            
            int indexCurrentElement = _elements.Count;

            // Cerco l'indice in _elements dell'ultimo ObjectPDF di tipo ObjectTypePDF.PAGE
            int indexLastPage = _elements.FindLastIndex(r => r.ObjectType == ObjectTypePdf.PAGE);

            var rangeList = _elements.GetRange(indexLastPage, indexCurrentElement - indexLastPage);

            // Conto quante TABLE con alemno 1 nota sono presenti in rangeList           
            var tableList = rangeList.FindAll(r => r.ObjectType == ObjectTypePdf.TABLE && ((TablePDF)r).Notes.Count > 0);

            // Cliclo le TABLE trovate e per ognuno ciclo sulle proprie Note
            foreach (var objectPdf in tableList)
            {
                var table = (TablePDF)objectPdf;

                foreach (var note in table.Notes)
                {
                    if (currentNote == note)
                        return result;

                    result++;
                }
            }

            return result;
        }

        /// <summary>
        /// Incrementa o decrementa la prima colonna se allineata a sinistra e l'ultima colonna se allineata a destra,
        /// del valore impostato come margine alla tabella.
        /// Serve per dare la spaziatura tra la prima e l'ultima colonna tra il bordo e il testo.
        /// </summary>
        /// <param name="xcorrente">valore della x corrente</param>
        /// <param name="currentcolumn">indice della colonna corrente</param>
        /// <param name="table">tabella</param>
        /// <returns></returns>
        private float TablePDF_GetXTextContent(float xcorrente, int currentcolumn, TablePDF table)
        {
            #region Imposto il valore della proprietà Margin per la prima colonna se l'allineamento è a SINISTRA

            if (currentcolumn == 0 && table.Columns[currentcolumn].HorizontalAlignment == HorizontalAlignmentType.Sinistra)
                return xcorrente += table.Margin;

            #endregion

            #region Imposto il valore della proprietà Margin per l'ultima colonna se l'allineamento è a DESTRA

            if (currentcolumn == table.Columns.Count - 1 && table.Columns[currentcolumn].HorizontalAlignment == HorizontalAlignmentType.Destra)
                return xcorrente -= table.Margin;

            #endregion

            return xcorrente;
        }

        /// <summary>
        /// Incrementa o decrementa la prima colonna se allineata a sinistra e l'ultima colonna se allineata a destra,
        /// del valore impostato come margine alla tabella.
        /// Serve per dare la psaziatura tra la prima e l'ultima colonna tra il bordo e il testo.
        /// </summary>
        /// <param name="xcorrente">valore della x corrente</param>
        /// <param name="currentcolumn">indice della colonna corrente</param>
        /// <param name="table">tabella</param>
        /// <returns></returns>
        private float TablePDF_GetXTextFooter(float xcorrente, int currentcolumn, TablePDF table)
        {
            #region Imposto il valore della proprietà Margin per la prima colonna se l'allineamento è a SINISTRA

            if (currentcolumn == 0 && table.FooterColumns[currentcolumn].HorizontalAlignment == HorizontalAlignmentType.Sinistra)
                return xcorrente + table.Margin;

            #endregion

            #region Imposto il valore della proprietà Margin per l'ultima colonna se l'allineamento è a DESTRA

            if (currentcolumn == table.FooterColumns.Count - 1 && table.FooterColumns[currentcolumn].HorizontalAlignment == HorizontalAlignmentType.Destra)
                return xcorrente - table.Margin;

            #endregion

            return xcorrente;
        }

        /// <summary>
        /// Disegna la riga del titolo della tabella.
        /// Imposta automaticamente a false la proprietà ShowBorderHeader della TablePDF (element).
        /// Aggiunge uno SpacePDF pari a 10.
        /// </summary>
        private bool TablePDF_DrawTitleRow(TablePDF element)
        {
            element.ShowBorderHeader = false;
            bool printedTitleRow = false;

            //// Il TitleRow della tabella deve essere stampato in una nuova pagina se lo spazio rimanente non può contenere il titlerow stesso, l'header e 2 righe della tabella.
            //if (element.TitleRowHeight + element.HeaderHeight + (element.CellHeight * 2) + element.TitleRowSpace > RemainingSpace)
            //{
            //    AddPage();
            //    element.Y = _yupperlimit;
            //}

            switch (element.TitleRowBorder)
            {
                case BorderTitleRowType.Pieno:
                    {
                        //Disegno un rettangolo in secondo piano che dia l'effetto cornice all'intestazione
                        var rectangleFrame = new RectanglePDF(element.X - 1, _ywritable - 1, element.TitleRowHeight / 2, element.Width + 2, ColorPDF.ConsulenzaBase_Grigio_BordoColonnaHeaderFooterTabella)
                        {
                            AutoIncrementYWritable = false
                        };
                        WriteElement(rectangleFrame);

                        // rettangolo contenitore grigio
                        var rectangleHeader = new RectanglePDF(element.X, _ywritable, element.TitleRowHeight, element.Width, ColorPDF.ConsulenzaBase_Grigio_SfondoColonnaHeaderFooterTabella)
                        {
                            AutoIncrementYWritable = false
                        };

                        WriteElement(rectangleHeader);

                        // TitleRowText
                        var labelTitle = new FormattedTextAreaPDF(element.TitleRowText, element.X + element.Margin, element.Width);
                        labelTitle.Y = _ywritable + ((element.TitleRowHeight / 2) - (labelTitle.Height / 2));
                        labelTitle.AutoIncrementYWritable = false;
                        labelTitle.FontBold = true;

                        //labelTitle.TextColor = element.HeaderFontColor;
                        WriteElement(labelTitle);
                        printedTitleRow = true;
                    }
                    break;
                case BorderTitleRowType.Nessuno:
                    {
                        var labelTitle = new FormattedTextAreaPDF(element.TitleRowText, element.X + element.Margin, element.Width);
                        labelTitle.Y = _ywritable + ((element.TitleRowHeight / 2) - (labelTitle.Height / 2));
                        labelTitle.AutoIncrementYWritable = false;
                        WriteElement(labelTitle);
                        printedTitleRow = true;
                    }
                    break;
            }

            AddSpace(element.TitleRowHeight);

            // SUBTITLE
            if (element.SubTitleTable != null)
            {
                WriteElement(element.SubTitleTable);
                _printinginnewpage = true;
            }

            if (element.SubTitleElements != null)
            {
                foreach (ObjectPDF item in element.SubTitleElements)
                {
                    WriteElement(item);
                    _printinginnewpage = true;
                }
            }

            AddSpace(element.TitleRowSpace);

            return printedTitleRow;
        }
        private bool TablePDF_DrawTitleRow(TablePDF element, bool unica = true) //row unica per es. scheda 31
        {
            element.ShowBorderHeader = false;
            bool printedTitleRow = false;
            var remainingSpace = YLowerLimit - _ywritable;
            if (element.TitleRowHeight + element.HeaderHeight + (element.RowHeight * 2) + element.TitleRowSpace > remainingSpace)
            {
                AddPage();
                AddSpace(1);
                element.Y = YUpperLimit;
            }

            var rectangleHeader = new RectanglePDF(element.X, _ywritable, element.TitleRowHeight, element.Width, ColorPDF.Bianco)
            {
                AutoIncrementYWritable = false
            };

            WriteElement(rectangleHeader);

            // TitleRowText
            var labelTitle = new FormattedTextAreaPDF(element.TitleRowText, element.X + element.Margin, element.Width) { FontSize = 11, FontColor = ColorPDF.Nero, FontBold = true };
            labelTitle.Y = _ywritable + ((element.TitleRowHeight / 2) - (labelTitle.Height / 2));
            labelTitle.AutoIncrementYWritable = false;
            WriteElement(labelTitle);
            printedTitleRow = true;


            AddSpace(element.TitleRowHeight);

            // SUBTITLE
            if (element.SubTitleTable != null)
            {
                WriteElement(element.SubTitleTable);
                _printinginnewpage = true;
            }

            if (element.SubTitleElements != null)
            {
                foreach (ObjectPDF item in element.SubTitleElements)
                {
                    WriteElement(item);
                    _printinginnewpage = true;
                }
            }

            AddSpace(element.TitleRowSpace);

            return printedTitleRow;
        }
        /// <summary>
        /// Disegna l'header della tabella.
        /// </summary>
        private void TablePDF_DrawHeader(TablePDF element, string[,] arrayAsterischiNote_Intestazione)
        {
            var yHeader = _ywritable; // recupero la posizione y su cui è stato disegnato il rettangolo dell' Header
            var backgroundColor = ColorPDF.ConsulenzaBase_Grigio_SfondoColonnaHeaderFooterTabella; //Grigio : standard per Proposta Consulenzabase.           
            var fontColorHeaderColumn = ColorPDF.Nero;

            // Salto pagina se non c'è abbastanza spazio per stampare l'header + 2 righe
            if (_ywritable + element.HeaderHeight + element.AdditionalSpaceBetweenHeadersAndTable + element.HeaderMargin + ((element.RowHeight + element.RowsPadding) * 2) > _ylowerlimitoriginal 
                || (_ywritable + element.HeaderHeight + element.AdditionalSpaceBetweenHeadersAndTable + element.HeaderMargin + ((element.RowHeight + element.RowsPadding) * 2) >= element.TableCantReachThisYPosition && element.TableCantReachThisYPosition != 0))
            {
                AddPage();
                if (element.AddSpaceBeforeTableAfterEntireTableIsMovedToNextPage)
                {
                    AddSpace(5); // adds space at the very begining, so while inserting a table at the top of the page, there is a space for
                                 // a built in header
                }                
                yHeader = _ywritable;
                element.Y = _ywritable;
            }

            if (element.HeaderNoteObjects.Count > 0)
            {
                //if (!element.HeaderTextDrawJustOnce || (element.HeaderTextDrawJustOnce && element.HeaderNoteObjectsCounter < 1))
                //{
                element.HeaderNoteObjectsCounter++;
                foreach (var e in element.HeaderNoteObjects)
                {
                    WriteElement(e);
                }
                //}
            }
            // label dell'intestazione delle colonne
            float xLabelHeaderText = element.X;
            FormattedTextAreaPDF labelHeaderText;

            if (!string.IsNullOrEmpty(element.TableTitle))//if (!element.HeaderTextDrawJustOnce || (element.HeaderTextDrawJustOnce && element.HeaderTextCounter < 1))
            {
                element.HeaderTextCounter++;
                #region stampo nell'header della tabella il testo contenuto in HeaderText.

                labelHeaderText = new FormattedTextAreaPDF(element.TableTitle,
                    TablePDF_GetXTextContent(xLabelHeaderText, 0, element),
                    element.Width,
                    TextAlign.Left)
                {
                    Y = yHeader,
                    FontBold = true,
                    AutoIncrementYWritable = false
                };

                if (element.TableTitleDeltaX != 0)
                {
                    labelHeaderText.X += element.TableTitleDeltaX;
                }
                if (element.TableTitleFontSize != 0)
                {
                    labelHeaderText.FontSize = element.TableTitleFontSize;
                }
                if (element.TableTitleFontColor != null)
                {
                    labelHeaderText.FontColor = element.TableTitleFontColor;
                }

                labelHeaderText.GetAndSetHeight(_reportEnvironment.FontFamily, labelHeaderText.FontBold);

                #region Allineamento verticale

                switch (element.HeaderTextVerticalAlign)
                {
                    case VerticalAlignmentType.Alto:
                        labelHeaderText.Y = yHeader;
                        break;
                    case VerticalAlignmentType.Basso:
                        labelHeaderText.Y = yHeader + (element.HeaderHeight - labelHeaderText.Height);
                        break;
                    case VerticalAlignmentType.Centrato:
                        labelHeaderText.Y = yHeader + ((element.HeaderHeight / 2) - (labelHeaderText.Height / 2));
                        break;
                }
                #endregion

                WriteElement(labelHeaderText);
                #endregion
            }
            _ywritable += element.HeadersObjectsHeight;
            yHeader += element.HeadersObjectsHeight;


            switch (element.Style)
            {
                case Style.ConsulenzaBase:
                    #region ConsulenzaBase

                    if (element.ShowBorderHeader)
                    {
                        //Disegno un rettangolo in secondo piano che dia l'effetto cornice all'intestazione
                        var rectangleFrame = new RectanglePDF(element.X - 1, _ywritable - 1, element.HeaderHeight / 2, element.Width + 2, ColorPDF.ConsulenzaBase_Grigio_BordoColonnaHeaderFooterTabella) { AutoIncrementYWritable = false };
                        WriteElement(rectangleFrame);
                    }

                    // rettangolo contenitore grigio
                    var rectangleHeader = new RectanglePDF(element.X, _ywritable, element.HeaderHeight, element.Width, backgroundColor) { AutoIncrementYWritable = false };
                    WriteElement(rectangleHeader);

                    #endregion
                    break;
                case Style.Immobiliare:
                    #region Immobiliare
                    if (element.DrawLineHeaderUP)
                    {
                        var lineHeaderUp = new LinePDF(element.X, element.X + element.Width, 0.5F, new ColorPDF(153, 148, 133));
                        WriteElement(lineHeaderUp);
                    }

                    var lineHeaderDown = new LinePDF(element.X, element.X + element.Width, 0.5F, new ColorPDF(153, 148, 133)) { DeltaY = element.HeaderHeight };
                    WriteElement(lineHeaderDown);


                    #endregion
                    break;
                case Style.ConsulenzaUnica:
                    #region ConsulenzaUnica
                    // rettangolo contenitore grigio
                    backgroundColor = ColorPDF.ConsulenzaUnica_Grigio_SfondoColonnaHeaderFooterTabella;
                    WriteElement(new RectanglePDF(element.X, yHeader, element.HeaderHeight, element.Width, backgroundColor) { AutoIncrementYWritable = false });

                    break;
                    #endregion
            }

            // label dell'intestazione delle colonne
//            float xLabelHeaderText = element.X;
//            FormattedTextAreaPDF labelHeaderText;

            if (element.HeaderText == string.Empty)
            {
                #region  stampo nell'header della tabella le caption delle singole colonne della tabella

                int columnIndex = 0;
                int widthcurrent = 0;
                foreach (var column in element.Columns)
                {
                    if (column.Visibile)
                    {
                        #region Aggiungo un rettangolo di sfondo (BackgroundColor).

                        if (column.HeaderBackgroundColor != null)
                        {
                            var colorRectangleBackground = column.HeaderBackgroundColor;
                            var rectangleBackground = new RectanglePDF(xLabelHeaderText, yHeader, element.HeaderHeight, column.Width, colorRectangleBackground) { AutoIncrementYWritable = false };

                            WriteElement(rectangleBackground);

                            // Sovrascrivo la linea Down dell' Header nel caso in cui le colonne abbiano un BackgroundColor impostato. La riga viene impostata a bianco per maggiore leggibilità.
                            var lineHeaderDown = new LinePDF(xLabelHeaderText, yHeader + element.HeaderHeight, xLabelHeaderText + column.Width, yHeader + element.HeaderHeight, 1F, ColorPDF.Bianco) { DeltaY = 0.5F, AutoIncrementYWritable = false };
                            WriteElement(lineHeaderDown);
                        }

                        #endregion

                        var stringAsteriscoIntestazione = arrayAsterischiNote_Intestazione[0, columnIndex] ?? string.Empty;

                        labelHeaderText = new FormattedTextAreaPDF(column.HeaderText + stringAsteriscoIntestazione,
                            TablePDF_GetXTextContent(xLabelHeaderText, columnIndex, element) + column.HeaderPaddingLeft,
                            column.Width - column.HeaderPaddingRight,
                            GetTextAlign(column.HorizontalAlignment))
                        {
                            Y = yHeader,
                            FontBold = column.HeaderFontBold,
                            FontSize = column.HeaderFontSize,
                            AutoIncrementYWritable = false,
                            TextVerticalDirection = column.HeaderTextVerticalDirection
                        };

                        #region Altezza del TESTO

                        if (labelHeaderText.TextVerticalDirection)
                            labelHeaderText.Width = element.HeaderHeight;

                        labelHeaderText.GetAndSetHeight(_reportEnvironment.FontFamily, labelHeaderText.FontBold);

                        #endregion

                        #region Direzione VERTICALE del TESTO

                        if (labelHeaderText.TextVerticalDirection)
                        {
                            labelHeaderText.FixedHeight = labelHeaderText.Height;

                            labelHeaderText.TextHorizontalAlign = TextAlign.Left;
                            labelHeaderText.Y = (yHeader + element.HeaderHeight) - 2;
                            if (_reportEnvironment.ReportType == ReportType.Unica_Diagnosi || _reportEnvironment.ReportType == ReportType.Unica_Monitoraggio || _reportEnvironment.ReportType == ReportType.Unica_Nucleo || _reportEnvironment.ReportType == ReportType.Unica_Proposta)
                                labelHeaderText.X = labelHeaderText.X + (element.Columns[columnIndex].Width / 2) - (labelHeaderText.FontSize);
                            else
                                labelHeaderText.X = labelHeaderText.X + (element.Columns[columnIndex].Width / 2) - (labelHeaderText.FontSize / 2);
                        }

                        #endregion

                        #region Colore del TESTO

                        switch (element.Style)
                        {
                            case Style.ConsulenzaBase:
                            case Style.Immobiliare:
                                fontColorHeaderColumn = ColorPDF.Nero;
                                break;
                            case Style.ConsulenzaUnica:
                                fontColorHeaderColumn = ColorPDF.ConsulenzaUnica_Rosso;
                                break;
                        }

                        labelHeaderText.FontColor = fontColorHeaderColumn;

                        if (column.HeaderFontColor != null)
                            labelHeaderText.FontColor = column.HeaderFontColor;

                        #endregion

                        #region Allineamento verticale del TESTO (Recupero Y)

                        if (!labelHeaderText.TextVerticalDirection)
                        {
                            switch (column.HeaderVerticalAlignment)
                            {
                                case VerticalAlignmentType.Alto:
                                    labelHeaderText.Y = yHeader;
                                    break;
                                case VerticalAlignmentType.Basso:
                                    labelHeaderText.Y = yHeader + (element.HeaderHeight - labelHeaderText.Height);
                                    break;
                                case VerticalAlignmentType.Centrato:
                                    labelHeaderText.Y = yHeader + ((element.HeaderHeight / 2) - (labelHeaderText.Height / 2));
                                    break;
                            }
                        }

                        #endregion

                        // Incremento la X
                        xLabelHeaderText += column.Width;
                        // widthcurrent += xLabelHeaderText + column.Width;
                        // Disegno la label di HeaderText
                        WriteElement(labelHeaderText);
                        if (element.ShowBorderHeader)
                        {
                            WriteElement(new RectanglePDF(xLabelHeaderText + 1, yHeader, element.HeaderHeight, 1, ColorPDF.Bianco) { AutoIncrementYWritable = false });

                        }
                    }
                    columnIndex++;
                }

                #region HeaderGroupText e HeaderGroupPathImage

                //Aggiungo un HeaderGroupText alle colonne che hanno impostato HeaderGroupPathImage, in modo da sfruttare il codice scritto per HeaderGroupText.
                element.Columns.Where(o => o.HeaderGroupPathImage != null).ToList().ForEach(i => i.HeaderGroupText = new List<string>() { " " });

                // Controllo se esiste almeno una colonna con HeaderGroupText impostato.
                if (element.Columns.Any(o => o.HeaderGroupText.Any()))
                {
                    columnIndex = 0;
                    xLabelHeaderText = element.X;

                    foreach (var column in element.Columns)
                    {
                        if (column.Visibile)
                        {
                            var scostamentoX = 0F;

                            foreach (var itemHeaderGroupText in column.HeaderGroupText)
                            {
                                var xHeaderGroupText = column.HeaderGroupTextVerticalDirection
                                    ? xLabelHeaderText + (column.HeaderGroupWidth / 2) + column.HeaderGroupTextDeltaX + scostamentoX
                                    : xLabelHeaderText + column.HeaderGroupTextDeltaX;

                                var yHeaderGroupText = element.Y + element.HeaderHeight + column.HeaderGroupTextDeltaY;

                                var labelHeaderGroupText = new FormattedTextAreaPDF(
                                    itemHeaderGroupText,
                                    xHeaderGroupText,
                                    column.HeaderGroupWidth)
                                {
                                    FontBold = true,
                                    AutoIncrementYWritable = false,
                                    TextVerticalDirection = column.HeaderGroupTextVerticalDirection,
                                    FontColor = column.HeaderFontColor != null ? column.HeaderFontColor : ColorPDF.Nero
                                };

                                #region Altezza del TESTO

                                if (labelHeaderGroupText.TextVerticalDirection)
                                    labelHeaderGroupText.Width = element.HeaderHeight + column.HeaderGroupTextDeltaY;

                                labelHeaderGroupText.GetAndSetHeight(_reportEnvironment.FontFamily, labelHeaderGroupText.FontBold);

                                #endregion

                                #region Direzione VERTICALE del TESTO HeaderGroupText

                                if (column.HeaderGroupTextVerticalDirection)
                                {
                                    labelHeaderGroupText.FixedHeight = labelHeaderGroupText.Height;

                                    labelHeaderGroupText.TextHorizontalAlign = TextAlign.Left;
                                    labelHeaderGroupText.Y = yHeaderGroupText;
                                    labelHeaderGroupText.X = xHeaderGroupText + labelHeaderGroupText.FontSize;
                                }

                                #endregion

                                #region Allineamento verticale del TESTO (se TextVerticalDirection = false)

                                if (!labelHeaderGroupText.TextVerticalDirection)
                                {
                                    switch (column.HeaderVerticalAlignment)
                                    {
                                        case VerticalAlignmentType.Alto:
                                            labelHeaderGroupText.Y = element.Y + column.HeaderGroupTextDeltaY;
                                            break;
                                        case VerticalAlignmentType.Basso:
                                            labelHeaderGroupText.Y = element.Y + (element.HeaderHeight - labelHeaderGroupText.FontSize) + column.HeaderGroupTextDeltaY;
                                            break;
                                        case VerticalAlignmentType.Centrato:
                                            labelHeaderGroupText.Y = element.Y + ((element.HeaderHeight / 2) - (labelHeaderGroupText.FontSize / 2)) + column.HeaderGroupTextDeltaY;
                                            break;
                                    }
                                }

                                #endregion

                                // Disegno la label di GroupHeaderText
                                WriteElement(labelHeaderGroupText);

                                //Disegno le immagini aggiunte a HeaderGroupPathImage
                                if (column.HeaderGroupPathImage != null)
                                    WriteElement(new ImagePDF(labelHeaderGroupText.X, column.HeaderGroupScaleImage, column.HeaderGroupPathImage));

                                scostamentoX += labelHeaderGroupText.FixedHeight;

                                //Linea di separazione in basso.
                                if (column.HeaderGroupBorderLine)
                                    WriteElement(new LinePDF(xHeaderGroupText, yHeaderGroupText + 3, xHeaderGroupText + column.HeaderGroupWidth - column.HeaderGroupTextDeltaX, yHeaderGroupText + 3, 0.5F, new ColorPDF(153, 148, 133)) { AutoIncrementYWritable = false });

                            }
                            xLabelHeaderText += column.Width;
                        }
                        columnIndex++;
                    }
                }

                #endregion

                #endregion
            }
            else           
            {
                element.HeaderTextCounter++;
                #region stampo nell'header della tabella il testo contenuto in HeaderText.

                labelHeaderText = new FormattedTextAreaPDF(element.HeaderText,
                    TablePDF_GetXTextContent(xLabelHeaderText, 0, element),
                    element.Width,
                    TextAlign.Left)
                {
                    Y = yHeader,
                    FontBold = true,
                    AutoIncrementYWritable = false
                };


                labelHeaderText.GetAndSetHeight(_reportEnvironment.FontFamily, labelHeaderText.FontBold);

                #region Allineamento verticale

                switch (element.HeaderTextVerticalAlign)
                {
                    case VerticalAlignmentType.Alto:
                        labelHeaderText.Y = yHeader;
                        break;
                    case VerticalAlignmentType.Basso:
                        labelHeaderText.Y = yHeader + (element.HeaderHeight - labelHeaderText.Height);
                        break;
                    case VerticalAlignmentType.Centrato:
                        labelHeaderText.Y = yHeader + ((element.HeaderHeight / 2) - (labelHeaderText.Height / 2));
                        break;
                }
                #endregion

                WriteElement(labelHeaderText);
                #endregion
            }
            
            AddSpace(element.AdditionalSpaceBetweenHeadersAndTable); // tmp
            _printinginnewpage = false;
        }
        /// <summary>
        /// Disegna il salto pagina per l'ogetto TablePDF.
        /// Aggiunge una pagina.
        /// </summary>
        private void StackedPDF_ContinuedOnNextPage()
        {
            switch (_reportEnvironment.ReportType)
            {
                case ReportType.Base_Proposta:
                    break;
                case ReportType.Unica_Diagnosi:
                case ReportType.Unica_Monitoraggio:
                case ReportType.Unica_Proposta:
                case ReportType.Unica_Nucleo:

                    WriteElement(new ImagePDF(435, 0.15F, "changepage.png") { Y = 745 - 5, AutoIncrementYWritable = false });
                    WriteElement(new FormattedTextAreaPDF("continua alla pagina successiva", 450, 200) { Y = 745 - 5, FontSize = 6, AutoIncrementYWritable = false, AbsolutePosition = true });

                    AddPage(false);

                    AddSpace(2);

                    WriteElement(new ImagePDF(XLeftLimit, 0.15F, "changepage.png") { AutoIncrementYWritable = false });
                    WriteElement(new FormattedTextAreaPDF("continua dalla pagina precedente", XLeftLimit + 15, 200) { FontSize = 6, AutoIncrementYWritable = true });

                    AddSpace(20);

                    break;
                case ReportType.Immobiliare_Diagnosi:
                case ReportType.Immobiliare_Monitoraggio:
                case ReportType.Immobiliare_DiagnosiNucleo:
                case ReportType.Immobiliare_MappaturaPreliminare:
                case ReportType.Immobiliare_Finalita:

                    //#region Immobiliare

                    //WriteElement(new FormattedTextAreaPDF("continua alla pagina successiva", XRightLimit - 200, 200) { Y = _ylowerlimitoriginal - 10, AutoIncrementYWritable = false, TextHorizontalAlign = TextAlign.Right, FontSize = 6, AbsolutePosition = true });

                    //AddPage(false);

                    //#endregion

                    break;

                default:
                    throw new Exception("ReportType da gestire: [Consulenza.ReportWriter.Business.TablePDF_ContinuedOnNextPage()]");
            }
        }

        /// <summary>
        /// Disegna il salto pagina per l'ogetto TablePDF.
        /// Aggiunge una pagina.
        /// </summary>
        private void TablePDF_ContinuedOnNextPage()
        {
            switch (_reportEnvironment.ReportType)
            {
                case ReportType.Base_Proposta:
                case ReportType.Unica_Diagnosi:
                case ReportType.Unica_Monitoraggio:
                case ReportType.Unica_Proposta:
                case ReportType.Unica_Nucleo:

                    WriteElement(new ImagePDF(435, 0.15F, "changepage.png") { AutoIncrementYWritable = false });
                    WriteElement(new FormattedTextAreaPDF("continua alla pagina successiva", 450, 200) { FontSize = 6, AutoIncrementYWritable = false, AbsolutePosition = true });

                    AddPage(false);

                    AddSpace(2);

                    WriteElement(new ImagePDF(XLeftLimit, 0.15F, "changepage.png") { Y = YUpperLimit + 2, AutoIncrementYWritable = false });
                    WriteElement(new FormattedTextAreaPDF("continua dalla pagina precedente", XLeftLimit + 15, 200) { Y = YUpperLimit + 2, FontSize = 6, AutoIncrementYWritable = true, AbsolutePosition = true });

                    AddSpace(20);

                    break;
                case ReportType.Immobiliare_Diagnosi:
                case ReportType.Immobiliare_DiagnosiNucleo:
                case ReportType.Immobiliare_MappaturaPreliminare:
                case ReportType.Immobiliare_Finalita:

                    #region Immobiliare

                    WriteElement(new FormattedTextAreaPDF("continua alla pagina successiva", XRightLimit - 200, 200) { Y = _ylowerlimitoriginal - 10, AutoIncrementYWritable = false, TextHorizontalAlign = TextAlign.Right, FontSize = 6, AbsolutePosition = true });

                    AddPage(false);

                    #endregion

                    break;

                case ReportType.Immobiliare_Monitoraggio:
                    #region Immobiliare Monitoraggio

                    //WriteElement(new FormattedTextAreaPDF("continua alla pagina successiva", XRightLimit - 350, 200) { Y = _ylowerlimitoriginal-2, AutoIncrementYWritable = false, TextHorizontalAlign = TextAlign.Right, FontSize = 6, AbsolutePosition = true });
                    WriteElement(new FormattedTextAreaPDF("continua alla pagina successiva", XRightLimit - 350, 200) { Y = _ylowerlimitoriginal - 8, AutoIncrementYWritable = false, TextHorizontalAlign = TextAlign.Right, FontSize = 6, AbsolutePosition = true });

                    AddPage(false);

                    #endregion

                    break;

                case ReportType.Immobiliare_MonitoraggioNuclei:
                    #region Immobiliare Monitoraggio

                    WriteElement(new FormattedTextAreaPDF("continua alla pagina successiva", XRightLimit - 350, 200) { Y = _ylowerlimitoriginal-10, AutoIncrementYWritable = false, TextHorizontalAlign = TextAlign.Right, FontSize = 6, AbsolutePosition = true });

                    AddPage(false);

                    #endregion

                    break;

                default:
                    throw new Exception("ReportType da gestire: [Consulenza.ReportWriter.Business.TablePDF_ContinuedOnNextPage()]");
            }
        }

        /// <summary>
        /// Scrive le note della tabella nel footer della pagina.
        /// </summary>k
        /// <param name="notesFooterPage"></param>
        private void WriteNoteFooterPage(List<TableNotePDF> notesFooterPage)
        {
            if (notesFooterPage.Count <= 0) return;

            var newnotesFooterPage = notesFooterPage;
            newnotesFooterPage.Reverse();

            float yNote = (_ylowerlimitoriginal) - _spacenotefooterpagePerpage;

            foreach (var noteFooterPage in newnotesFooterPage)
            {
                var areatoWrite = new FormattedTextAreaPDF(noteFooterPage.Text, XLeftLimit, XRightLimit - XLeftLimit)
                {
                    Y = yNote,
                    FontSize = noteFooterPage.FontSize
                };

                WriteElement(areatoWrite);
                yNote -= noteFooterPage.FontSize;
                _spacenotefooterpagePerpage += noteFooterPage.FontSize;
            }
        }

        /// <summary>
        /// Scrive le informazioni da riportare nel footer della pagina.
        /// Le informazioni vengono recuperate a questo livello dalla struttura _reportEnvironment.
        /// </summary>
        private void WriteFooterPage(ReportType reportType)
        {
            switch (reportType)
            {
                case ReportType.Base_Proposta:
                    {
                        #region Recupero le informazione necessarie

                        string nomeCliente = Helper.CapitalizeWords(_reportEnvironment.Cliente.Nome);
                        string cognomeCliente = Helper.CapitalizeWords(_reportEnvironment.Cliente.Cognome);
                        string nominativoPrivateBanker = Helper.CapitalizeWords(_reportEnvironment.PrivateBanker.Nominativo);
                        string indirizzoPrivateBanker = Helper.CapitalizeWords(
                            _reportEnvironment.PrivateBanker.Indirizzo) + " " +
                                                        _reportEnvironment.PrivateBanker.NumeroCivico + " - " +
                                                        _reportEnvironment.PrivateBanker.Cap + " " +
                                                        Helper.CapitalizeWords(_reportEnvironment.PrivateBanker.Citta);

                        string telefonoPrivateBanker = "Tel. " +
                                                       _reportEnvironment.PrivateBanker.PrefissoTelefono +
                                                       _reportEnvironment.PrivateBanker.Telefono;

                        #endregion

                        #region Footer parte sinistra

                        // Footer parte sinistra
                        var labelProduzioneReport = new FormattedTextAreaPDF("Report prodotto per", XLeftLimit, 200, TextAlign.Left) { Y = _yendpage + 15, FontSize = 7, AutoIncrementYWritable = false };

                        var labelCliente = new FormattedTextAreaPDF(string.Format("{0} {1}", nomeCliente, cognomeCliente), XLeftLimit, 200, TextAlign.Left) { Y = _yendpage + 25, FontSize = 7, FontBold = true, AutoIncrementYWritable = false };

                        WriteElement(labelProduzioneReport);
                        WriteElement(labelCliente);

                        #endregion

                        #region Footer parte destra

                        // Footer parte destra
                        var labelPrivateBanker = new FormattedTextAreaPDF("Private Banker", 350F, 200, TextAlign.Right) { Y = _yendpage + 15, FontSize = 7, FontBold = true, AutoIncrementYWritable = false };

                        var labelNomeCognomePrivateBanker = new FormattedTextAreaPDF(nominativoPrivateBanker, 350F, 200, TextAlign.Right) { Y = _yendpage + 25, FontSize = 7, FontBold = true, AutoIncrementYWritable = false };

                        var labelIndirizzoPrivateBanker = new FormattedTextAreaPDF(indirizzoPrivateBanker, 350F, 200, TextAlign.Right) { Y = _yendpage + 35, FontSize = 7, AutoIncrementYWritable = false };

                        var labelTelefonoPrivateBanker = new FormattedTextAreaPDF(telefonoPrivateBanker, 350F, 200, TextAlign.Right) { Y = _yendpage + 45, FontSize = 7, AutoIncrementYWritable = false };

                        WriteElement(labelPrivateBanker);
                        WriteElement(labelNomeCognomePrivateBanker);
                        WriteElement(labelIndirizzoPrivateBanker);
                        WriteElement(labelTelefonoPrivateBanker);

                        #endregion
                    }
                    break;
                case ReportType.Immobiliare_Diagnosi:
                case ReportType.Immobiliare_MappaturaPreliminare:
                case ReportType.Immobiliare_Finalita:
                    {
                        var nomeCliente = Helper.CapitalizeWords(_reportEnvironment.Cliente.Nome);
                        var cognomeCliente = Helper.CapitalizeWords(_reportEnvironment.Cliente.Cognome);
                        string labelCliente = _reportEnvironment.Cliente.Tipo == ClienteType.Fisico ? "Codice fiscale" : _reportEnvironment.Cliente.CodiceFiscale != "" ? "Codice fiscale" : "Partita Iva";
                        string datoCliente = _reportEnvironment.Cliente.Tipo == ClienteType.Fisico ? _reportEnvironment.Cliente.CodiceFiscale : _reportEnvironment.Cliente.CodiceFiscale != "" ? _reportEnvironment.Cliente.CodiceFiscale : _reportEnvironment.Cliente.PartitaIva;
                        var cliente = new FormattedTextAreaPDF(string.Format("{0} {1} {2} - {3} {4}", "<B>Cliente:</B>", nomeCliente, cognomeCliente, "Codice fiscale", datoCliente), XLeftLimit) { Y = _yendpage + 40, AutoIncrementYWritable = false };
                        var privateBanker = new FormattedTextAreaPDF(string.Format("{0} {1}", "<B>Private Banker:</B>", Helper.CapitalizeWords(_reportEnvironment.PrivateBanker.Nominativo)), XLeftLimit) { Y = _yendpage + 54, AutoIncrementYWritable = false };

                        WriteElement(cliente);
                        WriteElement(privateBanker);
                    }
                    break;
                case ReportType.Immobiliare_Monitoraggio:
                    {
                        var nomeCliente = Helper.CapitalizeWords(_reportEnvironment.Cliente.Nome);
                        var cognomeCliente = Helper.CapitalizeWords(_reportEnvironment.Cliente.Cognome);
                        string labelCliente = _reportEnvironment.Cliente.Tipo == ClienteType.Fisico ? "Codice fiscale" : _reportEnvironment.Cliente.CodiceFiscale != "" ? "Codice fiscale" : "Partita Iva";
                        string datoCliente = _reportEnvironment.Cliente.Tipo == ClienteType.Fisico ? _reportEnvironment.Cliente.CodiceFiscale : _reportEnvironment.Cliente.CodiceFiscale != "" ? _reportEnvironment.Cliente.CodiceFiscale : _reportEnvironment.Cliente.PartitaIva;
                        var cliente = new FormattedTextAreaPDF(string.Format("{0} {1} {2} - {3} {4}", "<B>Cliente:</B>", nomeCliente, cognomeCliente, "Codice fiscale", datoCliente), XLeftLimit + 4) { Y = _yendpage + 47, AutoIncrementYWritable = false, FontSize = 6 };
                        var privateBanker = new FormattedTextAreaPDF(string.Format("{0} {1}", "<B>Private Banker:</B>", Helper.CapitalizeWords(_reportEnvironment.PrivateBanker.Nominativo)), XLeftLimit + 4) { Y = _yendpage + 56, AutoIncrementYWritable = false, FontSize = 6 };

                        WriteElement(cliente);
                        WriteElement(privateBanker);
                    }
                    break;
                case ReportType.Immobiliare_DiagnosiNucleo:
                    {
                        var nomeNucleo = Helper.CapitalizeWords(_reportEnvironment.NucleoImmobiliare.NomeNucleo);

                        var nucleo = new FormattedTextAreaPDF(string.Format("{0} {1}", "<B>Nucleo:</B>", nomeNucleo), XLeftLimit) { Y = _yendpage + 40, AutoIncrementYWritable = false };
                        var privateBanker = new FormattedTextAreaPDF(string.Format("{0} {1}", "<B>Private Banker:</B>", Helper.CapitalizeWords(_reportEnvironment.PrivateBanker.Nominativo)), XLeftLimit) { Y = _yendpage + 54, AutoIncrementYWritable = false };

                        WriteElement(nucleo);
                        WriteElement(privateBanker);
                    }
                    break;

                case ReportType.Immobiliare_MonitoraggioNuclei:
                    {
                        var nomeNucleo = Helper.CapitalizeWords(_reportEnvironment.NucleoImmobiliare.NomeNucleo);

                        var nucleo = new FormattedTextAreaPDF(string.Format("{0} {1}", "<B>Nucleo:</B>", nomeNucleo), XLeftLimit + 4) { Y = _yendpage + 47, AutoIncrementYWritable = false, FontSize = 6 };
                        var privateBanker = new FormattedTextAreaPDF(string.Format("{0} {1}", "<B>Private Banker:</B>", Helper.CapitalizeWords(_reportEnvironment.PrivateBanker.Nominativo)), XLeftLimit + 4) { Y = _yendpage + 56, AutoIncrementYWritable = false, FontSize = 6 };

                        WriteElement(nucleo);
                        WriteElement(privateBanker);
                    }
                    break;

                case ReportType.Unica_Diagnosi:
                case ReportType.Unica_Monitoraggio:
                case ReportType.Unica_Proposta:
                case ReportType.Unica_Nucleo:

                    var reportAnonimo = _reportEnvironment.ReportStruct.GetOptionReport<Opzione1>().ReportAnonimo;

                    #region Colonna Sinistra

                    var sProduzioneReport = reportAnonimo ? "Report prodotto {0}" : "Report prodotto {0} per";
                    var ftaProduzioneReport = new FormattedTextAreaPDF(string.Format(sProduzioneReport, DateTime.Now.ToLongDateString()), XLeftLimit, 500)
                    {
                        Y = YLowerLimit + 17,
                        AutoIncrementYWritable = false,
                        AbsolutePosition = true,
                        FontSize = 7
                    };
                    WriteElement(ftaProduzioneReport);

                    if (!reportAnonimo)
                    {
                        string nome = reportType == ReportType.Unica_Nucleo ? _reportEnvironment.Cliente.Cognome : Helper.CapitalizeWords(_reportEnvironment.Cliente.Cognome + " " + _reportEnvironment.Cliente.Nome);
                        var ftaNominativoCliente = new FormattedTextAreaPDF(string.Format("{0}", nome), XLeftLimit, 500)
                        {
                            Y = YLowerLimit + 26,
                            AutoIncrementYWritable = false,
                            AbsolutePosition = true,
                            FontBold = true,
                            FontSize = 7
                        };
                        WriteElement(ftaNominativoCliente);
                    }

                    #endregion

                    #region Colonna Destra

                    var ftaPrivateBanker = new FormattedTextAreaPDF("Private Banker", XRightLimit - 300, 300)
                    {
                        Y = YLowerLimit + 17,
                        AutoIncrementYWritable = false,
                        AbsolutePosition = true,
                        FontBold = true,
                        TextHorizontalAlign = TextAlign.Right,
                        FontSize = 7
                    };
                    WriteElement(ftaPrivateBanker);

                    var ftaNominativoPrivateBanker = new FormattedTextAreaPDF(Helper.CapitalizeWords(_reportEnvironment.PrivateBanker.Nominativo), XRightLimit - 300, 300)
                    {
                        Y = YLowerLimit + 26,
                        AutoIncrementYWritable = false,
                        AbsolutePosition = true,
                        FontBold = true,
                        TextHorizontalAlign = TextAlign.Right,
                        FontSize = 7
                    };
                    WriteElement(ftaNominativoPrivateBanker);

                    var ftaIndirizzoPrivateBanker = new FormattedTextAreaPDF(string.Format("{0} {1} - {2} {3}", Helper.CapitalizeWords(_reportEnvironment.PrivateBanker.Indirizzo), _reportEnvironment.PrivateBanker.NumeroCivico, _reportEnvironment.PrivateBanker.Cap, _reportEnvironment.PrivateBanker.Citta), XRightLimit - 500, 500)
                    {
                        Y = YLowerLimit + 35,
                        AutoIncrementYWritable = false,
                        AbsolutePosition = true,
                        TextHorizontalAlign = TextAlign.Right,
                        FontSize = 7
                    };
                    WriteElement(ftaIndirizzoPrivateBanker);

                    var ftaTelefonoPrivateBanker = new FormattedTextAreaPDF(string.Format("Tel. {0} - {1}", _reportEnvironment.PrivateBanker.PrefissoTelefono, _reportEnvironment.PrivateBanker.Telefono), XRightLimit - 300, 300)
                    {
                        Y = YLowerLimit + 44,
                        AutoIncrementYWritable = false,
                        AbsolutePosition = true,
                        TextHorizontalAlign = TextAlign.Right,
                        FontSize = 7
                    };
                    WriteElement(ftaTelefonoPrivateBanker);

                    #endregion

                    break;

                default:
                    throw new Exception("ReportType da gestire: [Consulenza.ReportWriter.Business.WriteFooterPage()]");
            }
        }



        private List<Tuple<PageHeader, FormattedTextAreaPDF>> headers = new List<Tuple<PageHeader, FormattedTextAreaPDF>>();
        /// <summary>
        /// Scrive tutti gli elementi di tipo FORMATTEDTEXTAREA o IMAGE aggiunti al capitolo.
        /// </summary>
        private void WriteChapterTitle(ReportType reportType)
        {
            // ES Modifica 20190322 per Semestrale 
            if (reportType == ReportType.Immobiliare_Monitoraggio || reportType == ReportType.Immobiliare_MonitoraggioNuclei)
            {
                // we've never encountered a problem of typing page (1/3)
                // the problem is, that we need now to generate all pages first and then
                // come back to all added elements, and see whether there are pages belonging to same chapter/section
                // and add strings (eg. (1/2))
                // here, we add all headers to headers list and after generating all elements (and pages)
                // we will fix headers with proper values
                // keep in mind, that across entire solution, we use convention 1 chapter = 1 section
                int chapterId = int.Parse(_currentchapter.ToString());
                var currentChapterHeader = MonitoraggioImmobiliarePageHeaderManager.GetHeader(chapterId);
                int xOffset = 20;
                if (currentChapterHeader.ImagePath != null)
                {
                    var image = new ImagePDF(XLeftLimit + xOffset, 0, currentChapterHeader.ImagePath)
                    {
                        Width = currentChapterHeader.ImageWidth,
                        Height = currentChapterHeader.ImageHeight,
                        AutoIncrementYWritable = false,
                        //Y = 14 + currentChapterHeader.DeltaY
                        Y = 10 + currentChapterHeader.DeltaY
                    };
                    WriteElement(image);
                    xOffset += (int)image.Width;

                }

                string headerText = string.Empty;
                headerText += currentChapterHeader.SectionName ?? string.Empty;
                if (currentChapterHeader.SectionName != null && currentChapterHeader.ChapterName != null)
                {
                    headerText += " - ";
                }
                headerText += currentChapterHeader.ChapterName != null ? (string.Format("<font color='AE9651'><b>{0}{1}</b></font>", currentChapterHeader.ChapterName, currentChapterHeader.TextReplaceGuid)) : string.Empty;
                //FormattedTextAreaPDF pageHeader = new FormattedTextAreaPDF(headerText, XLeftLimit + xOffset + 6) { FontSize = 16, FontColor = ColorPDF.Immobiliare_Grigio_TitoloPiccolo, AutoIncrementYWritable = false, Width = 700, Y = 20, FixedHeight = 20 };
                FormattedTextAreaPDF pageHeader = new FormattedTextAreaPDF(headerText, XLeftLimit + xOffset + 6) { FontSize = 16, FontColor = ColorPDF.Immobiliare_Grigio_TitoloPiccolo, AutoIncrementYWritable = false, Width = 700, Y = 16, FixedHeight = 20 };
                headers.Add(new Tuple<PageHeader, FormattedTextAreaPDF>(currentChapterHeader, pageHeader));
                WriteElement(pageHeader);
            }
            else
            {
                // Quando numberPageOnChapter = 0 non c'è bisogno di disegnare gli oggetti aggiunti al capitolo perché sara l'invocazione alla classe del capitolo stesso che lo farà.
                if (!_currentchapter.ChapterFacade.RepeatOnEachPage || numberPageOnChapter == 0)
                    return;

                foreach (var item in _currentchapter.Elements.Where(o => o.ObjectType == ObjectTypePdf.FORMATTEDTEXTAREA || o.ObjectType == ObjectTypePdf.IMAGE))
                {
                    switch (item.ObjectType)
                    {
                        case ObjectTypePdf.FORMATTEDTEXTAREA:
                            WriteElement((FormattedTextAreaPDF)item);
                            break;
                        case ObjectTypePdf.IMAGE:
                            WriteElement((ImagePDF)item);
                            break;
                    }
                }
            }
        }


        /// <summary>
        /// Invoca il gestore delle classi che devono renderizzare le intestazioni di pagina (istanze di DTOPageFrameDataClassImplementation).
        /// </summary>
        /// <param name="pagetype">Tipo di template da utilizzare per la pagina da aggiungere.</param>
        private void AddPage(PagePDF.PagePDFType pagetype = PagePDF.PagePDFType.Generic)
        {
            _spacenotefooterpagePerpage = 0;
            YLowerLimit = _ylowerlimitoriginal;

            _ywritable = YUpperLimit;

            if (pagetype == PagePDF.PagePDFType.Generic)
            {
                _page = new ImportedPage(_generictemplate.GetPage(1));

                switch (_reportEnvironment.ReportType)
                {
                    case ReportType.Base_Proposta:
                        _page.Elements.Add(new PageNumberingLabel("Pagina %%SP%% di %%ST%%", XLeftLimit, _yendpage, XRightLimit - XLeftLimit, 12, Font.Helvetica, 7, TextAlign.Left));
                        break;
                    case ReportType.Immobiliare_Diagnosi:
                    case ReportType.Immobiliare_DiagnosiNucleo:
                    case ReportType.Immobiliare_MappaturaPreliminare:
                    case ReportType.Immobiliare_Finalita:
                        _page.Elements.Add(new PageNumberingLabel("%%SP%% di %%ST%%", XLeftLimit, _yendpage, XRightLimit - XLeftLimit, 12) { FontSize = 7 });
                        break;

                    case ReportType.Immobiliare_Monitoraggio:
                        _page.Elements.Add(new PageNumberingLabel("%%SP%% di %%ST%%", XLeftLimit + 5, _yendpage + 6, XRightLimit - XLeftLimit, 12, new OpenTypeFont("verdanab.TTF"), 6) { FontSize = 6 });
                        break;

                    case ReportType.Immobiliare_MonitoraggioNuclei:
                        _page.Elements.Add(new PageNumberingLabel("%%SP%% di %%ST%%", XLeftLimit + 5, _yendpage + 6, XRightLimit - XLeftLimit, 12, new OpenTypeFont("verdanab.TTF"), 6) { FontSize = 6 });
                        break;

                    case ReportType.Unica_Proposta:
                        string titolo = string.Empty;
                        if (!_reportEnvironment.Adeguata)
                        {
                            WriteElement(new RectanglePDF(XLeftLimit, 15, 41, 220, ColorPDF.ConsulenzaUnica_Grigio_SfondoColonnaHeaderFooterTabella) { AutoIncrementYWritable = false, Y = 15 });
                            WriteElement(new LinePDF(XLeftLimit, 260, 1) { AutoIncrementYWritable = false, Y1 = 37, Y2 = 37, Color = ColorPDF.ConsulenzaUnica_Rosso });
                            titolo = "REPORT OPERAZIONI RICHIESTE";
                        }
                        else
                            titolo = "REPORT PROPOSTA";
                        WriteElement(new FormattedTextAreaPDF(titolo, XLeftLimit, 300) { FontBold = true, FontSize = 11, FontColor = ColorPDF.ConsulenzaUnica_Rosso, AutoIncrementYWritable = false, Y = 40 });
                        break;
                    case ReportType.Unica_Nucleo: //tolta paginazione per ticket #1728
                    case ReportType.Unica_Diagnosi:
                    case ReportType.Unica_Monitoraggio:
                        //_page.Elements.Add(new PageNumberingLabel("pagina %%SP%% di %%ST%%", XRightLimit - 65, _yendpage + 80, XRightLimit - XLeftLimit, 12) { FontSize = 7 });
                        WriteElement(new FormattedTextAreaPDF(string.Format("REPORT {0}", HelperEnum<ReportType>.GetDescription(_reportEnvironment.ReportType)), XLeftLimit, 300) { FontBold = true, FontSize = 11, FontColor = ColorPDF.ConsulenzaUnica_Rosso, AutoIncrementYWritable = false, Y = 40 });
                        break;
                    default:
                        throw new Exception("ReportType da gestire: [Consulenza.ReportWriter.Business.AddPage(PagePDF.PagePDFType pagetype)]");
                }

                WriteChapterTitle(_reportEnvironment.ReportType);
                WriteFooterPage(_reportEnvironment.ReportType);

                // Aggiungo gli elementi di _repeaterElements
                if (_repeaterElements != null)
                {
                    foreach (var item in _repeaterElements)
                        WriteElement(item);
                }
            }
            else
                _page = new ImportedPage(_covertemplate.GetPage(1));

            _document.Pages.Add(_page);
            int count = _document.Pages.Count;
            _printinginnewpage = true;

        }

        /// <summary>
        /// Invoca il gestore delle classi che devono renderizzare le intestazioni di pagina
        /// (istanze di DTOPageFrameDataClassImplementation) ed aggiunge una nuova pagina vuota e numerata al documento.
        /// Se resetylowerlimit=true viene impostato _ylowerlimit=_ylowerlimitoriginal.
        /// </summary>
        /// <param name="resetylowerlimit"></param>
        private void AddPage(bool resetylowerlimit)
        {
            AddPage();

            if (resetylowerlimit)
                YLowerLimit = _ylowerlimitoriginal;
        }

        /// <summary>
        /// Aggiunge uno spazio sull'asse y pari a space
        /// </summary>
        /// <param name="space"></param>
        private void AddSpace(float space)
        {
            _ywritable += space;
        }
    }
}
